Merge branch 'master' into multivalued-flexible-fields

This commit is contained in:
Šarūnas Nejus 2025-08-19 13:39:34 +01:00 committed by GitHub
commit c0675fefb8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
138 changed files with 9164 additions and 8807 deletions

View file

@ -53,3 +53,7 @@ c490ac5810b70f3cf5fd8649669838e8fdb19f4d
1a045c91668c771686f4c871c84f1680af2e944b
# Library restructure (split library.py into multiple modules)
0ad4e19d4f870db757373f44d12ff3be2441363a
# Docs: fix linting issues
769dcdc88a1263638ae25944ba6b2be3e8933666
# Reformat all docs using docstrfmt
ab5acaabb3cd24c482adb7fa4800c89fd6a2f08d

View file

@ -0,0 +1,16 @@
{
"problemMatcher": [
{
"owner": "sphinx-build",
"severity": "error",
"pattern": [
{
"regexp": "^(/[^:]+):((\\d+):)?(\\sWARNING:)?\\s*(.+)$",
"file": 1,
"line": 3,
"message": 5
}
]
}
]
}

View file

@ -0,0 +1,17 @@
{
"problemMatcher": [
{
"owner": "sphinx-lint",
"severity": "error",
"pattern": [
{
"regexp": "^([^:]+):(\\d+):\\s+(.*)\\s\\(([a-z-]+)\\)$",
"file": 1,
"line": 2,
"message": 3,
"code": 4
}
]
}
]
}

View file

@ -1,15 +0,0 @@
{
"problemMatcher": [
{
"owner": "sphinx",
"pattern": [
{
"regexp": "^([^:]+):(\\d+): (WARNING: )?(.+)$",
"file": 1,
"line": 2,
"message": 4
}
]
}
]
}

View file

@ -1,6 +1,6 @@
name: Verify changelog updated
on:
on:
pull_request_target:
types:
- opened
@ -14,20 +14,20 @@ jobs:
- name: Get all updated Python files
id: changed-python-files
uses: tj-actions/changed-files@v44
uses: tj-actions/changed-files@v46
with:
files: |
**.py
- name: Check for the changelog update
id: changelog-update
uses: tj-actions/changed-files@v44
uses: tj-actions/changed-files@v46
with:
files: docs/changelog.rst
- name: Comment under the PR with a reminder
if: steps.changed-python-files.outputs.any_changed == 'true' && steps.changelog-update.outputs.any_changed == 'false'
uses: thollander/actions-comment-pull-request@v2
with:
message: 'Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry.'
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
message: 'Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry.'
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'

View file

@ -4,6 +4,12 @@ on:
push:
branches:
- master
concurrency:
# Cancel previous workflow run when a new commit is pushed to a feature branch
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
env:
PY_COLORS: 1
@ -37,7 +43,7 @@ jobs:
- name: Get changed lyrics files
id: lyrics-update
uses: tj-actions/changed-files@v45
uses: tj-actions/changed-files@v46
with:
files: |
beetsplug/lyrics.py
@ -52,7 +58,7 @@ jobs:
- if: ${{ env.IS_MAIN_PYTHON != 'true' }}
name: Test without coverage
run: |
poetry install --extras=autobpm --extras=lyrics --extras=embedart
poetry install --without=lint --extras=autobpm --extras=lyrics --extras=replaygain --extras=reflink --extras=fetchart --extras=chroma --extras=sonosupdate
poe test
- if: ${{ env.IS_MAIN_PYTHON == 'true' }}
@ -60,10 +66,16 @@ jobs:
env:
LYRICS_UPDATED: ${{ steps.lyrics-update.outputs.any_changed }}
run: |
poetry install --extras=autobpm --extras=lyrics --extras=docs --extras=replaygain --extras=reflink --extras=fetchart
poetry install --extras=autobpm --extras=lyrics --extras=docs --extras=replaygain --extras=reflink --extras=fetchart --extras=chroma --extras=sonosupdate
poe docs
poe test-with-coverage
- if: ${{ !cancelled() }}
name: Upload test results to Codecov
uses: codecov/test-results-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
- if: ${{ env.IS_MAIN_PYTHON == 'true' }}
name: Store the coverage report
uses: actions/upload-artifact@v4
@ -86,7 +98,7 @@ jobs:
name: coverage-report
- name: Upload code coverage
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
files: ./coverage.xml
use_oidc: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork) }}

View file

@ -6,6 +6,11 @@ on:
branches:
- master
concurrency:
# Cancel previous workflow run when a new commit is pushed to a feature branch
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
env:
PYTHON_VERSION: 3.9
@ -22,13 +27,13 @@ jobs:
- uses: actions/checkout@v4
- name: Get changed docs files
id: changed-doc-files
uses: tj-actions/changed-files@v44
uses: tj-actions/changed-files@v46
with:
files: |
docs/**
- name: Get changed python files
id: raw-changed-python-files
uses: tj-actions/changed-files@v44
uses: tj-actions/changed-files@v46
with:
files: |
**.py
@ -107,7 +112,7 @@ jobs:
uses: liskin/gh-problem-matcher-wrap@v3
with:
linters: mypy
run: poe check-types --show-column-numbers --no-error-summary ${{ needs.changed-files.outputs.changed_python_files }}
run: poe check-types --show-column-numbers --no-error-summary .
docs:
if: needs.changed-files.outputs.any_docs_changed == 'true'
@ -126,11 +131,16 @@ jobs:
- name: Install dependencies
run: poetry install --extras=docs
- name: Add Sphinx problem matcher
run: echo "::add-matcher::.github/sphinx-problem-matcher.json"
- name: Add Sphinx problem matchers
run: |
echo "::add-matcher::.github/problem-matchers/sphinx-build.json"
echo "::add-matcher::.github/problem-matchers/sphinx-lint.json"
- name: Check docs formatting
run: poe format-docs --check
- name: Lint docs
run: poe lint-docs
- name: Build docs
run: |-
poe docs |& tee /tmp/output
# fail the job if there are issues
grep -q " WARNING:" /tmp/output && exit 1 || exit 0
run: poe docs -e 'SPHINXOPTS=--fail-on-warning --keep-going'

View file

@ -5,8 +5,14 @@ repos:
- repo: local
hooks:
- id: format
name: Format
name: Format Python files
entry: poe format
language: system
files: '.*.py'
pass_filenames: true
- id: format-docs
name: Format docs
entry: poe format-docs
language: system
files: '.*.rst'
pass_filenames: true

View file

@ -1,9 +1,8 @@
####################################
Contributor Covenant Code of Conduct
####################################
====================================
Our Pledge
==========
----------
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
@ -16,7 +15,7 @@ We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
Our Standards
=============
-------------
Examples of behavior that contributes to a positive environment for our
community include:
@ -41,7 +40,7 @@ Examples of unacceptable behavior include:
professional setting
Enforcement Responsibilities
============================
----------------------------
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
@ -54,7 +53,7 @@ not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
Scope
=====
-----
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
@ -63,7 +62,7 @@ posting via an official social media account, or acting as an appointed
representative at an online or offline event.
Enforcement
===========
-----------
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at here on Github.
@ -73,13 +72,13 @@ All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
Enforcement Guidelines
======================
----------------------
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
1. Correction
-------------
~~~~~~~~~~~~~
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
@ -89,7 +88,7 @@ clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
2. Warning
----------
~~~~~~~~~~
**Community Impact**: A violation through a single incident or series of
actions.
@ -102,7 +101,7 @@ like social media. Violating these terms may lead to a temporary or permanent
ban.
3. Temporary Ban
----------------
~~~~~~~~~~~~~~~~
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
@ -114,7 +113,7 @@ with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
4. Permanent Ban
----------------
~~~~~~~~~~~~~~~~
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
@ -124,7 +123,7 @@ individual, or aggression toward or disparagement of classes of individuals.
community.
Attribution
===========
-----------
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available `here
@ -136,4 +135,3 @@ enforcement ladder.
For answers to common questions about this code of conduct, see the `FAQ
<https://www.contributor-covenant.org/faq>`_. Translations are available at
`translations <https://www.contributor-covenant.org/translations>`_.

View file

@ -1,111 +1,106 @@
############
Contributing
############
============
.. contents::
:depth: 3
Thank you!
==========
----------
First off, thank you for considering contributing to beets! Its people
like you that make beets continue to succeed.
First off, thank you for considering contributing to beets! Its people like you
that make beets continue to succeed.
These guidelines describe how you can help most effectively. By
following these guidelines, you can make life easier for the development
team as it indicates you respect the maintainers time; in return, the
maintainers will reciprocate by helping to address your issue, review
changes, and finalize pull requests.
These guidelines describe how you can help most effectively. By following these
guidelines, you can make life easier for the development team as it indicates
you respect the maintainers time; in return, the maintainers will reciprocate
by helping to address your issue, review changes, and finalize pull requests.
Types of Contributions
======================
----------------------
We love to get contributions from our community—you! There are many ways
to contribute, whether youre a programmer or not.
We love to get contributions from our community—you! There are many ways to
contribute, whether youre a programmer or not.
The first thing to do, regardless of how you'd like to contribute to the
project, is to check out our :doc:`Code of Conduct <code_of_conduct>` and to
keep that in mind while interacting with other contributors and users.
Non-Programming
---------------
~~~~~~~~~~~~~~~
- Promote beets! Help get the word out by telling your friends, writing
a blog post, or discussing it on a forum you frequent.
- Improve the `documentation`_. Its
incredibly easy to contribute here: just find a page you want to
modify and hit the “Edit on GitHub” button in the upper-right. You
can automatically send us a pull request for your changes.
- GUI design. For the time being, beets is a command-line-only affair.
But thats mostly because we dont have any great ideas for what a
good GUI should look like. If you have those great ideas, please get
in touch.
- Benchmarks. Wed like to have a consistent way of measuring speed
improvements in beets tagger and other functionality as well as a
way of comparing beets performance to other tools. You can help by
compiling a library of freely-licensed music files (preferably with
incorrect metadata) for testing and measurement.
- Think you have a nice config or cool use-case for beets? Wed love to
hear about it! Submit a post to our `discussion board
<https://github.com/beetbox/beets/discussions/categories/show-and-tell>`__
under the “Show and Tell” category for a chance to get featured in `the
docs <https://beets.readthedocs.io/en/stable/guides/advanced.html>`__.
- Consider helping out fellow users by by `responding to support requests
<https://github.com/beetbox/beets/discussions/categories/q-a>`__ .
- Promote beets! Help get the word out by telling your friends, writing a blog
post, or discussing it on a forum you frequent.
- Improve the documentation_. Its incredibly easy to contribute here: just find
a page you want to modify and hit the “Edit on GitHub” button in the
upper-right. You can automatically send us a pull request for your changes.
- GUI design. For the time being, beets is a command-line-only affair. But
thats mostly because we dont have any great ideas for what a good GUI should
look like. If you have those great ideas, please get in touch.
- Benchmarks. Wed like to have a consistent way of measuring speed improvements
in beets tagger and other functionality as well as a way of comparing beets
performance to other tools. You can help by compiling a library of
freely-licensed music files (preferably with incorrect metadata) for testing
and measurement.
- Think you have a nice config or cool use-case for beets? Wed love to hear
about it! Submit a post to our `discussion board
<https://github.com/beetbox/beets/discussions/categories/show-and-tell>`__
under the “Show and Tell” category for a chance to get featured in `the docs
<https://beets.readthedocs.io/en/stable/guides/advanced.html>`__.
- Consider helping out fellow users by by `responding to support requests
<https://github.com/beetbox/beets/discussions/categories/q-a>`__ .
Programming
-----------
~~~~~~~~~~~
- As a programmer (even if youre just a beginner!), you have a ton of
opportunities to get your feet wet with beets.
- For developing plugins, or hacking away at beets, theres some good
information in the `“For Developers” section of the
docs <https://beets.readthedocs.io/en/stable/dev/>`__.
- As a programmer (even if youre just a beginner!), you have a ton of
opportunities to get your feet wet with beets.
- For developing plugins, or hacking away at beets, theres some good
information in the `“For Developers” section of the docs
<https://beets.readthedocs.io/en/stable/dev/>`__.
.. _development-tools:
Development Tools
^^^^^^^^^^^^^^^^^
+++++++++++++++++
In order to develop beets, you will need a few tools installed:
- `poetry`_ for packaging, virtual environment and dependency management
- `poethepoet`_ to run tasks, such as linting, formatting, testing
- poetry_ for packaging, virtual environment and dependency management
- poethepoet_ to run tasks, such as linting, formatting, testing
Python community recommends using `pipx`_ to install stand-alone command-line
applications such as above. `pipx`_ installs each application in an isolated
Python community recommends using pipx_ to install stand-alone command-line
applications such as above. pipx_ installs each application in an isolated
virtual environment, where its dependencies will not interfere with your system
and other CLI tools.
If you do not have `pipx`_ installed in your system, follow `pipx-installation-instructions`_ or
If you do not have pipx_ installed in your system, follow `pipx installation
instructions <https://pipx.pypa.io/stable/installation/>`__ or
.. code-block:: sh
$ python3 -m pip install --user pipx
Install `poetry`_ and `poethepoet`_ using `pipx`_::
Install poetry_ and poethepoet_ using pipx_:
::
$ pipx install poetry poethepoet
.. admonition:: Check ``tool.pipx-install`` section in ``pyproject.toml`` to
see supported versions
.. admonition:: Check ``tool.pipx-install`` section in ``pyproject.toml`` to see supported versions
::
.. code-block:: toml
[tool.pipx-install]
poethepoet = ">=0.26"
poetry = "<2"
.. _pipx: https://pipx.pypa.io/stable
.. _pipx-installation-instructions: https://pipx.pypa.io/stable/installation/
[tool.pipx-install]
poethepoet = ">=0.26"
poetry = "<2"
.. _getting-the-source:
Getting the Source
^^^^^^^^^^^^^^^^^^
++++++++++++++++++
The easiest way to get started with the latest beets source is to clone the
repository and install ``beets`` in a local virtual environment using `poetry`_.
repository and install ``beets`` in a local virtual environment using poetry_.
This can be done with:
.. code-block:: bash
@ -115,26 +110,32 @@ This can be done with:
$ poetry install
This will install ``beets`` and all development dependencies into its own
virtual environment in your ``$POETRY_CACHE_DIR``. See ``poetry install
--help`` for installation options, including installing ``extra`` dependencies
for plugins.
virtual environment in your ``$POETRY_CACHE_DIR``. See ``poetry install --help``
for installation options, including installing ``extra`` dependencies for
plugins.
In order to run something within this virtual environment, start the command
with ``poetry run`` to them, for example ``poetry run pytest``.
On the other hand, it may get tedious to type ``poetry run`` before every
command. Instead, you can activate the virtual environment in your shell with::
command. Instead, you can activate the virtual environment in your shell with:
::
$ poetry shell
You should see ``(beets-py3.9)`` prefix in your shell prompt. Now you can run
commands directly, for example::
commands directly, for example:
::
$ (beets-py3.9) pytest
Additionally, `poethepoet`_ task runner assists us with the most common
Additionally, poethepoet_ task runner assists us with the most common
operations. Formatting, linting, testing are defined as ``poe`` tasks in
`pyproject.toml`_. Run::
pyproject.toml_. Run:
::
$ poe
@ -149,204 +150,200 @@ to see all available tasks. They can be used like this, for example
$ poe test --lf # re-run failing tests (note the additional pytest option)
$ poe check-types --pretty # check types with an extra option for mypy
Code Contribution Ideas
^^^^^^^^^^^^^^^^^^^^^^^
+++++++++++++++++++++++
- We maintain a set of `issues marked as
“good first issue” <https://github.com/beetbox/beets/labels/good%20first%20issue>`__.
These are issues that would serve as a good introduction to the
codebase. Claim one and start exploring!
- Like testing? Our `test
coverage <https://codecov.io/github/beetbox/beets>`__ is somewhat
low. You can help out by finding low-coverage modules or checking out
other `testing-related
issues <https://github.com/beetbox/beets/labels/testing>`__.
- There are several ways to improve the tests in general (see :ref:`testing` and some
places to think about performance optimization (see
`Optimization <https://github.com/beetbox/beets/wiki/Optimization>`__).
- Not all of our code is up to our coding conventions. In particular,
the `library API
documentation <https://beets.readthedocs.io/en/stable/dev/library.html>`__
are currently quite sparse. You can help by adding to the docstrings
in the code and to the documentation pages themselves. beets follows
`PEP-257 <https://www.python.org/dev/peps/pep-0257/>`__ for
docstrings and in some places, we also sometimes use `ReST autodoc
syntax for
Sphinx <https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html>`__
to, for example, refer to a class name.
.. _poethepoet: https://poethepoet.natn.io/index.html
.. _poetry: https://python-poetry.org/docs/
- We maintain a set of `issues marked as “good first issue”
<https://github.com/beetbox/beets/labels/good%20first%20issue>`__. These are
issues that would serve as a good introduction to the codebase. Claim one and
start exploring!
- Like testing? Our `test coverage <https://codecov.io/github/beetbox/beets>`__
is somewhat low. You can help out by finding low-coverage modules or checking
out other `testing-related issues
<https://github.com/beetbox/beets/labels/testing>`__.
- There are several ways to improve the tests in general (see :ref:`testing` and
some places to think about performance optimization (see `Optimization
<https://github.com/beetbox/beets/wiki/Optimization>`__).
- Not all of our code is up to our coding conventions. In particular, the
`library API documentation
<https://beets.readthedocs.io/en/stable/dev/library.html>`__ are currently
quite sparse. You can help by adding to the docstrings in the code and to the
documentation pages themselves. beets follows `PEP-257
<https://www.python.org/dev/peps/pep-0257/>`__ for docstrings and in some
places, we also sometimes use `ReST autodoc syntax for Sphinx
<https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html>`__ to,
for example, refer to a class name.
Your First Contribution
=======================
-----------------------
If this is your first time contributing to an open source project,
welcome! If you are confused at all about how to contribute or what to
contribute, take a look at `this great
tutorial <http://makeapullrequest.com/>`__, or stop by our
`discussion board <https://github.com/beetbox/beets/discussions/>`__
if you have any questions.
We maintain a list of issues we reserved for those new to open source
labeled `“first timers
only” <https://github.com/beetbox/beets/issues?q=is%3Aopen+is%3Aissue+label%3A%22first+timers+only%22>`__.
Since the goal of these issues is to get users comfortable with
contributing to an open source project, please do not hesitate to ask
If this is your first time contributing to an open source project, welcome! If
you are confused at all about how to contribute or what to contribute, take a
look at `this great tutorial <http://makeapullrequest.com/>`__, or stop by our
`discussion board <https://github.com/beetbox/beets/discussions/>`__ if you have
any questions.
We maintain a list of issues we reserved for those new to open source labeled
`first timers only`_. Since the goal of these issues is to get users comfortable
with contributing to an open source project, please do not hesitate to ask any
questions.
.. _first timers only: https://github.com/beetbox/beets/issues?q=is%3Aopen+is%3Aissue+label%3A%22first+timers+only%22
How to Submit Your Work
=======================
-----------------------
Do you have a great bug fix, new feature, or documentation expansion
youd like to contribute? Follow these steps to create a GitHub pull
request and your code will ship in no time.
Do you have a great bug fix, new feature, or documentation expansion youd like
to contribute? Follow these steps to create a GitHub pull request and your code
will ship in no time.
1. Fork the beets repository and clone it (see above) to create a
workspace.
1. Fork the beets repository and clone it (see above) to create a workspace.
2. Install pre-commit, following the instructions `here
<https://pre-commit.com/>`_.
3. Make your changes.
4. Add tests. If youve fixed a bug, write a test to ensure that youve
actually fixed it. If theres a new feature or plugin, please
contribute tests that show that your code does what it says.
5. Add documentation. If youve added a new command flag, for example,
find the appropriate page under ``docs/`` where it needs to be
listed.
6. Add a changelog entry to ``docs/changelog.rst`` near the top of the
document.
4. Add tests. If youve fixed a bug, write a test to ensure that youve actually
fixed it. If theres a new feature or plugin, please contribute tests that
show that your code does what it says.
5. Add documentation. If youve added a new command flag, for example, find the
appropriate page under ``docs/`` where it needs to be listed.
6. Add a changelog entry to ``docs/changelog.rst`` near the top of the document.
7. Run the tests and style checker, see :ref:`testing`.
8. Push to your fork and open a pull request! Well be in touch shortly.
9. If you add commits to a pull request, please add a comment or
re-request a review after you push them since GitHub doesnt
automatically notify us when commits are added.
9. If you add commits to a pull request, please add a comment or re-request a
review after you push them since GitHub doesnt automatically notify us when
commits are added.
Remember, code contributions have four parts: the code, the tests, the
documentation, and the changelog entry. Thank you for contributing!
The Code
========
--------
The documentation has a section on the
`library API <https://beets.readthedocs.io/en/stable/dev/library.html>`__
that serves as an introduction to beets design.
The documentation has a section on the `library API
<https://beets.readthedocs.io/en/stable/dev/library.html>`__ that serves as an
introduction to beets design.
Coding Conventions
==================
------------------
General
-------
~~~~~~~
There are a few coding conventions we use in beets:
- Whenever you access the library database, do so through the provided
Library methods or via a Transaction object. Never call
``lib.conn.*`` directly. For example, do this:
- Whenever you access the library database, do so through the provided Library
methods or via a Transaction object. Never call ``lib.conn.*`` directly. For
example, do this:
.. code-block:: python
.. code-block:: python
with g.lib.transaction() as tx:
rows = tx.query("SELECT DISTINCT '{0}' FROM '{1}' ORDER BY '{2}'"
.format(field, model._table, sort_field))
with g.lib.transaction() as tx:
rows = tx.query(
"SELECT DISTINCT '{0}' FROM '{1}' ORDER BY '{2}'".format(
field, model._table, sort_field
)
)
To fetch Item objects from the database, use lib.items(…) and supply
a query as an argument. Resist the urge to write raw SQL for your
query. If you must use lower-level queries into the database, do
this:
To fetch Item objects from the database, use lib.items(…) and supply a query
as an argument. Resist the urge to write raw SQL for your query. If you must
use lower-level queries into the database, do this:
.. code-block:: python
.. code-block:: python
with lib.transaction() as tx:
rows = tx.query("SELECT …")
with lib.transaction() as tx:
rows = tx.query("SELECT …")
Transaction objects help control concurrent access to the database
and assist in debugging conflicting accesses.
- ``str.format()`` should be used instead of the ``%`` operator
- Never ``print`` informational messages; use the
`logging <http://docs.python.org/library/logging.html>`__ module
instead. In particular, we have our own logging shim, so youll see
``from beets import logging`` in most files.
Transaction objects help control concurrent access to the database and assist
in debugging conflicting accesses.
- The loggers use
`str.format <http://docs.python.org/library/stdtypes.html#str.format>`__-style
logging instead of ``%``-style, so you can type
``log.debug("{0}", obj)`` to do your formatting.
- ``str.format()`` should be used instead of the ``%`` operator
- Never ``print`` informational messages; use the `logging
<http://docs.python.org/library/logging.html>`__ module instead. In
particular, we have our own logging shim, so youll see ``from beets import
logging`` in most files.
- Exception handlers must use ``except A as B:`` instead of
``except A, B:``.
- The loggers use `str.format
<http://docs.python.org/library/stdtypes.html#str.format>`__-style logging
instead of ``%``-style, so you can type ``log.debug("{0}", obj)`` to do your
formatting.
- Exception handlers must use ``except A as B:`` instead of ``except A, B:``.
Style
-----
~~~~~
We use `ruff`_ to format and lint the codebase.
We use `ruff <https://docs.astral.sh/ruff/>`__ to format and lint the codebase.
Run ``poe check-format`` and ``poe lint`` to check your code for style and
linting errors. Running ``poe format`` will automatically format your code
according to the specifications required by the project.
.. _ruff: https://docs.astral.sh/ruff/
Similarly, run ``poe format-docs`` and ``poe lint-docs`` to ensure consistent
documentation formatting and check for any issues.
Handling Paths
--------------
~~~~~~~~~~~~~~
A great deal of convention deals with the handling of **paths**. Paths
are stored internally—in the database, for instance—as byte strings
(i.e., ``bytes`` instead of ``str`` in Python 3). This is because POSIX
operating systems path names are only reliably usable as byte
strings—operating systems typically recommend but do not require that
filenames use a given encoding, so violations of any reported encoding
are inevitable. On Windows, the strings are always encoded with UTF-8;
on Unix, the encoding is controlled by the filesystem. Here are some
guidelines to follow:
A great deal of convention deals with the handling of **paths**. Paths are
stored internally—in the database, for instance—as byte strings (i.e., ``bytes``
instead of ``str`` in Python 3). This is because POSIX operating systems path
names are only reliably usable as byte strings—operating systems typically
recommend but do not require that filenames use a given encoding, so violations
of any reported encoding are inevitable. On Windows, the strings are always
encoded with UTF-8; on Unix, the encoding is controlled by the filesystem. Here
are some guidelines to follow:
- If you have a Unicode path or youre not sure whether something is
Unicode or not, pass it through ``bytestring_path`` function in the
``beets.util`` module to convert it to bytes.
- Pass every path name through the ``syspath`` function (also in
``beets.util``) before sending it to any *operating system* file
operation (``open``, for example). This is necessary to use long
filenames (which, maddeningly, must be Unicode) on Windows. This
allows us to consistently store bytes in the database but use the
native encoding rule on both POSIX and Windows.
- Similarly, the ``displayable_path`` utility function converts
bytestring paths to a Unicode string for displaying to the user.
Every time you want to print out a string to the terminal or log it
with the ``logging`` module, feed it through this function.
- If you have a Unicode path or youre not sure whether something is Unicode or
not, pass it through ``bytestring_path`` function in the ``beets.util`` module
to convert it to bytes.
- Pass every path name through the ``syspath`` function (also in ``beets.util``)
before sending it to any *operating system* file operation (``open``, for
example). This is necessary to use long filenames (which, maddeningly, must be
Unicode) on Windows. This allows us to consistently store bytes in the
database but use the native encoding rule on both POSIX and Windows.
- Similarly, the ``displayable_path`` utility function converts bytestring paths
to a Unicode string for displaying to the user. Every time you want to print
out a string to the terminal or log it with the ``logging`` module, feed it
through this function.
Editor Settings
---------------
~~~~~~~~~~~~~~~
Personally, I work on beets with `vim`_. Here are
some ``.vimrc`` lines that might help with PEP 8-compliant Python
coding::
Personally, I work on beets with vim_. Here are some ``.vimrc`` lines that might
help with PEP 8-compliant Python coding:
::
filetype indent on
autocmd FileType python setlocal shiftwidth=4 tabstop=4 softtabstop=4 expandtab shiftround autoindent
Consider installing `this alternative Python indentation
plugin <https://github.com/mitsuhiko/vim-python-combined>`__. I also
like `neomake <https://github.com/neomake/neomake>`__ with its flake8
checker.
Consider installing `this alternative Python indentation plugin
<https://github.com/mitsuhiko/vim-python-combined>`__. I also like `neomake
<https://github.com/neomake/neomake>`__ with its flake8 checker.
.. _testing:
Testing
=======
-------
Running the Tests
-----------------
~~~~~~~~~~~~~~~~~
Use ``poe`` to run tests::
Use ``poe`` to run tests:
::
$ poe test [pytest options]
You can disable a hand-selected set of "slow" tests by setting the
environment variable ``SKIP_SLOW_TESTS``, for example::
You can disable a hand-selected set of "slow" tests by setting the environment
variable ``SKIP_SLOW_TESTS``, for example:
::
$ SKIP_SLOW_TESTS=1 poe test
Coverage
^^^^^^^^
++++++++
The ``test`` command does not include coverage as it slows down testing. In
order to measure it, use the ``test-with-coverage`` task
@ -359,56 +356,69 @@ You are welcome to explore coverage by opening the HTML report in
Note that for each covered line the report shows **which tests cover it**
(expand the list on the right-hand side of the affected line).
You can find project coverage status on `Codecov`_.
You can find project coverage status on Codecov_.
Red Flags
^^^^^^^^^
+++++++++
The `pytest-random`_ plugin makes it easy to randomize the order of
tests. ``poe test --random`` will occasionally turn up failing tests
that reveal ordering dependencies—which are bad news!
The pytest-random_ plugin makes it easy to randomize the order of tests. ``poe
test --random`` will occasionally turn up failing tests that reveal ordering
dependencies—which are bad news!
Test Dependencies
^^^^^^^^^^^^^^^^^
+++++++++++++++++
The tests have a few more dependencies than beets itself. (The additional
dependencies consist of testing utilities and dependencies of non-default
plugins exercised by the test suite.) The dependencies are listed under the
``tool.poetry.group.test.dependencies`` section in `pyproject.toml`_.
``tool.poetry.group.test.dependencies`` section in pyproject.toml_.
Writing Tests
-------------
~~~~~~~~~~~~~
Writing tests is done by adding or modifying files in folder `test`_.
Take a look at
`https://github.com/beetbox/beets/blob/master/test/test_template.py#L224`_
to get a basic view on how tests are written. Since we are currently migrating
the tests from `unittest`_ to `pytest`_, new tests should be written using
`pytest`_. Contributions migrating existing tests are welcome!
Writing tests is done by adding or modifying files in folder test_. Take a look
at `https://github.com/beetbox/beets/blob/master/test/test_template.py#L224`_ to
get a basic view on how tests are written. Since we are currently migrating the
tests from unittest_ to pytest_, new tests should be written using pytest_.
Contributions migrating existing tests are welcome!
External API requests under test should be mocked with `requests-mock`_,
However, we still want to know whether external APIs are up and that they
return expected responses, therefore we test them weekly with our `integration
test`_ suite.
External API requests under test should be mocked with requests-mock_, However,
we still want to know whether external APIs are up and that they return expected
responses, therefore we test them weekly with our `integration test`_ suite.
In order to add such a test, mark your test with the ``integration_test`` marker
.. code-block:: python
@pytest.mark.integration_test
def test_external_api_call():
...
@pytest.mark.integration_test
def test_external_api_call(): ...
This way, the test will be run only in the integration test suite.
.. _Codecov: https://codecov.io/github/beetbox/beets
.. _pytest-random: https://github.com/klrmn/pytest-random
.. _pytest: https://docs.pytest.org/en/stable/
.. _pyproject.toml: https://github.com/beetbox/beets/tree/master/pyproject.toml
.. _test: https://github.com/beetbox/beets/tree/master/test
.. _`https://github.com/beetbox/beets/blob/master/test/test_template.py#L224`: https://github.com/beetbox/beets/blob/master/test/test_template.py#L224
.. _unittest: https://docs.python.org/3/library/unittest.html
.. _integration test: https://github.com/beetbox/beets/actions?query=workflow%3A%22integration+tests%22
.. _requests-mock: https://requests-mock.readthedocs.io/en/latest/response.html
.. _codecov: https://codecov.io/github/beetbox/beets
.. _documentation: https://beets.readthedocs.io/en/stable/
.. _https://github.com/beetbox/beets/blob/master/test/test_template.py#l224: https://github.com/beetbox/beets/blob/master/test/test_template.py#L224
.. _integration test: https://github.com/beetbox/beets/actions?query=workflow%3A%22integration+tests%22
.. _pipx: https://pipx.pypa.io/stable
.. _poethepoet: https://poethepoet.natn.io/index.html
.. _poetry: https://python-poetry.org/docs/
.. _pyproject.toml: https://github.com/beetbox/beets/tree/master/pyproject.toml
.. _pytest: https://docs.pytest.org/en/stable/
.. _pytest-random: https://github.com/klrmn/pytest-random
.. _requests-mock: https://requests-mock.readthedocs.io/en/latest/response.html
.. _test: https://github.com/beetbox/beets/tree/master/test
.. _unittest: https://docs.python.org/3/library/unittest.html
.. _vim: https://www.vim.org/

View file

@ -10,115 +10,132 @@
.. image:: https://repology.org/badge/tiny-repos/beets.svg
:target: https://repology.org/project/beets/versions
beets
=====
Beets is the media library management system for obsessive music geeks.
The purpose of beets is to get your music collection right once and for all.
It catalogs your collection, automatically improving its metadata as it goes.
It then provides a bouquet of tools for manipulating and accessing your music.
The purpose of beets is to get your music collection right once and for all. It
catalogs your collection, automatically improving its metadata as it goes. It
then provides a bouquet of tools for manipulating and accessing your music.
Here's an example of beets' brainy tag corrector doing its thing::
Here's an example of beets' brainy tag corrector doing its thing:
$ beet import ~/music/ladytron
Tagging:
Ladytron - Witching Hour
(Similarity: 98.4%)
* Last One Standing -> The Last One Standing
* Beauty -> Beauty*2
* White Light Generation -> Whitelightgenerator
* All the Way -> All the Way...
::
$ beet import ~/music/ladytron
Tagging:
Ladytron - Witching Hour
(Similarity: 98.4%)
* Last One Standing -> The Last One Standing
* Beauty -> Beauty*2
* White Light Generation -> Whitelightgenerator
* All the Way -> All the Way...
Because beets is designed as a library, it can do almost anything you can
imagine for your music collection. Via `plugins`_, beets becomes a panacea:
imagine for your music collection. Via plugins_, beets becomes a panacea:
- Fetch or calculate all the metadata you could possibly need: `album art`_,
`lyrics`_, `genres`_, `tempos`_, `ReplayGain`_ levels, or `acoustic
fingerprints`_.
- Get metadata from `MusicBrainz`_, `Discogs`_, and `Beatport`_. Or guess
metadata using songs' filenames or their acoustic fingerprints.
lyrics_, genres_, tempos_, ReplayGain_ levels, or `acoustic fingerprints`_.
- Get metadata from MusicBrainz_, Discogs_, and Beatport_. Or guess metadata
using songs' filenames or their acoustic fingerprints.
- `Transcode audio`_ to any format you like.
- Check your library for `duplicate tracks and albums`_ or for `albums that
are missing tracks`_.
- Check your library for `duplicate tracks and albums`_ or for `albums that are
missing tracks`_.
- Clean up crufty tags left behind by other, less-awesome tools.
- Embed and extract album art from files' metadata.
- Browse your music library graphically through a Web browser and play it in any
browser that supports `HTML5 Audio`_.
- Analyze music files' metadata from the command line.
- Listen to your library with a music player that speaks the `MPD`_ protocol
and works with a staggering variety of interfaces.
- Listen to your library with a music player that speaks the MPD_ protocol and
works with a staggering variety of interfaces.
If beets doesn't do what you want yet, `writing your own plugin`_ is
shockingly simple if you know a little Python.
If beets doesn't do what you want yet, `writing your own plugin`_ is shockingly
simple if you know a little Python.
.. _acoustic fingerprints: https://beets.readthedocs.org/page/plugins/chroma.html
.. _album art: https://beets.readthedocs.org/page/plugins/fetchart.html
.. _albums that are missing tracks: https://beets.readthedocs.org/page/plugins/missing.html
.. _beatport: https://www.beatport.com
.. _discogs: https://www.discogs.com/
.. _duplicate tracks and albums: https://beets.readthedocs.org/page/plugins/duplicates.html
.. _genres: https://beets.readthedocs.org/page/plugins/lastgenre.html
.. _html5 audio: https://html.spec.whatwg.org/multipage/media.html#the-audio-element
.. _lyrics: https://beets.readthedocs.org/page/plugins/lyrics.html
.. _mpd: https://www.musicpd.org/
.. _musicbrainz: https://musicbrainz.org/
.. _musicbrainz music collection: https://musicbrainz.org/doc/Collections/
.. _plugins: https://beets.readthedocs.org/page/plugins/
.. _MPD: https://www.musicpd.org/
.. _MusicBrainz music collection: https://musicbrainz.org/doc/Collections/
.. _writing your own plugin:
https://beets.readthedocs.org/page/dev/plugins.html
.. _HTML5 Audio:
https://html.spec.whatwg.org/multipage/media.html#the-audio-element
.. _albums that are missing tracks:
https://beets.readthedocs.org/page/plugins/missing.html
.. _duplicate tracks and albums:
https://beets.readthedocs.org/page/plugins/duplicates.html
.. _Transcode audio:
https://beets.readthedocs.org/page/plugins/convert.html
.. _Discogs: https://www.discogs.com/
.. _acoustic fingerprints:
https://beets.readthedocs.org/page/plugins/chroma.html
.. _ReplayGain: https://beets.readthedocs.org/page/plugins/replaygain.html
.. _replaygain: https://beets.readthedocs.org/page/plugins/replaygain.html
.. _tempos: https://beets.readthedocs.org/page/plugins/acousticbrainz.html
.. _genres: https://beets.readthedocs.org/page/plugins/lastgenre.html
.. _album art: https://beets.readthedocs.org/page/plugins/fetchart.html
.. _lyrics: https://beets.readthedocs.org/page/plugins/lyrics.html
.. _MusicBrainz: https://musicbrainz.org/
.. _Beatport: https://www.beatport.com
.. _transcode audio: https://beets.readthedocs.org/page/plugins/convert.html
.. _writing your own plugin: https://beets.readthedocs.org/page/dev/plugins.html
Install
-------
You can install beets by typing ``pip install beets`` or directly from Github (see details `here`_).
Beets has also been packaged in the `software repositories`_ of several
distributions. Check out the `Getting Started`_ guide for more information.
You can install beets by typing ``pip install beets`` or directly from Github
(see details here_). Beets has also been packaged in the `software
repositories`_ of several distributions. Check out the `Getting Started`_ guide
for more information.
.. _getting started: https://beets.readthedocs.org/page/guides/main.html
.. _here: https://beets.readthedocs.io/en/latest/faq.html#run-the-latest-source-version-of-beets
.. _Getting Started: https://beets.readthedocs.org/page/guides/main.html
.. _software repositories: https://repology.org/project/beets/versions
Contribute
----------
Thank you for considering contributing to ``beets``! Whether you're a
programmer or not, you should be able to find all the info you need at
`CONTRIBUTING.rst`_.
Thank you for considering contributing to ``beets``! Whether you're a programmer
or not, you should be able to find all the info you need at CONTRIBUTING.rst_.
.. _CONTRIBUTING.rst: https://github.com/beetbox/beets/blob/master/CONTRIBUTING.rst
.. _contributing.rst: https://github.com/beetbox/beets/blob/master/CONTRIBUTING.rst
Read More
---------
Learn more about beets at `its Web site`_. Follow `@b33ts`_ on Mastodon for
news and updates.
Learn more about beets at `its Web site`_. Follow `@b33ts`_ on Mastodon for news
and updates.
.. _its Web site: https://beets.io/
.. _@b33ts: https://fosstodon.org/@beets
.. _its web site: https://beets.io/
Contact
-------
* Encountered a bug you'd like to report? Check out our `issue tracker`_!
* If your issue hasn't already been reported, please `open a new ticket`_
and we'll be in touch with you shortly.
* If you'd like to vote on a feature/bug, simply give a :+1: on issues
you'd like to see prioritized over others.
* Need help/support, would like to start a discussion, have an idea for a new
feature, or would just like to introduce yourself to the team? Check out
`GitHub Discussions`_!
.. _GitHub Discussions: https://github.com/beetbox/beets/discussions
- Encountered a bug you'd like to report? Check out our `issue tracker`_!
- If your issue hasn't already been reported, please `open a new ticket`_ and
we'll be in touch with you shortly.
- If you'd like to vote on a feature/bug, simply give a :+1: on issues you'd
like to see prioritized over others.
- Need help/support, would like to start a discussion, have an idea for a new
feature, or would just like to introduce yourself to the team? Check out
`GitHub Discussions`_!
.. _github discussions: https://github.com/beetbox/beets/discussions
.. _issue tracker: https://github.com/beetbox/beets/issues
.. _open a new ticket: https://github.com/beetbox/beets/issues/new/choose
Authors
@ -126,4 +143,4 @@ Authors
Beets is by `Adrian Sampson`_ with a supporting cast of thousands.
.. _Adrian Sampson: https://www.cs.cornell.edu/~asampson/
.. _adrian sampson: https://www.cs.cornell.edu/~asampson/

View file

@ -1,108 +1,119 @@
.. image:: https://img.shields.io/pypi/v/beets.svg
:target: https://pypi.python.org/pypi/beets
.. image:: https://img.shields.io/codecov/c/github/beetbox/beets.svg
:target: https://codecov.io/github/beetbox/beets
.. image:: https://travis-ci.org/beetbox/beets.svg?branch=master
:target: https://travis-ci.org/beetbox/beets
beets
=====
Beets는 강박적인 음악을 듣는 사람들을 위한 미디어 라이브러리 관리 시스템이다.
Beets의 목적은 음악들을 한번에 다 받는 것이다.
음악들을 카탈로그화 하고, 자동으로 메타 데이터를 개선한다.
그리고 음악에 접근하고 조작할 수 있는 도구들을 제공한다.
다음은 Beets의 brainy tag corrector가 한 일의 예시이다.
$ beet import ~/music/ladytron
Tagging:
Ladytron - Witching Hour
(Similarity: 98.4%)
* Last One Standing -> The Last One Standing
* Beauty -> Beauty*2
* White Light Generation -> Whitelightgenerator
* All the Way -> All the Way...
Beets는 라이브러리로 디자인 되었기 때문에, 당신이 음악들에 대해 상상하는 모든 것을 할 수 있다.
`plugins`_ 을 통해서 모든 것을 할 수 있는 것이다!
- 필요하는 메타 데이터를 계산하거나 패치 할 때: `album art`_,
`lyrics`_, `genres`_, `tempos`_, `ReplayGain`_ levels, or `acoustic
fingerprints`_.
- `MusicBrainz`_, `Discogs`_,`Beatport`_로부터 메타데이터를 가져오거나,
노래 제목이나 음향 특징으로 메타데이터를 추측한다
- `Transcode audio`_ 당신이 좋아하는 어떤 포맷으로든 변경한다.
- 당신의 라이브러리에서 `duplicate tracks and albums`_ 이나 `albums that are missing tracks`_ 를 검사한다.
- 남이 남기거나, 좋지 않은 도구로 남긴 잡다한 태그들을 지운다.
- 파일의 메타데이터에서 앨범 아트를 삽입이나 추출한다.
- 당신의 음악들을 `HTML5 Audio`_ 를 지원하는 어떤 브라우저든 재생할 수 있고,
웹 브라우저에 표시 할 수 있다.
- 명령어로부터 음악 파일의 메타데이터를 분석할 수 있다.
- `MPD`_ 프로토콜을 사용하여 음악 플레이어로 음악을 들으면, 엄청나게 다양한 인터페이스로 작동한다.
만약 Beets에 당신이 원하는게 아직 없다면,
당신이 python을 안다면 `writing your own plugin`_ _은 놀라울정도로 간단하다.
.. _plugins: https://beets.readthedocs.org/page/plugins/
.. _MPD: https://www.musicpd.org/
.. _MusicBrainz music collection: https://musicbrainz.org/doc/Collections/
.. _writing your own plugin:
https://beets.readthedocs.org/page/dev/plugins.html
.. _HTML5 Audio:
https://html.spec.whatwg.org/multipage/media.html#the-audio-element
.. _albums that are missing tracks:
https://beets.readthedocs.org/page/plugins/missing.html
.. _duplicate tracks and albums:
https://beets.readthedocs.org/page/plugins/duplicates.html
.. _Transcode audio:
https://beets.readthedocs.org/page/plugins/convert.html
.. _Discogs: https://www.discogs.com/
.. _acoustic fingerprints:
https://beets.readthedocs.org/page/plugins/chroma.html
.. _ReplayGain: https://beets.readthedocs.org/page/plugins/replaygain.html
.. _tempos: https://beets.readthedocs.org/page/plugins/acousticbrainz.html
.. _genres: https://beets.readthedocs.org/page/plugins/lastgenre.html
.. _album art: https://beets.readthedocs.org/page/plugins/fetchart.html
.. _lyrics: https://beets.readthedocs.org/page/plugins/lyrics.html
.. _MusicBrainz: https://musicbrainz.org/
.. _Beatport: https://www.beatport.com
설치
-------
당신은 ``pip install beets`` 을 사용해서 Beets를 설치할 수 있다.
그리고 `Getting Started`_ 가이드를 확인할 수 있다.
.. _Getting Started: https://beets.readthedocs.org/page/guides/main.html
컨트리뷰션
----------
어떻게 도우려는지 알고싶다면 `Hacking`_ 위키페이지를 확인하라.
당신은 docs 안에 `For Developers`_ 에도 관심이 있을수 있다.
.. _Hacking: https://github.com/beetbox/beets/wiki/Hacking
.. _For Developers: https://beets.readthedocs.io/en/stable/dev/
Read More
---------
`its Web site`_ 에서 Beets에 대해 조금 더 알아볼 수 있다.
트위터에서 `@b33ts`_ 를 팔로우하면 새 소식을 볼 수 있다.
.. _its Web site: https://beets.io/
.. _@b33ts: https://twitter.com/b33ts/
저자들
-------
`Adrian Sampson`_ 와 많은 사람들의 지지를 받아 Beets를 만들었다.
돕고 싶다면 `forum`_.를 방문하면 된다.
.. _forum: https://github.com/beetbox/beets/discussions/
.. _Adrian Sampson: https://www.cs.cornell.edu/~asampson/
.. image:: https://img.shields.io/pypi/v/beets.svg
:target: https://pypi.python.org/pypi/beets
.. image:: https://img.shields.io/codecov/c/github/beetbox/beets.svg
:target: https://codecov.io/github/beetbox/beets
.. image:: https://travis-ci.org/beetbox/beets.svg?branch=master
:target: https://travis-ci.org/beetbox/beets
beets
=====
Beets는 강박적인 음악을 듣는 사람들을 위한 미디어 라이브러리 관리 시스템이다.
Beets의 목적은 음악들을 한번에 다 받는 것이다. 음악들을 카탈로그화 하고, 자동으로 메타 데이터를 개선한다. 그리고 음악에 접근하고 조작할
수 있는 도구들을 제공한다.
다음은 Beets의 brainy tag corrector가 한 일의 예시이다.
::
$ beet import ~/music/ladytron
Tagging:
Ladytron - Witching Hour
(Similarity: 98.4%)
* Last One Standing -> The Last One Standing
* Beauty -> Beauty*2
* White Light Generation -> Whitelightgenerator
* All the Way -> All the Way...
Beets는 라이브러리로 디자인 되었기 때문에, 당신이 음악들에 대해 상상하는 모든 것을 할 수 있다. plugins_ 을 통해서 모든 것을 할
수 있는 것이다!
- 필요하는 메타 데이터를 계산하거나 패치 할 때: `album art`_, lyrics_, genres_, tempos_,
ReplayGain_ levels, or `acoustic fingerprints`_.
- MusicBrainz_, Discogs_,`Beatport`_로부터 메타데이터를 가져오거나, 노래 제목이나 음향 특징으로 메타데이터를
추측한다
- `Transcode audio`_ 당신이 좋아하는 어떤 포맷으로든 변경한다.
- 당신의 라이브러리에서 `duplicate tracks and albums`_ 이나 `albums that are missing
tracks`_ 를 검사한다.
- 남이 남기거나, 좋지 않은 도구로 남긴 잡다한 태그들을 지운다.
- 파일의 메타데이터에서 앨범 아트를 삽입이나 추출한다.
- 당신의 음악들을 `HTML5 Audio`_ 를 지원하는 어떤 브라우저든 재생할 수 있고, 웹 브라우저에 표시 할 수 있다.
- 명령어로부터 음악 파일의 메타데이터를 분석할 수 있다.
- MPD_ 프로토콜을 사용하여 음악 플레이어로 음악을 들으면, 엄청나게 다양한 인터페이스로 작동한다.
만약 Beets에 당신이 원하는게 아직 없다면, 당신이 python을 안다면 `writing your own plugin`_ _은 놀라울정도로
간단하다.
.. _acoustic fingerprints: https://beets.readthedocs.org/page/plugins/chroma.html
.. _album art: https://beets.readthedocs.org/page/plugins/fetchart.html
.. _albums that are missing tracks: https://beets.readthedocs.org/page/plugins/missing.html
.. _beatport: https://www.beatport.com
.. _discogs: https://www.discogs.com/
.. _duplicate tracks and albums: https://beets.readthedocs.org/page/plugins/duplicates.html
.. _genres: https://beets.readthedocs.org/page/plugins/lastgenre.html
.. _html5 audio: https://html.spec.whatwg.org/multipage/media.html#the-audio-element
.. _lyrics: https://beets.readthedocs.org/page/plugins/lyrics.html
.. _mpd: https://www.musicpd.org/
.. _musicbrainz: https://musicbrainz.org/
.. _musicbrainz music collection: https://musicbrainz.org/doc/Collections/
.. _plugins: https://beets.readthedocs.org/page/plugins/
.. _replaygain: https://beets.readthedocs.org/page/plugins/replaygain.html
.. _tempos: https://beets.readthedocs.org/page/plugins/acousticbrainz.html
.. _transcode audio: https://beets.readthedocs.org/page/plugins/convert.html
.. _writing your own plugin: https://beets.readthedocs.org/page/dev/plugins.html
설치
-------
당신은 ``pip install beets`` 을 사용해서 Beets를 설치할 수 있다. 그리고 `Getting Started`_ 가이드를
확인할 수 있다.
.. _getting started: https://beets.readthedocs.org/page/guides/main.html
컨트리뷰션
----------
어떻게 도우려는지 알고싶다면 Hacking_ 위키페이지를 확인하라. 당신은 docs 안에 `For Developers`_ 에도 관심이 있을수
있다.
.. _for developers: https://beets.readthedocs.io/en/stable/dev/
.. _hacking: https://github.com/beetbox/beets/wiki/Hacking
Read More
---------
`its Web site`_ 에서 Beets에 대해 조금 더 알아볼 수 있다. 트위터에서 `@b33ts`_ 를 팔로우하면 새 소식을 볼 수
있다.
.. _@b33ts: https://twitter.com/b33ts/
.. _its web site: https://beets.io/
저자들
-------
`Adrian Sampson`_ 와 많은 사람들의 지지를 받아 Beets를 만들었다. 돕고 싶다면 forum_.를 방문하면 된다.
.. _adrian sampson: https://www.cs.cornell.edu/~asampson/
.. _forum: https://github.com/beetbox/beets/discussions/

View file

@ -16,15 +16,16 @@
from __future__ import annotations
import warnings
from importlib import import_module
from typing import TYPE_CHECKING, Union
from beets import config, logging
from beets.util import get_most_common_tags as current_metadata
# Parts of external interface.
from beets.util import unique_list
from .distance import Distance
from ..util import deprecate_imports
from .hooks import AlbumInfo, AlbumMatch, TrackInfo, TrackMatch
from .match import Proposal, Recommendation, tag_album, tag_item
@ -33,10 +34,27 @@ if TYPE_CHECKING:
from beets.library import Album, Item, LibModel
def __getattr__(name: str):
if name == "current_metadata":
warnings.warn(
(
f"'beets.autotag.{name}' is deprecated and will be removed in"
" 3.0.0. Use 'beets.util.get_most_common_tags' instead."
),
DeprecationWarning,
stacklevel=2,
)
return import_module("beets.util").get_most_common_tags
return deprecate_imports(
__name__, {"Distance": "beets.autotag.distance"}, name, "3.0.0"
)
__all__ = [
"AlbumInfo",
"AlbumMatch",
"Distance", # for backwards compatibility
"Proposal",
"Recommendation",
"TrackInfo",
@ -44,7 +62,6 @@ __all__ = [
"apply_album_metadata",
"apply_item_metadata",
"apply_metadata",
"current_metadata", # for backwards compatibility
"tag_album",
"tag_item",
]

View file

@ -26,8 +26,9 @@ from abc import ABC
from collections import defaultdict
from collections.abc import Generator, Iterable, Iterator, Mapping, Sequence
from sqlite3 import Connection
from typing import TYPE_CHECKING, Any, AnyStr, Callable, Generic, TypeVar
from typing import TYPE_CHECKING, Any, AnyStr, Callable, Generic
from typing_extensions import TypeVar # default value support
from unidecode import unidecode
import beets
@ -49,10 +50,7 @@ if TYPE_CHECKING:
from .query import SQLiteType
D = TypeVar("D", bound="Database", default=Any)
else:
D = TypeVar("D", bound="Database")
D = TypeVar("D", bound="Database", default=Any)
FlexAttrs = dict[str, str]

View file

@ -1,33 +0,0 @@
from typing import Literal
EventType = Literal[
"pluginload",
"import",
"album_imported",
"album_removed",
"item_copied",
"item_imported",
"before_item_moved",
"item_moved",
"item_linked",
"item_hardlinked",
"item_reflinked",
"item_removed",
"write",
"after_write",
"import_task_created",
"import_task_start",
"import_task_apply",
"import_task_before_choice",
"import_task_choice",
"import_task_files",
"library_opened",
"database_change",
"cli_exit",
"import_begin",
"trackinfo_received",
"albuminfo_received",
"before_choose_candidate",
"mb_track_extract",
"mb_album_extract",
]

View file

@ -1,8 +1,21 @@
from beets.util import deprecate_imports
from .exceptions import FileOperationError, ReadError, WriteError
from .library import Library
from .models import Album, Item, LibModel
from .queries import parse_query_parts, parse_query_string
NEW_MODULE_BY_NAME = dict.fromkeys(
("DateType", "DurationType", "MusicalKey", "PathType"), "beets.dbcore.types"
) | dict.fromkeys(
("BLOB_TYPE", "SingletonQuery", "PathQuery"), "beets.dbcore.query"
)
def __getattr__(name: str):
return deprecate_imports(__name__, NEW_MODULE_BY_NAME, name, "3.0.0")
__all__ = [
"Library",
"LibModel",

View file

@ -10,20 +10,16 @@ from __future__ import annotations
import abc
import inspect
import re
import sys
import warnings
from typing import TYPE_CHECKING, Generic, Literal, Sequence, TypedDict, TypeVar
from typing_extensions import NotRequired
from beets.util import cached_classproperty
from beets.util.id_extractors import extract_release_id
from .plugins import BeetsPlugin, find_plugins, notify_info_yielded, send
if sys.version_info >= (3, 11):
from typing import NotRequired
else:
from typing_extensions import NotRequired
if TYPE_CHECKING:
from collections.abc import Iterable

View file

@ -20,28 +20,21 @@ import abc
import inspect
import re
import sys
import traceback
from collections import defaultdict
from functools import wraps
from pathlib import Path
from types import GenericAlias
from typing import TYPE_CHECKING, Any, Callable, Sequence, TypeVar
from typing import TYPE_CHECKING, Any, ClassVar, Literal, TypeVar
import mediafile
from typing_extensions import ParamSpec
import beets
from beets import logging
from beets.util import unique_list
if TYPE_CHECKING:
from beets.event_types import EventType
if sys.version_info >= (3, 10):
from typing import ParamSpec
else:
from typing_extensions import ParamSpec
if TYPE_CHECKING:
from collections.abc import Iterable
from collections.abc import Callable, Iterable, Sequence
from confuse import ConfigView
@ -63,7 +56,7 @@ if TYPE_CHECKING:
P = ParamSpec("P")
Ret = TypeVar("Ret", bound=Any)
Listener = Callable[..., None]
Listener = Callable[..., Any]
IterF = Callable[P, Iterable[Ret]]
@ -72,6 +65,37 @@ PLUGIN_NAMESPACE = "beetsplug"
# Plugins using the Last.fm API can share the same API key.
LASTFM_KEY = "2dc3914abf35f0d9c92d97d8f8e42b43"
EventType = Literal[
"after_write",
"album_imported",
"album_removed",
"albuminfo_received",
"before_choose_candidate",
"before_item_moved",
"cli_exit",
"database_change",
"import",
"import_begin",
"import_task_apply",
"import_task_before_choice",
"import_task_choice",
"import_task_created",
"import_task_files",
"import_task_start",
"item_copied",
"item_hardlinked",
"item_imported",
"item_linked",
"item_moved",
"item_reflinked",
"item_removed",
"library_opened",
"mb_album_extract",
"mb_track_extract",
"pluginload",
"trackinfo_received",
"write",
]
# Global logger.
log = logging.getLogger("beets")
@ -84,6 +108,17 @@ class PluginConflictError(Exception):
"""
class PluginImportError(ImportError):
"""Indicates that a plugin could not be imported.
This is a subclass of ImportError so that it can be caught separately
from other errors.
"""
def __init__(self, name: str):
super().__init__(f"Could not import plugin {name}")
class PluginLogFilter(logging.Filter):
"""A logging filter that identifies the plugin that emitted a log
message.
@ -110,6 +145,14 @@ class BeetsPlugin(metaclass=abc.ABCMeta):
the abstract methods defined here.
"""
_raw_listeners: ClassVar[dict[EventType, list[Listener]]] = defaultdict(
list
)
listeners: ClassVar[dict[EventType, list[Listener]]] = defaultdict(list)
template_funcs: TFuncMap[str] | None = None
template_fields: TFuncMap[Item] | None = None
album_template_fields: TFuncMap[Album] | None = None
name: str
config: ConfigView
early_import_stages: list[ImportStageFunc]
@ -223,25 +266,13 @@ class BeetsPlugin(metaclass=abc.ABCMeta):
mediafile.MediaFile.add_field(name, descriptor)
library.Item._media_fields.add(name)
_raw_listeners: dict[str, list[Listener]] | None = None
listeners: dict[str, list[Listener]] | None = None
def register_listener(self, event: "EventType", func: Listener):
def register_listener(self, event: EventType, func: Listener) -> None:
"""Add a function as a listener for the specified event."""
wrapped_func = self._set_log_level_and_params(logging.WARNING, func)
cls = self.__class__
if cls.listeners is None or cls._raw_listeners is None:
cls._raw_listeners = defaultdict(list)
cls.listeners = defaultdict(list)
if func not in cls._raw_listeners[event]:
cls._raw_listeners[event].append(func)
cls.listeners[event].append(wrapped_func)
template_funcs: TFuncMap[str] | None = None
template_fields: TFuncMap[Item] | None = None
album_template_fields: TFuncMap[Album] | None = None
if func not in self._raw_listeners[event]:
self._raw_listeners[event].append(func)
self.listeners[event].append(
self._set_log_level_and_params(logging.WARNING, func)
)
@classmethod
def template_func(cls, name: str) -> Callable[[TFunc[str]], TFunc[str]]:
@ -275,69 +306,92 @@ class BeetsPlugin(metaclass=abc.ABCMeta):
return helper
_classes: set[type[BeetsPlugin]] = set()
def get_plugin_names() -> list[str]:
"""Discover and return the set of plugin names to be loaded.
def load_plugins(names: Sequence[str] = ()) -> None:
"""Imports the modules for a sequence of plugin names. Each name
must be the name of a Python module under the "beetsplug" namespace
package in sys.path; the module indicated should contain the
BeetsPlugin subclasses desired.
Configures the plugin search paths and resolves the final set of plugins
based on configuration settings, inclusion filters, and exclusion rules.
Automatically includes the musicbrainz plugin when enabled in configuration.
"""
for name in names:
modname = f"{PLUGIN_NAMESPACE}.{name}"
paths = [
str(Path(p).expanduser().absolute())
for p in beets.config["pluginpath"].as_str_seq(split=False)
]
log.debug("plugin paths: {}", paths)
# Extend the `beetsplug` package to include the plugin paths.
import beetsplug
beetsplug.__path__ = paths + list(beetsplug.__path__)
# For backwards compatibility, also support plugin paths that
# *contain* a `beetsplug` package.
sys.path += paths
plugins = unique_list(beets.config["plugins"].as_str_seq())
# TODO: Remove in v3.0.0
if (
"musicbrainz" not in plugins
and "musicbrainz" in beets.config
and beets.config["musicbrainz"].get().get("enabled")
):
plugins.append("musicbrainz")
beets.config.add({"disabled_plugins": []})
disabled_plugins = set(beets.config["disabled_plugins"].as_str_seq())
return [p for p in plugins if p not in disabled_plugins]
def _get_plugin(name: str) -> BeetsPlugin | None:
"""Dynamically load and instantiate a plugin class by name.
Attempts to import the plugin module, locate the appropriate plugin class
within it, and return an instance. Handles import failures gracefully and
logs warnings for missing plugins or loading errors.
"""
try:
try:
try:
namespace = __import__(modname, None, None)
except ImportError as exc:
# Again, this is hacky:
if exc.args[0].endswith(" " + name):
log.warning("** plugin {0} not found", name)
else:
raise
else:
for obj in getattr(namespace, name).__dict__.values():
if (
inspect.isclass(obj)
and not isinstance(
obj, GenericAlias
) # seems to be needed for python <= 3.9 only
and issubclass(obj, BeetsPlugin)
and obj != BeetsPlugin
and not inspect.isabstract(obj)
and obj not in _classes
):
_classes.add(obj)
namespace = __import__(f"{PLUGIN_NAMESPACE}.{name}", None, None)
except Exception as exc:
raise PluginImportError(name) from exc
except Exception:
log.warning(
"** error loading plugin {}:\n{}",
name,
traceback.format_exc(),
)
for obj in getattr(namespace, name).__dict__.values():
if (
inspect.isclass(obj)
and not isinstance(
obj, GenericAlias
) # seems to be needed for python <= 3.9 only
and issubclass(obj, BeetsPlugin)
and obj != BeetsPlugin
and not inspect.isabstract(obj)
):
return obj()
except Exception:
log.warning("** error loading plugin {}", name, exc_info=True)
return None
_instances: dict[type[BeetsPlugin], BeetsPlugin] = {}
_instances: list[BeetsPlugin] = []
def find_plugins() -> list[BeetsPlugin]:
"""Returns a list of BeetsPlugin subclass instances from all
currently loaded beets plugins. Loads the default plugin set
first.
def load_plugins() -> None:
"""Initialize the plugin system by loading all configured plugins.
Performs one-time plugin discovery and instantiation, storing loaded plugin
instances globally. Emits a pluginload event after successful initialization
to notify other components.
"""
if _instances:
# After the first call, use cached instances for performance reasons.
# See https://github.com/beetbox/beets/pull/3810
return list(_instances.values())
if not _instances:
names = get_plugin_names()
log.info("Loading plugins: {}", ", ".join(sorted(names)))
_instances.extend(filter(None, map(_get_plugin, names)))
load_plugins()
plugins = []
for cls in _classes:
# Only instantiate each plugin class once.
if cls not in _instances:
_instances[cls] = cls()
plugins.append(_instances[cls])
return plugins
send("pluginload")
def find_plugins() -> Iterable[BeetsPlugin]:
return _instances
# Communication with plugins.
@ -388,7 +442,9 @@ def named_queries(model_cls: type[AnyModel]) -> dict[str, FieldQueryType]:
}
def notify_info_yielded(event: str) -> Callable[[IterF[P, Ret]], IterF[P, Ret]]:
def notify_info_yielded(
event: EventType,
) -> Callable[[IterF[P, Ret]], IterF[P, Ret]]:
"""Makes a generator send the event 'event' every time it yields.
This decorator is supposed to decorate a generator, but any function
returning an iterable should work.
@ -479,19 +535,7 @@ def album_field_getters() -> TFuncMap[Album]:
# Event dispatch.
def event_handlers() -> dict[str, list[Listener]]:
"""Find all event handlers from plugins as a dictionary mapping
event names to sequences of callables.
"""
all_handlers: dict[str, list[Listener]] = defaultdict(list)
for plugin in find_plugins():
if plugin.listeners:
for event, handlers in plugin.listeners.items():
all_handlers[event] += handlers
return all_handlers
def send(event: str, **arguments: Any) -> list[Any]:
def send(event: EventType, **arguments: Any) -> list[Any]:
"""Send an event to all assigned event listeners.
`event` is the name of the event to send, all other named arguments
@ -500,12 +544,11 @@ def send(event: str, **arguments: Any) -> list[Any]:
Return a list of non-None values returned from the handlers.
"""
log.debug("Sending event: {0}", event)
results: list[Any] = []
for handler in event_handlers()[event]:
result = handler(**arguments)
if result is not None:
results.append(result)
return results
return [
r
for handler in BeetsPlugin.listeners[event]
if (r := handler(**arguments)) is not None
]
def feat_tokens(for_artist: bool = True) -> str:

0
beets/py.typed Normal file
View file

View file

@ -481,6 +481,11 @@ class PluginMixin(ConfigMixin):
super().teardown_beets()
self.unload_plugins()
def register_plugin(
self, plugin_class: type[beets.plugins.BeetsPlugin]
) -> None:
beets.plugins._instances.append(plugin_class())
def load_plugins(self, *plugins: str) -> None:
"""Load and initialize plugins by names.
@ -491,18 +496,15 @@ class PluginMixin(ConfigMixin):
plugins = (self.plugin,) if hasattr(self, "plugin") else plugins
self.config["plugins"] = plugins
cached_classproperty.cache.clear()
beets.plugins.load_plugins(plugins)
beets.plugins.send("pluginload")
beets.plugins.find_plugins()
beets.plugins.load_plugins()
def unload_plugins(self) -> None:
"""Unload all plugins and remove them from the configuration."""
# FIXME this should eventually be handled by a plugin manager
for plugin_class in beets.plugins._instances:
plugin_class.listeners = None
beets.plugins.BeetsPlugin.listeners.clear()
beets.plugins.BeetsPlugin._raw_listeners.clear()
self.config["plugins"] = []
beets.plugins._classes = set()
beets.plugins._instances = {}
beets.plugins._instances.clear()
@contextmanager
def configure_plugin(self, config: Any):

View file

@ -28,8 +28,9 @@ import struct
import sys
import textwrap
import traceback
import warnings
from difflib import SequenceMatcher
from typing import TYPE_CHECKING, Any, Callable
from typing import Any, Callable
import confuse
@ -39,9 +40,6 @@ from beets.dbcore import query as db_query
from beets.util import as_string
from beets.util.functemplate import template
if TYPE_CHECKING:
from types import ModuleType
# On Windows platforms, use colorama to support "ANSI" terminal colors.
if sys.platform == "win32":
try:
@ -104,6 +102,21 @@ def _stream_encoding(stream, default="utf-8"):
return stream.encoding or default
def decargs(arglist):
"""Given a list of command-line argument bytestrings, attempts to
decode them to Unicode strings when running under Python 2.
.. deprecated:: 2.4.0
This function will be removed in 3.0.0.
"""
warnings.warn(
"decargs() is deprecated and will be removed in version 3.0.0.",
DeprecationWarning,
stacklevel=2,
)
return arglist
def print_(*strings: str, end: str = "\n") -> None:
"""Like print, but rather than raising an error when a character
is not in the terminal's encoding's character set, just silently
@ -1557,59 +1570,16 @@ optparse.Option.ALWAYS_TYPED_ACTIONS += ("callback",)
# The main entry point and bootstrapping.
def _load_plugins(
options: optparse.Values, config: confuse.LazyConfig
) -> ModuleType:
"""Load the plugins specified on the command line or in the configuration."""
paths = config["pluginpath"].as_str_seq(split=False)
paths = [util.normpath(p) for p in paths]
log.debug("plugin paths: {0}", util.displayable_path(paths))
# On Python 3, the search paths need to be unicode.
paths = [os.fsdecode(p) for p in paths]
# Extend the `beetsplug` package to include the plugin paths.
import beetsplug
beetsplug.__path__ = paths + list(beetsplug.__path__)
# For backwards compatibility, also support plugin paths that
# *contain* a `beetsplug` package.
sys.path += paths
# If we were given any plugins on the command line, use those.
if options.plugins is not None:
plugin_list = (
options.plugins.split(",") if len(options.plugins) > 0 else []
)
else:
plugin_list = config["plugins"].as_str_seq()
# TODO: Remove in v2.4 or v3
if "musicbrainz" in config and config["musicbrainz"].get().get(
"enabled"
):
plugin_list.append("musicbrainz")
# Exclude any plugins that were specified on the command line
if options.exclude is not None:
plugin_list = [
p for p in plugin_list if p not in options.exclude.split(",")
]
plugins.load_plugins(plugin_list)
return plugins
def _setup(options, lib=None):
def _setup(
options: optparse.Values, lib: library.Library | None
) -> tuple[list[Subcommand], library.Library]:
"""Prepare and global state and updates it with command line options.
Returns a list of subcommands, a list of plugins, and a library instance.
"""
config = _configure(options)
plugins = _load_plugins(options, config)
plugins.send("pluginload")
plugins.load_plugins()
# Get the default subcommands.
from beets.ui.commands import default_commands
@ -1621,7 +1591,7 @@ def _setup(options, lib=None):
lib = _open_library(config)
plugins.send("library_opened", lib=lib)
return subcommands, plugins, lib
return subcommands, lib
def _configure(options):
@ -1675,7 +1645,7 @@ def _ensure_db_directory_exists(path):
os.makedirs(newpath)
def _open_library(config):
def _open_library(config: confuse.LazyConfig) -> library.Library:
"""Create a new library instance from the configuration."""
dbpath = util.bytestring_path(config["library"].as_filename())
_ensure_db_directory_exists(dbpath)
@ -1702,7 +1672,7 @@ def _open_library(config):
return lib
def _raw_main(args, lib=None):
def _raw_main(args: list[str], lib=None) -> None:
"""A helper function for `main` without top-level exception
handling.
"""
@ -1728,16 +1698,31 @@ def _raw_main(args, lib=None):
parser.add_option(
"-c", "--config", dest="config", help="path to configuration file"
)
def parse_csl_callback(
option: optparse.Option, _, value: str, parser: SubcommandsOptionParser
):
"""Parse a comma-separated list of values."""
setattr(
parser.values,
option.dest, # type: ignore[arg-type]
list(filter(None, value.split(","))),
)
parser.add_option(
"-p",
"--plugins",
dest="plugins",
action="callback",
callback=parse_csl_callback,
help="a comma-separated list of plugins to load",
)
parser.add_option(
"-P",
"--disable-plugins",
dest="exclude",
dest="disabled_plugins",
action="callback",
callback=parse_csl_callback,
help="a comma-separated list of plugins to disable",
)
parser.add_option(
@ -1769,7 +1754,7 @@ def _raw_main(args, lib=None):
return config_edit()
test_lib = bool(lib)
subcommands, plugins, lib = _setup(options, lib)
subcommands, lib = _setup(options, lib)
parser.add_subcommand(*subcommands)
subcommand, suboptions, subargs = parser.parse_subcommand(subargs)

View file

@ -27,6 +27,7 @@ import subprocess
import sys
import tempfile
import traceback
import warnings
from collections import Counter
from collections.abc import Sequence
from contextlib import suppress
@ -1191,3 +1192,26 @@ def get_temp_filename(
def unique_list(elements: Iterable[T]) -> list[T]:
"""Return a list with unique elements in the original order."""
return list(dict.fromkeys(elements))
def deprecate_imports(
old_module: str, new_module_by_name: dict[str, str], name: str, version: str
) -> Any:
"""Handle deprecated module imports by redirecting to new locations.
Facilitates gradual migration of module structure by intercepting import
attempts for relocated functionality. Issues deprecation warnings while
transparently providing access to the moved implementation, allowing
existing code to continue working during transition periods.
"""
if new_module := new_module_by_name.get(name):
warnings.warn(
(
f"'{old_module}.{name}' is deprecated and will be removed"
f" in {version}. Use '{new_module}.{name}' instead."
),
DeprecationWarning,
stacklevel=2,
)
return getattr(import_module(new_module), name)
raise AttributeError(f"module '{old_module}' has no attribute '{name}'")

View file

@ -38,10 +38,7 @@ import sys
from threading import Lock, Thread
from typing import Callable, Generator, TypeVar
if sys.version_info >= (3, 11):
from typing import TypeVarTuple, Unpack
else:
from typing_extensions import TypeVarTuple, Unpack
from typing_extensions import TypeVarTuple, Unpack
BUBBLE = "__PIPELINE_BUBBLE__"
POISON = "__PIPELINE_POISON__"

View file

@ -18,9 +18,9 @@ import errno
import hashlib
import json
import os
import shutil
import subprocess
import tempfile
from distutils.spawn import find_executable
import requests
@ -84,7 +84,7 @@ class AcousticBrainzSubmitPlugin(plugins.BeetsPlugin):
# Get the executable location on the system, which we need
# to calculate the SHA-1 hash.
self.extractor = find_executable(self.extractor)
self.extractor = shutil.which(self.extractor)
# Calculate extractor hash.
self.extractor_sha = hashlib.sha1()

View file

@ -16,7 +16,6 @@
import os
import re
import sys
from collections.abc import Mapping
from dataclasses import dataclass
from mimetypes import guess_type
@ -30,11 +29,7 @@ from flask import (
request,
send_file,
)
if sys.version_info >= (3, 11):
from typing import Self
else:
from typing_extensions import Self
from typing_extensions import Self
from beets import config
from beets.dbcore.query import (

View file

@ -305,7 +305,14 @@ class DiscogsPlugin(MetadataSourcePlugin):
# Explicitly reload the `Release` fields, as they might not be yet
# present if the result is from a `discogs_client.search()`.
if not result.data.get("artists"):
result.refresh()
try:
result.refresh()
except CONNECTION_ERRORS:
self._log.debug(
"Connection error in release lookup: {0}",
result,
)
return None
# Sanity check for required fields. The list of required fields is
# defined at Guideline 1.3.1.a, but in practice some releases might be

View file

@ -25,7 +25,7 @@ class LoadExtPlugin(BeetsPlugin):
super().__init__()
if not Database.supports_extensions:
self._log.warn(
self._log.warning(
"loadext is enabled but the current SQLite "
"installation does not support extensions"
)

View file

@ -1,14 +1,17 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="the music geeks media organizer">
<meta name="keywords"
content="beets, media, music, library, metadata, player, tagger, grep, transcoder, organizer">
<title>beets</title>
<link rel="stylesheet"
href="{{ url_for('static', filename='beets.css') }}" type="text/css">
href="{{ url_for('static', filename='beets.css') }}"
type="text/css">
<script src="{{ url_for('static', filename='jquery.js') }}"></script>
<script src="{{ url_for('static', filename='underscore.js') }}">
</script>
<script src="{{ url_for('static', filename='underscore.js') }}"></script>
<script src="{{ url_for('static', filename='backbone.js') }}"></script>
<script src="{{ url_for('static', filename='beets.js') }}"></script>
</head>
@ -17,18 +20,14 @@
<h1>beets</h1>
<div id="player">
<audio></audio>
<button class="disabled">&#9654;</button>
<button class="play">&#9654;</button>
<button class="pause" style="letter-spacing: 1px;">&#10073;&#10073;</button>
<span class="times">
<span class="currentTime">
</span>
<span class="currentTime"></span>
</span>
</div>
</div>
<div id="entities">
<form id="queryForm">
<input type="search" id="query" placeholder="Query">
@ -36,15 +35,14 @@
<ul id="results">
</ul>
</div>
<div id="main-detail">
</div>
<div id="extra-detail">
</div>
<div id="main-detail"></div>
<div id="extra-detail"></div>
<!-- Templates. -->
<script type="text/template" id="item-entry-template">
<% if (artist) { %><%= artist %><% } %>
<% if (artist && album) { %> &ndash; <% } %>
<% if (album) { %><%= album %><% } %>
<% if ((artist || album) && title) { %> &ndash; <% } %>
<%= title %>
<span class="playing">&#9654;</span>
</script>

View file

@ -1,5 +1,5 @@
comment:
layout: "condensed_header, condensed_files"
layout: "header, diff, files"
require_changes: true
# Sets non-blocking status checks
@ -13,6 +13,3 @@ coverage:
default:
informational: true
changes: false
github_checks:
annotations: false

View file

@ -1,3 +1,3 @@
{{ fullname | escape | underline}}
.. currentmodule:: {{ module }}
.. auto{{ objtype }}:: {{ objname }}
.. auto{{ objtype }}:: {{ objname }}

View file

@ -3,10 +3,10 @@
.. currentmodule:: {{ module }}
.. autoclass:: {{ objname }}
:members: <-- add at least this line
:members: <-- add at least this line
:private-members:
:show-inheritance: <-- plus I want to show inheritance...
:inherited-members: <-- ...and inherited members too
:show-inheritance: <-- plus I want to show inheritance...
:inherited-members: <-- ...and inherited members too
{% block methods %}
.. automethod:: __init__
@ -25,4 +25,3 @@
{% endblock %}
.. rubric:: {{ _('Methods definition') }}

View file

@ -8,4 +8,4 @@
{%- endfor %}
{% endif %}
{% endblock %}
{% endblock %}

View file

@ -1,20 +1,18 @@
Database
--------
========
.. currentmodule:: beets.library
Library
'''''''
-------
.. autosummary::
:toctree: generated/
Library
Models
''''''
------
.. autosummary::
:toctree: generated/
@ -23,9 +21,8 @@ Models
Album
Item
Transactions
''''''''''''
------------
.. currentmodule:: beets.dbcore.db
@ -35,7 +32,7 @@ Transactions
Transaction
Queries
'''''''
-------
.. currentmodule:: beets.dbcore.query
@ -44,4 +41,4 @@ Queries
Query
FieldQuery
AndQuery
AndQuery

View file

@ -1,10 +1,8 @@
Plugins
-------
=======
.. currentmodule:: beets.plugins
.. autosummary::
:toctree: generated/

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,4 @@
.. code_of_conduct:
..
code_of_conduct:
.. include:: ../CODE_OF_CONDUCT.rst

View file

@ -1,3 +1,4 @@
.. contributing:
..
contributing:
.. include:: ../CONTRIBUTING.rst

View file

@ -2,8 +2,7 @@ Providing a CLI
===============
The ``beets.ui`` module houses interactions with the user via a terminal, the
:doc:`/reference/cli`.
The main function is called when the user types beet on the command line.
The CLI functionality is organized into commands, some of which are built-in
and some of which are provided by plugins. The built-in commands are all
implemented in the ``beets.ui.commands`` submodule.
:doc:`/reference/cli`. The main function is called when the user types beet on
the command line. The CLI functionality is organized into commands, some of
which are built-in and some of which are provided by plugins. The built-in
commands are all implemented in the ``beets.ui.commands`` submodule.

View file

@ -3,17 +3,17 @@ Music Importer
The importer component is responsible for the user-centric workflow that adds
music to a library. This is one of the first aspects that a user experiences
when using beets: it finds music in the filesystem, groups it into albums,
finds corresponding metadata in MusicBrainz, asks the user for intervention,
applies changes, and moves/copies files. A description of its user interface is
given in :doc:`/guides/tagger`.
when using beets: it finds music in the filesystem, groups it into albums, finds
corresponding metadata in MusicBrainz, asks the user for intervention, applies
changes, and moves/copies files. A description of its user interface is given in
:doc:`/guides/tagger`.
The workflow is implemented in the ``beets.importer`` module and is
distinct from the core logic for matching MusicBrainz metadata (in the
``beets.autotag`` module). The workflow is also decoupled from the command-line
interface with the hope that, eventually, other (graphical) interfaces can be
bolted onto the same importer implementation.
The workflow is implemented in the ``beets.importer`` module and is distinct
from the core logic for matching MusicBrainz metadata (in the ``beets.autotag``
module). The workflow is also decoupled from the command-line interface with the
hope that, eventually, other (graphical) interfaces can be bolted onto the same
importer implementation.
The importer is multithreaded and follows the pipeline pattern. Each pipeline
stage is a Python coroutine. The ``beets.util.pipeline`` module houses
a generic, reusable implementation of a multithreaded pipeline.
stage is a Python coroutine. The ``beets.util.pipeline`` module houses a
generic, reusable implementation of a multithreaded pipeline.

View file

@ -4,10 +4,10 @@ For Developers
This section contains information for developers. Read on if you're interested
in hacking beets itself or creating plugins for it.
See also the documentation for `MediaFile`_, the library used by beets to read
and write metadata tags in media files.
See also the documentation for MediaFile_, the library used by beets to read and
write metadata tags in media files.
.. _MediaFile: https://mediafile.readthedocs.io/en/latest/
.. _mediafile: https://mediafile.readthedocs.io/en/latest/
.. toctree::
:maxdepth: 1
@ -17,11 +17,9 @@ and write metadata tags in media files.
importer
cli
.. toctree::
:maxdepth: 1
:caption: API Reference
../api/plugins
../api/database

View file

@ -4,8 +4,8 @@ Library Database API
.. currentmodule:: beets.library
This page describes the internal API of beets' core database features. It
doesn't exhaustively document the API, but is aimed at giving an overview of
the architecture to orient anyone who wants to dive into the code.
doesn't exhaustively document the API, but is aimed at giving an overview of the
architecture to orient anyone who wants to dive into the code.
The :class:`Library` object is the central repository for data in beets. It
represents a database containing songs, which are :class:`Item` instances, and
@ -16,26 +16,26 @@ The Library Class
The :class:`Library` is typically instantiated as a singleton. A single
invocation of beets usually has only one :class:`Library`. It's powered by
:class:`dbcore.Database` under the hood, which handles the `SQLite`_
abstraction, something like a very minimal `ORM`_. The library is also
responsible for handling queries to retrieve stored objects.
:class:`dbcore.Database` under the hood, which handles the SQLite_ abstraction,
something like a very minimal ORM_. The library is also responsible for handling
queries to retrieve stored objects.
Overview
''''''''
Overview
~~~~~~~~
You can add new items or albums to the library via the
:py:meth:`Library.add` and :py:meth:`Library.add_album` methods.
You can add new items or albums to the library via the :py:meth:`Library.add`
and :py:meth:`Library.add_album` methods.
You may also query the library for items and albums using the
:py:meth:`Library.items`, :py:meth:`Library.albums`, :py:meth:`Library.get_item` and :py:meth:`Library.get_album` methods.
:py:meth:`Library.items`, :py:meth:`Library.albums`, :py:meth:`Library.get_item`
and :py:meth:`Library.get_album` methods.
Any modifications to the library must go through a
:class:`Transaction` object, which you can get using the
:py:meth:`Library.transaction` context manager.
Any modifications to the library must go through a :class:`Transaction` object,
which you can get using the :py:meth:`Library.transaction` context manager.
.. _SQLite: https://sqlite.org/index.html
.. _ORM: https://en.wikipedia.org/wiki/Object-relational_mapping
.. _orm: https://en.wikipedia.org/wiki/Object-relational_mapping
.. _sqlite: https://sqlite.org/index.html
Model Classes
-------------
@ -49,108 +49,103 @@ To get or change the metadata of a model (an item or album), either access its
attributes (e.g., ``print(album.year)`` or ``album.year = 2012``) or use the
``dict``-like interface (e.g. ``item['artist']``).
Model base
''''''''''
~~~~~~~~~~
Models use dirty-flags to track when the object's metadata goes out of
sync with the database. The dirty dictionary maps field names to booleans
indicating whether the field has been written since the object was last
synchronized (via load or store) with the database. This logic is implemented
in the model base class :class:`LibModel` and is inherited by both
:class:`Item` and :class:`Album`.
Models use dirty-flags to track when the object's metadata goes out of sync with
the database. The dirty dictionary maps field names to booleans indicating
whether the field has been written since the object was last synchronized (via
load or store) with the database. This logic is implemented in the model base
class :class:`LibModel` and is inherited by both :class:`Item` and
:class:`Album`.
We provide CRUD-like methods for interacting with the database:
* :py:meth:`LibModel.store`
* :py:meth:`LibModel.load`
* :py:meth:`LibModel.remove`
* :py:meth:`LibModel.add`
- :py:meth:`LibModel.store`
- :py:meth:`LibModel.load`
- :py:meth:`LibModel.remove`
- :py:meth:`LibModel.add`
The base class :class:`beets.dbcore.Model` has a ``dict``-like interface, so
normal the normal mapping API is supported:
* :py:meth:`LibModel.keys`
* :py:meth:`LibModel.update`
* :py:meth:`LibModel.items`
* :py:meth:`LibModel.get`
- :py:meth:`LibModel.keys`
- :py:meth:`LibModel.update`
- :py:meth:`LibModel.items`
- :py:meth:`LibModel.get`
Item
''''
~~~~
Each :class:`Item` object represents a song or track. (We use the more generic
term item because, one day, beets might support non-music media.) An item can
either be purely abstract, in which case it's just a bag of metadata fields,
or it can have an associated file (indicated by ``item.path``).
either be purely abstract, in which case it's just a bag of metadata fields, or
it can have an associated file (indicated by ``item.path``).
In terms of the underlying SQLite database, items are backed by a single table
called items with one column per metadata fields. The metadata fields currently
in use are listed in ``library.py`` in ``Item._fields``.
To read and write a file's tags, we use the `MediaFile`_ library.
To make changes to either the database or the tags on a file, you
update an item's fields (e.g., ``item.title = "Let It Be"``) and then call
``item.write()``.
To read and write a file's tags, we use the MediaFile_ library. To make changes
to either the database or the tags on a file, you update an item's fields (e.g.,
``item.title = "Let It Be"``) and then call ``item.write()``.
.. _MediaFile: https://mediafile.readthedocs.io/en/latest/
.. _mediafile: https://mediafile.readthedocs.io/en/latest/
Items also track their modification times (mtimes) to help detect when they
become out of sync with on-disk metadata, mainly to speed up the
:ref:`update-cmd` (which needs to check whether the database is in sync with
the filesystem). This feature turns out to be sort of complicated.
:ref:`update-cmd` (which needs to check whether the database is in sync with the
filesystem). This feature turns out to be sort of complicated.
For any :class:`Item`, there are two mtimes: the on-disk mtime (maintained by
the OS) and the database mtime (maintained by beets). Correspondingly, there is
on-disk metadata (ID3 tags, for example) and DB metadata. The goal with the
mtime is to ensure that the on-disk and DB mtimes match when the on-disk and DB
metadata are in sync; this lets beets do a quick mtime check and avoid
rereading files in some circumstances.
metadata are in sync; this lets beets do a quick mtime check and avoid rereading
files in some circumstances.
Specifically, beets attempts to maintain the following invariant:
If the on-disk metadata differs from the DB metadata, then the on-disk
mtime must be greater than the DB mtime.
If the on-disk metadata differs from the DB metadata, then the on-disk mtime
must be greater than the DB mtime.
As a result, it is always valid for the DB mtime to be zero (assuming that real
disk mtimes are always positive). However, whenever possible, beets tries to
set ``db_mtime = disk_mtime`` at points where it knows the metadata is
synchronized. When it is possible that the metadata is out of sync, beets can
then just set ``db_mtime = 0`` to return to a consistent state.
disk mtimes are always positive). However, whenever possible, beets tries to set
``db_mtime = disk_mtime`` at points where it knows the metadata is synchronized.
When it is possible that the metadata is out of sync, beets can then just set
``db_mtime = 0`` to return to a consistent state.
This leads to the following implementation policy:
* On every write of disk metadata (``Item.write()``), the DB mtime is updated
to match the post-write disk mtime.
* Same for metadata reads (``Item.read()``).
* On every modification to DB metadata (``item.field = ...``), the DB mtime
is reset to zero.
- On every write of disk metadata (``Item.write()``), the DB mtime is
updated to match the post-write disk mtime.
- Same for metadata reads (``Item.read()``).
- On every modification to DB metadata (``item.field = ...``), the DB mtime
is reset to zero.
Album
'''''
~~~~~
An :class:`Album` is a collection of Items in the database. Every item in the
database has either zero or one associated albums (accessible via
``item.album_id``). An item that has no associated album is called a
singleton.
``item.album_id``). An item that has no associated album is called a singleton.
Changing fields on an album (e.g. ``album.year = 2012``) updates the album
itself and also changes the same field in all associated items.
An :class:`Album` object keeps track of album-level metadata, which is (mostly)
a subset of the track-level metadata. The album-level metadata fields are
listed in ``Album._fields``.
For those fields that are both item-level and album-level (e.g., ``year`` or
``albumartist``), every item in an album should share the same value. Albums
use an SQLite table called ``albums``, in which each column is an album
metadata field.
a subset of the track-level metadata. The album-level metadata fields are listed
in ``Album._fields``. For those fields that are both item-level and album-level
(e.g., ``year`` or ``albumartist``), every item in an album should share the
same value. Albums use an SQLite table called ``albums``, in which each column
is an album metadata field.
.. note::
The :py:meth:`Album.items` method is not inherited from
:py:meth:`LibModel.items` for historical reasons.
Transactions
''''''''''''
~~~~~~~~~~~~
The :class:`Library` class provides the basic methods necessary to access and
manipulate its contents. To perform more complicated operations atomically, or
@ -167,10 +162,9 @@ to interact directly with the underlying SQLite database, you must use a
.. currentmodule:: beets.dbcore.db
The :class:`Transaction` class is a context manager that provides a
transactional interface to the underlying SQLite database. It is
responsible for managing the transaction's lifecycle, including
beginning, committing, and rolling back the transaction if
an error occurs.
transactional interface to the underlying SQLite database. It is responsible for
managing the transaction's lifecycle, including beginning, committing, and
rolling back the transaction if an error occurs.
.. _blog post: https://beets.io/blog/sqlite-nightmare.html
@ -179,11 +173,11 @@ Queries
.. currentmodule:: beets.dbcore.query
To access albums and items in a library, we use :doc:`/reference/query`.
In beets, the :class:`Query` abstract base class represents a criterion that
matches items or albums in the database.
Every subclass of :class:`Query` must implement two methods, which implement
two different ways of identifying matching items/albums.
To access albums and items in a library, we use :doc:`/reference/query`. In
beets, the :class:`Query` abstract base class represents a criterion that
matches items or albums in the database. Every subclass of :class:`Query` must
implement two methods, which implement two different ways of identifying
matching items/albums.
The ``clause()`` method should return an SQLite ``WHERE`` clause that matches
appropriate albums/items. This allows for efficient batch queries.
@ -194,12 +188,10 @@ items that have already been fetched from the database match the query.
There are many different types of queries. Just as an example,
:class:`FieldQuery` determines whether a certain field matches a certain value
(an equality query).
:class:`AndQuery` (like its abstract superclass, :class:`CollectionQuery`)
takes a set of other query objects and bundles them together, matching only
albums/items that match all constituent queries.
(an equality query). :class:`AndQuery` (like its abstract superclass,
:class:`CollectionQuery`) takes a set of other query objects and bundles them
together, matching only albums/items that match all constituent queries.
Beets has a human-writable plain-text query syntax that can be parsed into
:class:`Query` objects. Calling ``AndQuery.from_strings`` parses a list of
query parts into a query object that can then be used with :class:`Library`
objects.
:class:`Query` objects. Calling ``AndQuery.from_strings`` parses a list of query
parts into a query object that can then be used with :class:`Library` objects.

View file

@ -5,7 +5,6 @@ Beets plugins are Python modules or packages that extend the core functionality
of beets. The plugin system is designed to be flexible, allowing developers to
add virtually any type of features.
.. _writing-plugins:
Writing Plugins
@ -14,12 +13,16 @@ Writing Plugins
A beets plugin is just a Python module or package inside the ``beetsplug``
namespace package. (Check out `this article`_ and `this Stack Overflow
question`_ if you haven't heard about namespace packages.) So, to make one,
create a directory called ``beetsplug`` and add either your plugin module::
create a directory called ``beetsplug`` and add either your plugin module:
::
beetsplug/
myawesomeplugin.py
or your plugin subpackage::
or your plugin subpackage:
::
beetsplug/
myawesomeplugin/
@ -30,8 +33,12 @@ or your plugin subpackage::
You do not anymore need to add a ``__init__.py`` file to the ``beetsplug``
directory. Python treats your plugin as a namespace package automatically,
thus we do not depend on ``pkgutil``-based setup in the ``__init__.py``
file anymore.
thus we do not depend on ``pkgutil``-based setup in the ``__init__.py`` file
anymore.
.. _this article: https://realpython.com/python-namespace-package/#setting-up-some-namespace-packages
.. _this stack overflow question: https://stackoverflow.com/a/27586272/9582674
The meat of your plugin goes in ``myawesomeplugin.py``. There, you'll have to
import ``BeetsPlugin`` from ``beets.plugins`` and subclass it, for example
@ -40,16 +47,21 @@ import ``BeetsPlugin`` from ``beets.plugins`` and subclass it, for example
from beets.plugins import BeetsPlugin
class MyAwesomePlugin(BeetsPlugin):
pass
Once you have your ``BeetsPlugin`` subclass, there's a variety of things your
plugin can do. (Read on!)
To use your new plugin, package your plugin (see how to do this with `poetry`_
or `setuptools`_, for example) and install it into your ``beets`` virtual
To use your new plugin, package your plugin (see how to do this with poetry_ or
setuptools_, for example) and install it into your ``beets`` virtual
environment. Then, add your plugin to beets configuration
.. _poetry: https://python-poetry.org/docs/pyproject/#packages
.. _setuptools: https://setuptools.pypa.io/en/latest/userguide/package_discovery.html#finding-simple-packages
.. code-block:: yaml
# config.yaml
@ -58,27 +70,24 @@ environment. Then, add your plugin to beets configuration
and you're good to go!
.. _this article: https://realpython.com/python-namespace-package/#setting-up-some-namespace-packages
.. _this Stack Overflow question: https://stackoverflow.com/a/27586272/9582674
.. _poetry: https://python-poetry.org/docs/pyproject/#packages
.. _setuptools: https://setuptools.pypa.io/en/latest/userguide/package_discovery.html#finding-simple-packages
.. _add_subcommands:
Add Commands to the CLI
^^^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~~~
Plugins can add new subcommands to the ``beet`` command-line interface. Define
the plugin class' ``commands()`` method to return a list of ``Subcommand``
objects. (The ``Subcommand`` class is defined in the ``beets.ui`` module.)
Here's an example plugin that adds a simple command::
Here's an example plugin that adds a simple command:
::
from beets.plugins import BeetsPlugin
from beets.ui import Subcommand
my_super_command = Subcommand('super', help='do something super')
def say_hi(lib, opts, args):
print "Hello everybody! I'm a plugin!"
print("Hello everybody! I'm a plugin!")
my_super_command.func = say_hi
class SuperPlug(BeetsPlugin):
@ -92,15 +101,14 @@ but it defaults to an empty parser (you can extend it later). ``help`` is a
description of your command, and ``aliases`` is a list of shorthand versions of
your command name.
.. _OptionParser instance: https://docs.python.org/library/optparse.html
.. _optionparser instance: https://docs.python.org/library/optparse.html
You'll need to add a function to your command by saying ``mycommand.func =
myfunction``. This function should take the following parameters: ``lib`` (a
beets ``Library`` object) and ``opts`` and ``args`` (command-line options and
arguments as returned by `OptionParser.parse_args`_).
arguments as returned by OptionParser.parse_args_).
.. _OptionParser.parse_args:
https://docs.python.org/library/optparse.html#parsing-arguments
.. _optionparser.parse_args: https://docs.python.org/library/optparse.html#parsing-arguments
The function should use any of the utility functions defined in ``beets.ui``.
Try running ``pydoc beets.ui`` to see what's available.
@ -115,15 +123,17 @@ and ``--format``. This feature is versatile and extensively documented, try
.. _plugin_events:
Listen for Events
^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~
Event handlers allow plugins to run code whenever something happens in beets'
operation. For instance, a plugin could write a log message every time an album
is successfully autotagged or update MPD's index whenever the database is
changed.
You can "listen" for events using ``BeetsPlugin.register_listener``. Here's
an example::
You can "listen" for events using ``BeetsPlugin.register_listener``. Here's an
example:
::
from beets.plugins import BeetsPlugin
@ -137,7 +147,9 @@ an example::
Note that if you want to access an attribute of your plugin (e.g. ``config`` or
``log``) you'll have to define a method and not a function. Here is the usual
registration process in this case::
registration process in this case:
::
from beets.plugins import BeetsPlugin
@ -151,139 +163,108 @@ registration process in this case::
The events currently available are:
* `pluginload`: called after all the plugins have been loaded after the ``beet``
command starts
* `import`: called after a ``beet import`` command finishes (the ``lib`` keyword
argument is a Library object; ``paths`` is a list of paths (strings) that were
imported)
* `album_imported`: called with an ``Album`` object every time the ``import``
- ``pluginload``: called after all the plugins have been loaded after the
``beet`` command starts
- ``import``: called after a ``beet import`` command finishes (the ``lib``
keyword argument is a Library object; ``paths`` is a list of paths (strings)
that were imported)
- ``album_imported``: called with an ``Album`` object every time the ``import``
command finishes adding an album to the library. Parameters: ``lib``,
``album``
* `album_removed`: called with an ``Album`` object every time an album is
- ``album_removed``: called with an ``Album`` object every time an album is
removed from the library (even when its file is not deleted from disk).
* `item_copied`: called with an ``Item`` object whenever its file is copied.
- ``item_copied``: called with an ``Item`` object whenever its file is copied.
Parameters: ``item``, ``source`` path, ``destination`` path
* `item_imported`: called with an ``Item`` object every time the importer adds a
singleton to the library (not called for full-album imports). Parameters:
- ``item_imported``: called with an ``Item`` object every time the importer adds
a singleton to the library (not called for full-album imports). Parameters:
``lib``, ``item``
* `before_item_moved`: called with an ``Item`` object immediately before its
- ``before_item_moved``: called with an ``Item`` object immediately before its
file is moved. Parameters: ``item``, ``source`` path, ``destination`` path
* `item_moved`: called with an ``Item`` object whenever its file is moved.
- ``item_moved``: called with an ``Item`` object whenever its file is moved.
Parameters: ``item``, ``source`` path, ``destination`` path
* `item_linked`: called with an ``Item`` object whenever a symlink is created
for a file.
Parameters: ``item``, ``source`` path, ``destination`` path
* `item_hardlinked`: called with an ``Item`` object whenever a hardlink is
created for a file.
Parameters: ``item``, ``source`` path, ``destination`` path
* `item_reflinked`: called with an ``Item`` object whenever a reflink is
created for a file.
Parameters: ``item``, ``source`` path, ``destination`` path
* `item_removed`: called with an ``Item`` object every time an item (singleton
- ``item_linked``: called with an ``Item`` object whenever a symlink is created
for a file. Parameters: ``item``, ``source`` path, ``destination`` path
- ``item_hardlinked``: called with an ``Item`` object whenever a hardlink is
created for a file. Parameters: ``item``, ``source`` path, ``destination``
path
- ``item_reflinked``: called with an ``Item`` object whenever a reflink is
created for a file. Parameters: ``item``, ``source`` path, ``destination``
path
- ``item_removed``: called with an ``Item`` object every time an item (singleton
or album's part) is removed from the library (even when its file is not
deleted from disk).
* `write`: called with an ``Item`` object, a ``path``, and a ``tags``
dictionary just before a file's metadata is written to disk (i.e.,
just before the file on disk is opened). Event handlers may change
the ``tags`` dictionary to customize the tags that are written to the
media file. Event handlers may also raise a
``library.FileOperationError`` exception to abort the write
operation. Beets will catch that exception, print an error message
and continue.
* `after_write`: called with an ``Item`` object after a file's metadata is
- ``write``: called with an ``Item`` object, a ``path``, and a ``tags``
dictionary just before a file's metadata is written to disk (i.e., just before
the file on disk is opened). Event handlers may change the ``tags`` dictionary
to customize the tags that are written to the media file. Event handlers may
also raise a ``library.FileOperationError`` exception to abort the write
operation. Beets will catch that exception, print an error message and
continue.
- ``after_write``: called with an ``Item`` object after a file's metadata is
written to disk (i.e., just after the file on disk is closed).
* `import_task_created`: called immediately after an import task is
- ``import_task_created``: called immediately after an import task is
initialized. Plugins can use this to, for example, change imported files of a
task before anything else happens. It's also possible to replace the task
with another task by returning a list of tasks. This list can contain zero
or more `ImportTask`s. Returning an empty list will stop the task.
Parameters: ``task`` (an `ImportTask`) and ``session`` (an `ImportSession`).
* `import_task_start`: called when before an import task begins processing.
task before anything else happens. It's also possible to replace the task with
another task by returning a list of tasks. This list can contain zero or more
``ImportTask``. Returning an empty list will stop the task. Parameters:
``task`` (an ``ImportTask``) and ``session`` (an ``ImportSession``).
- ``import_task_start``: called when before an import task begins processing.
Parameters: ``task`` and ``session``.
* `import_task_apply`: called after metadata changes have been applied in an
- ``import_task_apply``: called after metadata changes have been applied in an
import task. This is called on the same thread as the UI, so use this
sparingly and only for tasks that can be done quickly. For most plugins, an
import pipeline stage is a better choice (see :ref:`plugin-stage`).
Parameters: ``task`` and ``session``.
* `import_task_before_choice`: called after candidate search for an import task
before any decision is made about how/if to import or tag. Can be used to
- ``import_task_before_choice``: called after candidate search for an import
task before any decision is made about how/if to import or tag. Can be used to
present information about the task or initiate interaction with the user
before importing occurs. Return an importer action to take a specific action.
Only one handler may return a non-None result.
Parameters: ``task`` and ``session``
* `import_task_choice`: called after a decision has been made about an import
Only one handler may return a non-None result. Parameters: ``task`` and
``session``
- ``import_task_choice``: called after a decision has been made about an import
task. This event can be used to initiate further interaction with the user.
Use ``task.choice_flag`` to determine or change the action to be
taken. Parameters: ``task`` and ``session``.
* `import_task_files`: called after an import task finishes manipulating the
Use ``task.choice_flag`` to determine or change the action to be taken.
Parameters: ``task`` and ``session``.
- ``import_task_files``: called after an import task finishes manipulating the
filesystem (copying and moving files, writing metadata tags). Parameters:
``task`` and ``session``.
* `library_opened`: called after beets starts up and initializes the main
- ``library_opened``: called after beets starts up and initializes the main
Library object. Parameter: ``lib``.
* `database_change`: a modification has been made to the library database. The
- ``database_change``: a modification has been made to the library database. The
change might not be committed yet. Parameters: ``lib`` and ``model``.
* `cli_exit`: called just before the ``beet`` command-line program exits.
- ``cli_exit``: called just before the ``beet`` command-line program exits.
Parameter: ``lib``.
* `import_begin`: called just before a ``beet import`` session starts up.
- ``import_begin``: called just before a ``beet import`` session starts up.
Parameter: ``session``.
* `trackinfo_received`: called after metadata for a track item has been
fetched from a data source, such as MusicBrainz. You can modify the tags
that the rest of the pipeline sees on a ``beet import`` operation or during
later adjustments, such as ``mbsync``. Slow handlers of the event can impact
the operation, since the event is fired for any fetched possible match
`before` the user (or the autotagger machinery) gets to see the match.
Parameter: ``info``.
* `albuminfo_received`: like `trackinfo_received`, the event indicates new
metadata for album items. The parameter is an ``AlbumInfo`` object instead
of a ``TrackInfo``.
Parameter: ``info``.
* `before_choose_candidate`: called before the user is prompted for a decision
- ``trackinfo_received``: called after metadata for a track item has been
fetched from a data source, such as MusicBrainz. You can modify the tags that
the rest of the pipeline sees on a ``beet import`` operation or during later
adjustments, such as ``mbsync``. Slow handlers of the event can impact the
operation, since the event is fired for any fetched possible match ``before``
the user (or the autotagger machinery) gets to see the match. Parameter:
``info``.
- ``albuminfo_received``: like ``trackinfo_received``, the event indicates new
metadata for album items. The parameter is an ``AlbumInfo`` object instead of
a ``TrackInfo``. Parameter: ``info``.
- ``before_choose_candidate``: called before the user is prompted for a decision
during a ``beet import`` interactive session. Plugins can use this event for
:ref:`appending choices to the prompt <append_prompt_choices>` by returning a
list of ``PromptChoices``. Parameters: ``task`` and ``session``.
* `mb_track_extract`: called after the metadata is obtained from
MusicBrainz. The parameter is a ``dict`` containing the tags retrieved from
MusicBrainz for a track. Plugins must return a new (potentially empty)
``dict`` with additional ``field: value`` pairs, which the autotagger will
apply to the item, as flexible attributes if ``field`` is not a hardcoded
field. Fields already present on the track are overwritten.
- ``mb_track_extract``: called after the metadata is obtained from MusicBrainz.
The parameter is a ``dict`` containing the tags retrieved from MusicBrainz for
a track. Plugins must return a new (potentially empty) ``dict`` with
additional ``field: value`` pairs, which the autotagger will apply to the
item, as flexible attributes if ``field`` is not a hardcoded field. Fields
already present on the track are overwritten. Parameter: ``data``
- ``mb_album_extract``: Like ``mb_track_extract``, but for album tags.
Overwrites tags set at the track level, if they have the same ``field``.
Parameter: ``data``
* `mb_album_extract`: Like `mb_track_extract`, but for album tags. Overwrites
tags set at the track level, if they have the same ``field``.
Parameter: ``data``
The included ``mpdupdate`` plugin provides an example use case for event listeners.
The included ``mpdupdate`` plugin provides an example use case for event
listeners.
Extend the Autotagger
^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~
Plugins can also enhance the functionality of the autotagger. For a
comprehensive example, try looking at the ``chroma`` plugin, which is included
@ -296,79 +277,79 @@ levels; the initial search controls which candidates are presented to the
matching algorithm. Plugins implement these extensions by implementing four
methods on the plugin class:
* ``track_distance(self, item, info)``: adds a component to the distance
- ``track_distance(self, item, info)``: adds a component to the distance
function (i.e., the similarity metric) for individual tracks. ``item`` is the
track to be matched (an Item object) and ``info`` is the TrackInfo object
that is proposed as a match. Should return a ``(dist, dist_max)`` pair
of floats indicating the distance.
* ``album_distance(self, items, album_info, mapping)``: like the above, but
track to be matched (an Item object) and ``info`` is the TrackInfo object that
is proposed as a match. Should return a ``(dist, dist_max)`` pair of floats
indicating the distance.
- ``album_distance(self, items, album_info, mapping)``: like the above, but
compares a list of items (representing an album) to an album-level MusicBrainz
entry. ``items`` is a list of Item objects; ``album_info`` is an AlbumInfo
object; and ``mapping`` is a dictionary that maps Items to their corresponding
TrackInfo objects.
* ``candidates(self, items, artist, album, va_likely)``: given a list of items
- ``candidates(self, items, artist, album, va_likely)``: given a list of items
comprised by an album to be matched, return a list of ``AlbumInfo`` objects
for candidate albums to be compared and matched.
* ``item_candidates(self, item, artist, album)``: given a *singleton* item,
- ``item_candidates(self, item, artist, album)``: given a *singleton* item,
return a list of ``TrackInfo`` objects for candidate tracks to be compared and
matched.
* ``album_for_id(self, album_id)``: given an ID from user input or an album's
- ``album_for_id(self, album_id)``: given an ID from user input or an album's
tags, return a candidate AlbumInfo object (or None).
* ``track_for_id(self, track_id)``: given an ID from user input or a file's
- ``track_for_id(self, track_id)``: given an ID from user input or a file's
tags, return a candidate TrackInfo object (or None).
When implementing these functions, you may want to use the functions from the
``beets.autotag`` and ``beets.autotag.mb`` modules, both of which have
somewhat helpful docstrings.
``beets.autotag`` and ``beets.autotag.mb`` modules, both of which have somewhat
helpful docstrings.
Read Configuration Options
^^^^^^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~~~~~~
Plugins can configure themselves using the ``config.yaml`` file. You can read
configuration values in two ways. The first is to use `self.config` within
configuration values in two ways. The first is to use ``self.config`` within
your plugin class. This gives you a view onto the configuration values in a
section with the same name as your plugin's module. For example, if your plugin
is in ``greatplugin.py``, then `self.config` will refer to options under the
is in ``greatplugin.py``, then ``self.config`` will refer to options under the
``greatplugin:`` section of the config file.
For example, if you have a configuration value called "foo", then users can put
this in their ``config.yaml``::
this in their ``config.yaml``:
::
greatplugin:
foo: bar
To access this value, say ``self.config['foo'].get()`` at any point in your
plugin's code. The `self.config` object is a *view* as defined by the `Confuse`_
plugin's code. The ``self.config`` object is a *view* as defined by the Confuse_
library.
.. _Confuse: https://confuse.readthedocs.io/en/latest/
.. _confuse: https://confuse.readthedocs.io/en/latest/
If you want to access configuration values *outside* of your plugin's section,
import the `config` object from the `beets` module. That is, just put ``from
import the ``config`` object from the ``beets`` module. That is, just put ``from
beets import config`` at the top of your plugin and access values from there.
If your plugin provides configuration values for sensitive data (e.g.,
passwords, API keys, ...), you should add these to the config so they can be
redacted automatically when users dump their config. This can be done by
setting each value's `redact` flag, like so::
redacted automatically when users dump their config. This can be done by setting
each value's ``redact`` flag, like so:
::
self.config['password'].redact = True
Add Path Format Functions and Fields
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Beets supports *function calls* in its path format syntax (see
:doc:`/reference/pathformat`). Beets includes a few built-in functions, but
plugins can register new functions by adding them to the ``template_funcs``
dictionary.
Here's an example::
Here's an example:
::
class MyPlugin(BeetsPlugin):
def __init__(self):
@ -385,10 +366,12 @@ This plugin provides a function ``%initial`` to path templates where
``%initial{$artist}`` expands to the artist's initial (its capitalized first
character).
Plugins can also add template *fields*, which are computed values referenced
as ``$name`` in templates. To add a new field, add a function that takes an
Plugins can also add template *fields*, which are computed values referenced as
``$name`` in templates. To add a new field, add a function that takes an
``Item`` object to the ``template_fields`` dictionary on the plugin object.
Here's an example that adds a ``$disc_and_track`` field::
Here's an example that adds a ``$disc_and_track`` field:
::
class MyPlugin(BeetsPlugin):
def __init__(self):
@ -413,20 +396,21 @@ template fields by adding a function accepting an ``Album`` argument to the
``album_template_fields`` dict.
Extend MediaFile
^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~
`MediaFile`_ is the file tag abstraction layer that beets uses to make
MediaFile_ is the file tag abstraction layer that beets uses to make
cross-format metadata manipulation simple. Plugins can add fields to MediaFile
to extend the kinds of metadata that they can easily manage.
The ``MediaFile`` class uses ``MediaField`` descriptors to provide
access to file tags. If you have created a descriptor you can add it through
your plugins :py:meth:`beets.plugins.BeetsPlugin.add_media_field()`` method.
The ``MediaFile`` class uses ``MediaField`` descriptors to provide access to
file tags. If you have created a descriptor you can add it through your plugins
:py:meth:`beets.plugins.BeetsPlugin.add_media_field()` method.
.. _MediaFile: https://mediafile.readthedocs.io/en/latest/
.. _mediafile: https://mediafile.readthedocs.io/en/latest/
Here's an example plugin that provides a meaningless new field "foo":
Here's an example plugin that provides a meaningless new field "foo"::
::
class FooPlugin(BeetsPlugin):
def __init__(self):
@ -444,11 +428,10 @@ Here's an example plugin that provides a meaningless new field "foo"::
item.write()
# The "foo" tag of the file is now "ham"
.. _plugin-stage:
Add Import Pipeline Stages
^^^^^^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~~~~~~
Many plugins need to add high-latency operations to the import workflow. For
example, a plugin that fetches lyrics from the Web would, ideally, not block the
@ -462,9 +445,11 @@ Multiple stages run in parallel but each stage processes only one task at a time
and each task is processed by only one stage at a time.
Plugins provide stages as functions that take two arguments: ``config`` and
``task``, which are ``ImportSession`` and ``ImportTask`` objects (both defined in
``beets.importer``). Add such a function to the plugin's ``import_stages`` field
to register it::
``task``, which are ``ImportSession`` and ``ImportTask`` objects (both defined
in ``beets.importer``). Add such a function to the plugin's ``import_stages``
field to register it:
::
from beets.plugins import BeetsPlugin
class ExamplePlugin(BeetsPlugin):
@ -475,14 +460,16 @@ to register it::
print('Importing something!')
It is also possible to request your function to run early in the pipeline by
adding the function to the plugin's ``early_import_stages`` field instead::
adding the function to the plugin's ``early_import_stages`` field instead:
::
self.early_import_stages = [self.stage]
.. _extend-query:
Extend the Query Syntax
^^^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~~~
You can add new kinds of queries to beets' :doc:`query syntax
</reference/query>`. There are two ways to add custom queries: using a prefix
@ -491,24 +478,25 @@ named queries are not associated with any field. For example, beets already
supports regular expression queries, which are indicated by a colon
prefix---plugins can do the same.
For either kind of query extension, define a subclass of the ``Query`` type
from the ``beets.dbcore.query`` module. Then:
For either kind of query extension, define a subclass of the ``Query`` type from
the ``beets.dbcore.query`` module. Then:
- To define a prefix-based query, define a ``queries`` method in your plugin
class. Return from this method a dictionary mapping prefix strings to query
classes.
- To define a named query, defined dictionaries named either ``item_queries``
or ``album_queries``. These should map names to query types. So if you
use ``{ "foo": FooQuery }``, then the query ``foo:bar`` will construct a
query like ``FooQuery("bar")``.
- To define a named query, defined dictionaries named either ``item_queries`` or
``album_queries``. These should map names to query types. So if you use ``{
"foo": FooQuery }``, then the query ``foo:bar`` will construct a query like
``FooQuery("bar")``.
For prefix-based queries, you will want to extend ``FieldQuery``, which
implements string comparisons on fields. To use it, create a subclass
inheriting from that class and override the ``value_match`` class method.
(Remember the ``@classmethod`` decorator!) The following example plugin
declares a query using the ``@`` prefix to delimit exact string matches. The
plugin will be used if we issue a command like ``beet ls @something`` or
``beet ls artist:@something``::
implements string comparisons on fields. To use it, create a subclass inheriting
from that class and override the ``value_match`` class method. (Remember the
``@classmethod`` decorator!) The following example plugin declares a query using
the ``@`` prefix to delimit exact string matches. The plugin will be used if we
issue a command like ``beet ls @something`` or ``beet ls artist:@something``:
::
from beets.plugins import BeetsPlugin
from beets.dbcore import FieldQuery
@ -524,14 +512,14 @@ plugin will be used if we issue a command like ``beet ls @something`` or
'@': ExactMatchQuery
}
Flexible Field Types
^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~
If your plugin uses flexible fields to store numbers or other
non-string values, you can specify the types of those fields. A rating
plugin, for example, might want to declare that the ``rating`` field
should have an integer type::
If your plugin uses flexible fields to store numbers or other non-string values,
you can specify the types of those fields. A rating plugin, for example, might
want to declare that the ``rating`` field should have an integer type:
::
from beets.plugins import BeetsPlugin
from beets.dbcore import types
@ -543,73 +531,74 @@ should have an integer type::
def album_types(self):
return {'rating': types.INTEGER}
A plugin may define two attributes: `item_types` and `album_types`.
Each of those attributes is a dictionary mapping a flexible field name
to a type instance. You can find the built-in types in the
`beets.dbcore.types` and `beets.library` modules or implement your own
type by inheriting from the `Type` class.
A plugin may define two attributes: ``item_types`` and ``album_types``. Each of
those attributes is a dictionary mapping a flexible field name to a type
instance. You can find the built-in types in the ``beets.dbcore.types`` and
``beets.library`` modules or implement your own type by inheriting from the
``Type`` class.
Specifying types has several advantages:
* Code that accesses the field like ``item['my_field']`` gets the right
type (instead of just a string).
* You can use advanced queries (like :ref:`ranges <numericquery>`)
from the command line.
* User input for flexible fields may be validated and converted.
* Items missing the given field can use an appropriate null value for
querying and sorting purposes.
- Code that accesses the field like ``item['my_field']`` gets the right type
(instead of just a string).
- You can use advanced queries (like :ref:`ranges <numericquery>`) from the
command line.
- User input for flexible fields may be validated and converted.
- Items missing the given field can use an appropriate null value for querying
and sorting purposes.
.. _plugin-logging:
Logging
^^^^^^^
~~~~~~~
Each plugin object has a ``_log`` attribute, which is a ``Logger`` from the
`standard Python logging module`_. The logger is set up to `PEP 3101`_,
str.format-style string formatting. So you can write logging calls like this::
str.format-style string formatting. So you can write logging calls like this:
::
self._log.debug(u'Processing {0.title} by {0.artist}', item)
.. _PEP 3101: https://www.python.org/dev/peps/pep-3101/
.. _standard Python logging module: https://docs.python.org/2/library/logging.html
.. _pep 3101: https://www.python.org/dev/peps/pep-3101/
When beets is in verbose mode, plugin messages are prefixed with the plugin
name to make them easier to see.
.. _standard python logging module: https://docs.python.org/2/library/logging.html
When beets is in verbose mode, plugin messages are prefixed with the plugin name
to make them easier to see.
Which messages will be logged depends on the logging level and the action
performed:
* Inside import stages and event handlers, the default is ``WARNING`` messages
- Inside import stages and event handlers, the default is ``WARNING`` messages
and above.
* Everywhere else, the default is ``INFO`` or above.
- Everywhere else, the default is ``INFO`` or above.
The verbosity can be increased with ``--verbose`` (``-v``) flags: each flags
lowers the level by a notch. That means that, with a single ``-v`` flag, event
handlers won't have their ``DEBUG`` messages displayed, but command functions
(for example) will. With ``-vv`` on the command line, ``DEBUG`` messages will
be displayed everywhere.
(for example) will. With ``-vv`` on the command line, ``DEBUG`` messages will be
displayed everywhere.
This addresses a common pattern where plugins need to use the same code for a
command and an import stage, but the command needs to print more messages than
the import stage. (For example, you'll want to log "found lyrics for this song"
when you're run explicitly as a command, but you don't want to noisily
interrupt the importer interface when running automatically.)
when you're run explicitly as a command, but you don't want to noisily interrupt
the importer interface when running automatically.)
.. _append_prompt_choices:
Append Prompt Choices
^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~
Plugins can also append choices to the prompt presented to the user during
an import session.
Plugins can also append choices to the prompt presented to the user during an
import session.
To do so, add a listener for the ``before_choose_candidate`` event, and return
a list of ``PromptChoices`` that represent the additional choices that your
plugin shall expose to the user::
To do so, add a listener for the ``before_choose_candidate`` event, and return a
list of ``PromptChoices`` that represent the additional choices that your plugin
shall expose to the user:
::
from beets.plugins import BeetsPlugin
from beets.ui.commands import PromptChoice
@ -630,31 +619,35 @@ plugin shall expose to the user::
def bar(self, session, task):
print('User has chosen "Do bar"!')
The previous example modifies the standard prompt::
The previous example modifies the standard prompt:
::
# selection (default 1), Skip, Use as-is, as Tracks, Group albums,
Enter search, enter Id, aBort?
by appending two additional options (``Print foo`` and ``Do bar``)::
by appending two additional options (``Print foo`` and ``Do bar``):
::
# selection (default 1), Skip, Use as-is, as Tracks, Group albums,
Enter search, enter Id, aBort, Print foo, Do bar?
If the user selects a choice, the ``callback`` attribute of the corresponding
``PromptChoice`` will be called. It is the responsibility of the plugin to
check for the status of the import session and decide the choices to be
appended: for example, if a particular choice should only be presented if the
album has no candidates, the relevant checks against ``task.candidates`` should
be performed inside the plugin's ``before_choose_candidate_event`` accordingly.
``PromptChoice`` will be called. It is the responsibility of the plugin to check
for the status of the import session and decide the choices to be appended: for
example, if a particular choice should only be presented if the album has no
candidates, the relevant checks against ``task.candidates`` should be performed
inside the plugin's ``before_choose_candidate_event`` accordingly.
Please make sure that the short letter for each of the choices provided by the
plugin is not already in use: the importer will emit a warning and discard
all but one of the choices using the same letter, giving priority to the
core importer prompt choices. As a reference, the following characters are used
by the choices on the core importer prompt, and hence should not be used:
``a``, ``s``, ``u``, ``t``, ``g``, ``e``, ``i``, ``b``.
plugin is not already in use: the importer will emit a warning and discard all
but one of the choices using the same letter, giving priority to the core
importer prompt choices. As a reference, the following characters are used by
the choices on the core importer prompt, and hence should not be used: ``a``,
``s``, ``u``, ``t``, ``g``, ``e``, ``i``, ``b``.
Additionally, the callback function can optionally specify the next action to
be performed by returning a ``importer.Action`` value. It may also return a
Additionally, the callback function can optionally specify the next action to be
performed by returning a ``importer.Action`` value. It may also return a
``autotag.Proposal`` value to update the set of current proposals to be
considered.

View file

@ -1,57 +1,56 @@
FAQ
###
===
Here are some answers to frequently-asked questions from IRC and elsewhere.
Got a question that isn't answered here? Try the `discussion board`_, or
Here are some answers to frequently-asked questions from IRC and elsewhere. Got
a question that isn't answered here? Try the `discussion board`_, or
:ref:`filing an issue <bugs>` in the bug tracker.
.. _mailing list: https://groups.google.com/group/beets-users
.. _discussion board: https://github.com/beetbox/beets/discussions/
.. _mailing list: https://groups.google.com/group/beets-users
.. contents::
:local:
:depth: 2
How do I…
=========
---------
.. _move:
…rename my files according to a new path format configuration?
--------------------------------------------------------------
Just run the :ref:`move-cmd` command. Use a :doc:`query </reference/query>`
to rename a subset of your music or leave the query off to rename
everything.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Just run the :ref:`move-cmd` command. Use a :doc:`query </reference/query>` to
rename a subset of your music or leave the query off to rename everything.
.. _asispostfacto:
…find all the albums I imported "as-is"?
----------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Enable the :ref:`import log <import_log>`
to automatically record whenever you skip an album or accept one
"as-is".
Enable the :ref:`import log <import_log>` to automatically record whenever you
skip an album or accept one "as-is".
Alternatively, you can find all the albums in your library that are
missing MBIDs using a command like this::
Alternatively, you can find all the albums in your library that are missing
MBIDs using a command like this:
::
beet ls -a mb_albumid::^$
Assuming your files didn't have MBIDs already, then this will roughly
correspond to those albums that didn't get autotagged.
Assuming your files didn't have MBIDs already, then this will roughly correspond
to those albums that didn't get autotagged.
.. _discdir:
…create "Disc N" directories for multi-disc albums?
---------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use the :doc:`/plugins/inline` along
with the ``%if{}`` function to accomplish this::
Use the :doc:`/plugins/inline` along with the ``%if{}`` function to accomplish
this:
::
plugins: inline
paths:
@ -59,344 +58,313 @@ with the ``%if{}`` function to accomplish this::
item_fields:
multidisc: 1 if disctotal > 1 else 0
This ``paths`` configuration only contains the
``default`` key: it leaves the ``comp`` and ``singleton`` keys as their
default values, as documented in :ref:`path-format-config`.
To create "Disc N" directories for compilations and singletons, you will need
to specify similar templates for those keys as well.
This ``paths`` configuration only contains the ``default`` key: it leaves the
``comp`` and ``singleton`` keys as their default values, as documented in
:ref:`path-format-config`. To create "Disc N" directories for compilations and
singletons, you will need to specify similar templates for those keys as well.
.. _multidisc:
…import a multi-disc album?
---------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~
As of 1.0b11, beets tags multi-disc albums as a *single unit*. To get a
good match, it needs to treat all of the album's parts together as a
single release.
As of 1.0b11, beets tags multi-disc albums as a *single unit*. To get a good
match, it needs to treat all of the album's parts together as a single release.
To help with this, the importer uses a simple heuristic to guess when a
directory represents a multi-disc album that's been divided into
multiple subdirectories. When it finds a situation like this, it
collapses all of the items in the subdirectories into a single release
for tagging.
directory represents a multi-disc album that's been divided into multiple
subdirectories. When it finds a situation like this, it collapses all of the
items in the subdirectories into a single release for tagging.
The heuristic works by looking at the names of directories. If multiple
subdirectories of a common parent directory follow the pattern "(title)
disc (number) (...)" and the *prefix* (everything up to the number) is
the same, the directories are collapsed together. One of the key words
"disc" or "CD" must be present to make this work.
If you have trouble tagging a multi-disc album, consider the ``--flat``
flag (which treats a whole tree as a single album) or just putting all
the tracks into a single directory to force them to be tagged together.
subdirectories of a common parent directory follow the pattern "(title) disc
(number) (...)" and the *prefix* (everything up to the number) is the same, the
directories are collapsed together. One of the key words "disc" or "CD" must be
present to make this work.
If you have trouble tagging a multi-disc album, consider the ``--flat`` flag
(which treats a whole tree as a single album) or just putting all the tracks
into a single directory to force them to be tagged together.
.. _mbid:
…enter a MusicBrainz ID?
------------------------
~~~~~~~~~~~~~~~~~~~~~~~~
An MBID looks like one of these:
- ``https://musicbrainz.org/release/ded77dcf-7279-457e-955d-625bd3801b87``
- ``d569deba-8c6b-4d08-8c43-d0e5a1b8c7f3``
- ``https://musicbrainz.org/release/ded77dcf-7279-457e-955d-625bd3801b87``
- ``d569deba-8c6b-4d08-8c43-d0e5a1b8c7f3``
Beets can recognize either the hex-with-dashes UUID-style string or the
full URL that contains it (as of 1.0b11).
Beets can recognize either the hex-with-dashes UUID-style string or the full URL
that contains it (as of 1.0b11).
You can get these IDs by `searching on the MusicBrainz web
site <https://musicbrainz.org/>`__ and going to a *release* page (when
tagging full albums) or a *recording* page (when tagging singletons).
Then, copy the URL of the page and paste it into beets.
Note that MusicBrainz has both "releases" and "release groups," which
link together different versions of the same album. Use *release* IDs
here.
You can get these IDs by `searching on the MusicBrainz web site
<https://musicbrainz.org/>`__ and going to a *release* page (when tagging full
albums) or a *recording* page (when tagging singletons). Then, copy the URL of
the page and paste it into beets.
Note that MusicBrainz has both "releases" and "release groups," which link
together different versions of the same album. Use *release* IDs here.
.. _upgrade:
…upgrade to the latest version of beets?
----------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run a command like this::
Run a command like this:
::
pip install -U beets
The ``-U`` flag tells `pip`_ to upgrade
beets to the latest version. If you want a specific version, you can
specify with using ``==`` like so::
The ``-U`` flag tells pip_ to upgrade beets to the latest version. If you want a
specific version, you can specify with using ``==`` like so:
::
pip install beets==1.0rc2
.. _src:
…run the latest source version of beets?
----------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Beets sees regular releases (about every six weeks or so), but sometimes
it's helpful to run on the "bleeding edge". To run the latest source:
Beets sees regular releases (about every six weeks or so), but sometimes it's
helpful to run on the "bleeding edge". To run the latest source:
1. Uninstall beets. If you installed using ``pip``, you can just run
``pip uninstall beets``.
1. Uninstall beets. If you installed using ``pip``, you can just run ``pip
uninstall beets``.
2. Install from source. Choose one of these methods:
- Directly from GitHub using
``python -m pip install git+https://github.com/beetbox/beets.git``
command. Depending on your system, you may need to use ``pip3``
and ``python3`` instead of ``pip`` and ``python`` respectively.
- Use ``pip`` to install the latest snapshot tarball. Type:
``pip install https://github.com/beetbox/beets/tarball/master``
- Use ``pip`` to install an "editable" version of beets based on an
automatic source checkout. For example, run
``pip install -e git+https://github.com/beetbox/beets#egg=beets``
to clone beets and install it, allowing you to modify the source
in-place to try out changes.
- Clone source code and install it in editable mode
- Directly from GitHub using ``python -m pip install
git+https://github.com/beetbox/beets.git`` command. Depending on your
system, you may need to use ``pip3`` and ``python3`` instead of ``pip`` and
``python`` respectively.
- Use ``pip`` to install the latest snapshot tarball. Type: ``pip install
https://github.com/beetbox/beets/tarball/master``
- Use ``pip`` to install an "editable" version of beets based on an automatic
source checkout. For example, run ``pip install -e
git+https://github.com/beetbox/beets#egg=beets`` to clone beets and install
it, allowing you to modify the source in-place to try out changes.
- Clone source code and install it in editable mode
.. code-block:: shell
.. code-block:: shell
git clone https://github.com/beetbox/beets.git
poetry install
This approach lets you decide where the
source is stored, with any changes immediately reflected in your
environment.
More details about the beets source are available on the :doc:`developer documentation </dev/index>`
pages.
This approach lets you decide where the source is stored, with any changes
immediately reflected in your environment.
More details about the beets source are available on the :doc:`developer
documentation </dev/index>` pages.
.. _bugs:
…report a bug in beets?
-----------------------
~~~~~~~~~~~~~~~~~~~~~~~
We use the `issue tracker`_ on GitHub where you can `open a new ticket`_.
Please follow these guidelines when reporting an issue:
We use the `issue tracker`_ on GitHub where you can `open a new ticket`_. Please
follow these guidelines when reporting an issue:
- Most importantly: if beets is crashing, please `include the
traceback <https://imgur.com/jacoj>`__. Tracebacks can be more
readable if you put them in a pastebin (e.g.,
`Gist <https://gist.github.com/>`__ or
`Hastebin <https://hastebin.com/>`__), especially when communicating
over IRC or email.
- Turn on beets' debug output (using the -v option: for example,
``beet -v import ...``) and include that with your bug report. Look
through this verbose output for any red flags that might point to the
problem.
- If you can, try installing the latest beets source code to see if the
bug is fixed in an unreleased version. You can also look at the
:doc:`latest changelog entries </changelog>`
for descriptions of the problem you're seeing.
- Try to narrow your problem down to something specific. Is a
particular plugin causing the problem? (You can disable plugins to
see whether the problem goes away.) Is a some music file or a single
album leading to the crash? (Try importing individual albums to
determine which one is causing the problem.) Is some entry in your
configuration file causing it? Et cetera.
- If you do narrow the problem down to a particular audio file or
album, include it with your bug report so the developers can run
tests.
If you've never reported a bug before, Mozilla has some well-written
`general guidelines for good bug
reports`_.
.. _issue tracker: https://github.com/beetbox/beets/issues
.. _general guidelines for good bug reports: https://developer.mozilla.org/en-US/docs/Mozilla/QA/Bug_writing_guidelines
- Most importantly: if beets is crashing, please `include the traceback
<https://imgur.com/jacoj>`__. Tracebacks can be more readable if you put them
in a pastebin (e.g., `Gist <https://gist.github.com/>`__ or `Hastebin
<https://hastebin.com/>`__), especially when communicating over IRC or email.
- Turn on beets' debug output (using the -v option: for example, ``beet -v
import ...``) and include that with your bug report. Look through this verbose
output for any red flags that might point to the problem.
- If you can, try installing the latest beets source code to see if the bug is
fixed in an unreleased version. You can also look at the :doc:`latest
changelog entries </changelog>` for descriptions of the problem you're seeing.
- Try to narrow your problem down to something specific. Is a particular plugin
causing the problem? (You can disable plugins to see whether the problem goes
away.) Is a some music file or a single album leading to the crash? (Try
importing individual albums to determine which one is causing the problem.) Is
some entry in your configuration file causing it? Et cetera.
- If you do narrow the problem down to a particular audio file or album, include
it with your bug report so the developers can run tests.
If you've never reported a bug before, Mozilla has some well-written `general
guidelines for good bug reports`_.
.. _find-config:
.. _general guidelines for good bug reports: https://developer.mozilla.org/en-US/docs/Mozilla/QA/Bug_writing_guidelines
.. _issue tracker: https://github.com/beetbox/beets/issues
…find the configuration file (config.yaml)?
-------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You create this file yourself; beets just reads it. See
:doc:`/reference/config`.
.. _special-chars:
…avoid using special characters in my filenames?
------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use the ``%asciify{}`` function in your path formats. See
:ref:`template-functions`.
.. _move-dir:
…point beets at a new music directory?
--------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to move your music from one directory to another, the best way is
to let beets do it for you. First, edit your configuration and set the
If you want to move your music from one directory to another, the best way is to
let beets do it for you. First, edit your configuration and set the
``directory`` setting to the new place. Then, type ``beet move`` to have beets
move all your files.
If you've already moved your music *outside* of beets, you have a few options:
- Move the music back (with an ordinary ``mv``) and then use the above steps.
- Delete your database and re-create it from the new paths using ``beet import -AWC``.
- Delete your database and re-create it from the new paths using ``beet import
-AWC``.
- Resort to manually modifying the SQLite database (not recommended).
Why does beets…
===============
---------------
.. _nomatch:
…complain that it can't find a match?
-------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are a number of possibilities:
- First, make sure the album is in `the MusicBrainz
database <https://musicbrainz.org/>`__. You
can search on their site to make sure it's cataloged there. (If not,
anyone can edit MusicBrainz---so consider adding the data yourself.)
- If the album in question is a multi-disc release, see the relevant
FAQ answer above.
- The music files' metadata might be insufficient. Try using the "enter
search" or "enter ID" options to help the matching process find the
right MusicBrainz entry.
- If you have a lot of files that are missing metadata, consider using
:doc:`acoustic fingerprinting </plugins/chroma>` or
:doc:`filename-based guesses </plugins/fromfilename>`
for that music.
If none of these situations apply and you're still having trouble
tagging something, please :ref:`file a bug report <bugs>`.
- First, make sure the album is in `the MusicBrainz database
<https://musicbrainz.org/>`__. You can search on their site to make sure it's
cataloged there. (If not, anyone can edit MusicBrainz---so consider adding the
data yourself.)
- If the album in question is a multi-disc release, see the relevant FAQ answer
above.
- The music files' metadata might be insufficient. Try using the "enter search"
or "enter ID" options to help the matching process find the right MusicBrainz
entry.
- If you have a lot of files that are missing metadata, consider using
:doc:`acoustic fingerprinting </plugins/chroma>` or :doc:`filename-based
guesses </plugins/fromfilename>` for that music.
If none of these situations apply and you're still having trouble tagging
something, please :ref:`file a bug report <bugs>`.
.. _plugins:
…appear to be missing some plugins?
-----------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Please make sure you're using the latest version of beets---you might
be using a version earlier than the one that introduced the plugin. In
many cases, the plugin may be introduced in beets "trunk" (the latest
source version) and might not be released yet. Take a look at :doc:`the
changelog </changelog>`
to see which version added the plugin. (You can type ``beet version`` to
check which version of beets you have installed.)
Please make sure you're using the latest version of beets---you might be using a
version earlier than the one that introduced the plugin. In many cases, the
plugin may be introduced in beets "trunk" (the latest source version) and might
not be released yet. Take a look at :doc:`the changelog </changelog>` to see
which version added the plugin. (You can type ``beet version`` to check which
version of beets you have installed.)
If you want to live on the bleeding edge and use the latest source
version of beets, you can check out the source (see :ref:`the relevant
question <src>`).
To see the beets documentation for your version (and avoid confusion
with new features in trunk), select your version from the menu in the sidebar.
If you want to live on the bleeding edge and use the latest source version of
beets, you can check out the source (see :ref:`the relevant question <src>`).
To see the beets documentation for your version (and avoid confusion with new
features in trunk), select your version from the menu in the sidebar.
.. _kill:
…ignore control-C during an import?
-----------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Typing a ^C (control-C) control sequence will not halt beets'
multithreaded importer while it is waiting at a prompt for user input.
Instead, hit "return" (dismissing the prompt) after typing ^C.
Alternatively, just type a "b" for "aBort" at most prompts. Typing ^C
*will* work if the importer interface is between prompts.
Typing a ^C (control-C) control sequence will not halt beets' multithreaded
importer while it is waiting at a prompt for user input. Instead, hit "return"
(dismissing the prompt) after typing ^C. Alternatively, just type a "b" for
"aBort" at most prompts. Typing ^C *will* work if the importer interface is
between prompts.
Also note that beets may take some time to quit after ^C is typed; it
tries to clean up after itself briefly even when canceled.
(For developers: this is because the UI thread is blocking on
``input`` and cannot be interrupted by the main thread, which is
trying to close all pipeline stages in the exception handler by setting
a flag. There is no simple way to remedy this.)
Also note that beets may take some time to quit after ^C is typed; it tries to
clean up after itself briefly even when canceled.
(For developers: this is because the UI thread is blocking on ``input`` and
cannot be interrupted by the main thread, which is trying to close all pipeline
stages in the exception handler by setting a flag. There is no simple way to
remedy this.)
.. _id3v24:
…not change my ID3 tags?
------------------------
~~~~~~~~~~~~~~~~~~~~~~~~
Beets writes `ID3v2.4`_ tags by default.
Some software, including Windows (i.e., Windows Explorer and Windows
Media Player) and `id3lib/id3v2 <http://id3v2.sourceforge.net/>`__,
don't support v2.4 tags. When using 2.4-unaware software, it might look
like the tags are unmodified or missing completely.
Beets writes ID3v2.4_ tags by default. Some software, including Windows (i.e.,
Windows Explorer and Windows Media Player) and `id3lib/id3v2
<http://id3v2.sourceforge.net/>`__, don't support v2.4 tags. When using
2.4-unaware software, it might look like the tags are unmodified or missing
completely.
To enable ID3v2.3 tags, enable the :ref:`id3v23` config option.
.. _id3v2.4: https://id3.org/id3v2.4.0-structure
.. _invalid:
.. _ID3v2.4: https://id3.org/id3v2.4.0-structure
…complain that a file is "unreadable"?
--------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Beets will log a message like "unreadable file: /path/to/music.mp3" when
it encounters files that *look* like music files (according to their
extension) but seem to be broken. Most of the time, this is because the
file is corrupted. To check whether the file is intact, try opening it
in another media player (e.g.,
`VLC <https://www.videolan.org/vlc/index.html>`__) to see whether it can
read the file. You can also use specialized programs for checking file
integrity---for example, type ``metaflac --list music.flac`` to check
FLAC files.
Beets will log a message like "unreadable file: /path/to/music.mp3" when it
encounters files that *look* like music files (according to their extension) but
seem to be broken. Most of the time, this is because the file is corrupted. To
check whether the file is intact, try opening it in another media player (e.g.,
`VLC <https://www.videolan.org/vlc/index.html>`__) to see whether it can read
the file. You can also use specialized programs for checking file
integrity---for example, type ``metaflac --list music.flac`` to check FLAC
files.
If beets still complains about a file that seems to be valid, `open a new
ticket`_ and we'll look into it. There's always a possibility that there's
a bug "upstream" in the `Mutagen <https://github.com/quodlibet/mutagen>`__
library used by beets, in which case we'll forward the bug to that project's
tracker.
ticket`_ and we'll look into it. There's always a possibility that there's a bug
"upstream" in the `Mutagen <https://github.com/quodlibet/mutagen>`__ library
used by beets, in which case we'll forward the bug to that project's tracker.
.. _importhang:
…seem to "hang" after an import finishes?
-----------------------------------------
Probably not. Beets uses a *multithreaded importer* that overlaps many
different activities: it can prompt you for decisions while, in the
background, it talks to MusicBrainz and copies files. This means that,
even after you make your last decision, there may be a backlog of files
to be copied into place and tags to be written. (Plugin tasks, like
looking up lyrics and genres, also run at this time.) If beets pauses
after you see all the albums go by, have patience.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Probably not. Beets uses a *multithreaded importer* that overlaps many different
activities: it can prompt you for decisions while, in the background, it talks
to MusicBrainz and copies files. This means that, even after you make your last
decision, there may be a backlog of files to be copied into place and tags to be
written. (Plugin tasks, like looking up lyrics and genres, also run at this
time.) If beets pauses after you see all the albums go by, have patience.
.. _replaceq:
…put a bunch of underscores in my filenames?
--------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When naming files, beets replaces certain characters to avoid causing
problems on the filesystem. For example, leading dots can confusingly
hide files on Unix and several non-alphanumeric characters are forbidden
on Windows.
When naming files, beets replaces certain characters to avoid causing problems
on the filesystem. For example, leading dots can confusingly hide files on Unix
and several non-alphanumeric characters are forbidden on Windows.
The :ref:`replace` config option
controls which replacements are made. By default, beets makes filenames
safe for all known platforms by replacing several patterns with
underscores. This means that, even on Unix, filenames are made
Windows-safe so that network filesystems (such as SMB) can be used
safely.
Most notably, Windows forbids trailing dots, so a folder called "M.I.A."
will be rewritten to "M.I.A\_" by default. Change the ``replace`` config
if you don't want this behavior and don't need Windows-safe names.
The :ref:`replace` config option controls which replacements are made. By
default, beets makes filenames safe for all known platforms by replacing several
patterns with underscores. This means that, even on Unix, filenames are made
Windows-safe so that network filesystems (such as SMB) can be used safely.
Most notably, Windows forbids trailing dots, so a folder called "M.I.A." will be
rewritten to "M.I.A\_" by default. Change the ``replace`` config if you don't
want this behavior and don't need Windows-safe names.
.. _pathq:
…say "command not found"?
-------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~
You need to put the ``beet`` program on your system's search path. If you
installed using pip, the command ``pip show -f beets`` can show you where
``beet`` was placed on your system. If you need help extending your ``$PATH``,
try `this Super User answer`_.
.. _this Super User answer: https://superuser.com/a/284361/4569
.. _open a new ticket: https://github.com/beetbox/beets/issues/new?template=bug-report.md
.. _pip: https://pip.pypa.io/en/stable/
.. _open a new ticket:
https://github.com/beetbox/beets/issues/new?template=bug-report.md
.. _this super user answer: https://superuser.com/a/284361/4569

View file

@ -1,40 +1,40 @@
Advanced Awesomeness
====================
So you have beets up and running and you've started :doc:`importing your
music </guides/tagger>`. There's a lot more that beets can do now that it has
So you have beets up and running and you've started :doc:`importing your music
</guides/tagger>`. There's a lot more that beets can do now that it has
cataloged your collection. Here's a few features to get you started.
Most of these tips involve :doc:`plugins </plugins/index>` and fiddling with
beets' :doc:`configuration </reference/config>`. So use your favorite text
editor to create a config file before you continue.
Fetch album art, genres, and lyrics
-----------------------------------
Beets can help you fill in more than just the basic taxonomy metadata that
comes from MusicBrainz. Plugins can provide :doc:`album art
</plugins/fetchart>`, :doc:`lyrics </plugins/lyrics>`, and
:doc:`genres </plugins/lastgenre>` from databases around the Web.
Beets can help you fill in more than just the basic taxonomy metadata that comes
from MusicBrainz. Plugins can provide :doc:`album art </plugins/fetchart>`,
:doc:`lyrics </plugins/lyrics>`, and :doc:`genres </plugins/lastgenre>` from
databases around the Web.
If you want beets to get any of this data automatically during the import
process, just enable any of the three relevant plugins (see
:doc:`/plugins/index`). For example, put this line in your :doc:`config file
</reference/config>` to enable all three::
</reference/config>` to enable all three:
::
plugins: fetchart lyrics lastgenre
Each plugin also has a command you can run to fetch data manually. For
example, if you want to get lyrics for all the Beatles tracks in your
collection, just type ``beet lyrics beatles`` after enabling the plugin.
Each plugin also has a command you can run to fetch data manually. For example,
if you want to get lyrics for all the Beatles tracks in your collection, just
type ``beet lyrics beatles`` after enabling the plugin.
Read more about using each of these plugins:
* :doc:`/plugins/fetchart` (and its accompanying :doc:`/plugins/embedart`)
* :doc:`/plugins/lyrics`
* :doc:`/plugins/lastgenre`
- :doc:`/plugins/fetchart` (and its accompanying :doc:`/plugins/embedart`)
- :doc:`/plugins/lyrics`
- :doc:`/plugins/lastgenre`
Customize your file and folder names
------------------------------------
@ -42,22 +42,21 @@ Customize your file and folder names
Beets uses an extremely flexible template system to name the folders and files
that organize your music in your filesystem. Take a look at
:ref:`path-format-config` for the basics: use fields like ``$year`` and
``$title`` to build up a naming scheme. But if you need more flexibility,
there are two features you need to know about:
``$title`` to build up a naming scheme. But if you need more flexibility, there
are two features you need to know about:
* :ref:`Template functions <template-functions>` are simple expressions you
can use in your path formats to add logic to your names. For example, you
can get an artist's first initial using ``%upper{%left{$albumartist,1}}``.
* If you need more flexibility, the :doc:`/plugins/inline` lets you write
snippets of Python code that generate parts of your filenames. The
equivalent code for getting an artist initial with the *inline* plugin looks
like ``initial: albumartist[0].upper()``.
- :ref:`Template functions <template-functions>` are simple expressions you can
use in your path formats to add logic to your names. For example, you can get
an artist's first initial using ``%upper{%left{$albumartist,1}}``.
- If you need more flexibility, the :doc:`/plugins/inline` lets you write
snippets of Python code that generate parts of your filenames. The equivalent
code for getting an artist initial with the *inline* plugin looks like
``initial: albumartist[0].upper()``.
If you already have music in your library and want to update their names
according to a new scheme, just run the :ref:`move-cmd` command to rename
everything.
Stream your music to another computer
-------------------------------------
@ -69,8 +68,8 @@ your own personal Spotify.
First, enable the ``web`` plugin (see :doc:`/plugins/index`). Run the server by
typing ``beet web`` and head to http://localhost:8337 in a browser. You can
browse your collection with queries and, if your browser supports it, play
music using HTML5 audio.
browse your collection with queries and, if your browser supports it, play music
using HTML5 audio.
Transcode music files for media players
---------------------------------------
@ -78,9 +77,11 @@ Transcode music files for media players
Do you ever find yourself transcoding high-quality rips to a lower-bitrate,
lossy format for your phone or music player? Beets can help with that.
You'll first need to install `ffmpeg`_. Then, enable beets'
:doc:`/plugins/convert`. Set a destination directory in your
:doc:`config file </reference/config>` like so::
You'll first need to install ffmpeg_. Then, enable beets'
:doc:`/plugins/convert`. Set a destination directory in your :doc:`config file
</reference/config>` like so:
::
convert:
dest: ~/converted_music
@ -95,41 +96,44 @@ you like them. Check out :doc:`its documentation </plugins/convert>`.
.. _ffmpeg: https://www.ffmpeg.org
Store any data you like
-----------------------
The beets database keeps track of a long list of :ref:`built-in fields
<itemfields>`, but you're not limited to just that list. Say, for example,
that you like to categorize your music by the setting where it should be
played. You can invent a new ``context`` attribute to store this. Set the field
using the :ref:`modify-cmd` command::
<itemfields>`, but you're not limited to just that list. Say, for example, that
you like to categorize your music by the setting where it should be played. You
can invent a new ``context`` attribute to store this. Set the field using the
:ref:`modify-cmd` command:
::
beet modify context=party artist:'beastie boys'
By default, beets will show you the changes that are about to be applied and ask
if you really want to apply them to all, some or none of the items or albums.
You can type y for "yes", n for "no", or s for "select". If you choose the latter,
the command will prompt you for each individual matching item or album.
You can type y for "yes", n for "no", or s for "select". If you choose the
latter, the command will prompt you for each individual matching item or album.
Then :doc:`query </reference/query>` your music just as you would with any
other field::
Then :doc:`query </reference/query>` your music just as you would with any other
field:
::
beet ls context:mope
You can even use these fields in your filenames (see
:ref:`path-format-config`).
You can even use these fields in your filenames (see :ref:`path-format-config`).
And, unlike :ref:`built-in fields <itemfields>`, such fields can be removed::
And, unlike :ref:`built-in fields <itemfields>`, such fields can be removed:
::
beet modify context! artist:'beastie boys'
Read more than you ever wanted to know about the *flexible attributes*
feature `on the beets blog`_.
Read more than you ever wanted to know about the *flexible attributes* feature
`on the beets blog`_.
.. _on the beets blog: https://beets.io/blog/flexattr.html
Choose a path style manually for some music
-------------------------------------------
@ -139,19 +143,22 @@ like, but keep around to play for friends and family. This is, of course,
impossible to determine automatically using metadata from MusicBrainz.
Instead, use a flexible attribute (see above) to store a flag on the music you
want to categorize, like so::
want to categorize, like so:
::
beet modify bad=1 christmas
Then, you can query on this field in your path formats to sort this music
differently. Put something like this in your configuration file::
differently. Put something like this in your configuration file:
::
paths:
bad:1: Bad/$artist/$title
Used together, flexible attributes and path format conditions let you sort
your music by any criteria you can imagine.
Used together, flexible attributes and path format conditions let you sort your
music by any criteria you can imagine.
Automatically add new music to your library
-------------------------------------------
@ -167,19 +174,16 @@ or the like. To use it this way, you might want to use these options in your
quiet: yes
log: /path/to/log.txt
The :ref:`incremental` option will skip importing any directories that have
been imported in the past.
:ref:`quiet` avoids asking you any questions (since this will be run
automatically, no input is possible).
You might also want to use the :ref:`quiet_fallback` options to configure
what should happen when no near-perfect match is found -- this option depends
on your level of paranoia.
The :ref:`incremental` option will skip importing any directories that have been
imported in the past. :ref:`quiet` avoids asking you any questions (since this
will be run automatically, no input is possible). You might also want to use the
:ref:`quiet_fallback` options to configure what should happen when no
near-perfect match is found -- this option depends on your level of paranoia.
Finally, :ref:`import_log` will make beets record its decisions so you can come
back later and see what you need to handle manually.
The last step is to set up cron or some other automation system to run
``beet import /path/to/incoming/music``.
The last step is to set up cron or some other automation system to run ``beet
import /path/to/incoming/music``.
Useful reports
--------------
@ -187,19 +191,25 @@ Useful reports
Since beets has a quite powerful query tool, this list contains some useful and
powerful queries to run on your library.
* See a list of all albums which have files which are 128 bit rate::
- See a list of all albums which have files which are 128 bit rate:
::
beet list bitrate:128000
* See a list of all albums with the tracks listed in order of bit rate::
- See a list of all albums with the tracks listed in order of bit rate:
::
beet ls -f '$bitrate $artist - $title' bitrate+
* See a list of albums and their formats::
- See a list of albums and their formats:
::
beet ls -f '$albumartist $album $format' | sort | uniq
Note that ``beet ls --album -f '... $format'`` doesn't do what you want,
because ``format`` is an item-level field, not an album-level one.
If an album's tracks exist in multiple formats, the album will appear in the
list once for each format.
because ``format`` is an item-level field, not an album-level one. If an
album's tracks exist in multiple formats, the album will appear in the list
once for each format.

View file

@ -6,8 +6,8 @@ with beets. If you're new to beets, you'll want to begin with the :doc:`main`
guide.
.. toctree::
:maxdepth: 1
:maxdepth: 1
main
tagger
advanced
main
tagger
advanced

View file

@ -1,7 +1,7 @@
Getting Started
===============
Welcome to `beets`_! This guide will help you begin using it to make your music
Welcome to beets_! This guide will help you begin using it to make your music
collection better.
.. _beets: https://beets.io/
@ -9,65 +9,66 @@ collection better.
Installing
----------
You will need Python.
Beets works on Python 3.8 or later.
You will need Python. Beets works on Python 3.8 or later.
* **macOS** 11 (Big Sur) includes Python 3.8 out of the box.
You can opt for a more recent Python installing it via `Homebrew`_
(``brew install python3``).
There's also a `MacPorts`_ port. Run ``port install beets`` or
``port install beets-full`` to include many third-party plugins.
* On **Debian or Ubuntu**, depending on the version, beets is available as an
- **macOS** 11 (Big Sur) includes Python 3.8 out of the box. You can opt for a
more recent Python installing it via Homebrew_ (``brew install python3``).
There's also a MacPorts_ port. Run ``port install beets`` or ``port install
beets-full`` to include many third-party plugins.
- On **Debian or Ubuntu**, depending on the version, beets is available as an
official package (`Debian details`_, `Ubuntu details`_), so try typing:
``apt-get install beets``. But the version in the repositories might lag
behind, so make sure you read the right version of these docs. If you want
the latest version, you can get everything you need to install with pip
as described below by running:
``apt-get install python-dev python-pip``
* On **Arch Linux**, `beets is in [extra] <Arch extra_>`_, so just run ``pacman -S
beets``. (There's also a bleeding-edge `dev package <AUR_>`_ in the AUR, which will
probably set your computer on fire.)
* On **Alpine Linux**, `beets is in the community repository <Alpine package_>`_
behind, so make sure you read the right version of these docs. If you want the
latest version, you can get everything you need to install with pip as
described below by running: ``apt-get install python-dev python-pip``
- On **Arch Linux**, `beets is in [extra] <arch extra_>`_, so just run ``pacman
-S beets``. (There's also a bleeding-edge `dev package <aur_>`_ in the AUR,
which will probably set your computer on fire.)
- On **Alpine Linux**, `beets is in the community repository <alpine package_>`_
and can be installed with ``apk add beets``.
* For **Gentoo Linux**, beets is in Portage as ``media-sound/beets``. Just run
- For **Gentoo Linux**, beets is in Portage as ``media-sound/beets``. Just run
``emerge beets`` to install. There are several USE flags available for
optional plugin dependencies.
- On **FreeBSD**, there's a `beets port <freebsd_>`_ at ``audio/beets``.
- On **OpenBSD**, there's a `beets port <openbsd_>`_ can be installed with
``pkg_add beets``.
- For **Slackware**, there's a SlackBuild_ available.
- On **Fedora** 22 or later, there's a `DNF package`_ you can install with
``sudo dnf install beets beets-plugins beets-doc``.
- On **Solus**, run ``eopkg install beets``.
- On **NixOS**, there's a `package <nixos_>`_ you can install with ``nix-env -i
beets``.
* On **FreeBSD**, there's a `beets port <FreeBSD_>`_ at ``audio/beets``.
.. _alpine package: https://pkgs.alpinelinux.org/package/edge/community/x86_64/beets
* On **OpenBSD**, there's a `beets port <OpenBSD_>`_ can be installed with ``pkg_add beets``.
.. _arch extra: https://archlinux.org/packages/extra/any/beets/
* For **Slackware**, there's a `SlackBuild`_ available.
.. _aur: https://aur.archlinux.org/packages/beets-git/
* On **Fedora** 22 or later, there's a `DNF package`_ you can install with ``sudo dnf install beets beets-plugins beets-doc``.
.. _debian details: https://tracker.debian.org/pkg/beets
* On **Solus**, run ``eopkg install beets``.
.. _dnf package: https://packages.fedoraproject.org/pkgs/beets/
* On **NixOS**, there's a `package <NixOS_>`_ you can install with ``nix-env -i beets``.
.. _freebsd: http://portsmon.freebsd.org/portoverview.py?category=audio&portname=beets
.. _DNF package: https://packages.fedoraproject.org/pkgs/beets/
.. _SlackBuild: https://slackbuilds.org/repository/14.2/multimedia/beets/
.. _FreeBSD: http://portsmon.freebsd.org/portoverview.py?category=audio&portname=beets
.. _AUR: https://aur.archlinux.org/packages/beets-git/
.. _Debian details: https://tracker.debian.org/pkg/beets
.. _Ubuntu details: https://launchpad.net/ubuntu/+source/beets
.. _OpenBSD: http://openports.se/audio/beets
.. _Arch extra: https://archlinux.org/packages/extra/any/beets/
.. _Alpine package: https://pkgs.alpinelinux.org/package/edge/community/x86_64/beets
.. _NixOS: https://github.com/NixOS/nixpkgs/tree/master/pkgs/tools/audio/beets
.. _MacPorts: https://www.macports.org
.. _macports: https://www.macports.org
If you have `pip`_, just say ``pip install beets`` (or ``pip install --user
.. _nixos: https://github.com/NixOS/nixpkgs/tree/master/pkgs/tools/audio/beets
.. _openbsd: http://openports.se/audio/beets
.. _slackbuild: https://slackbuilds.org/repository/14.2/multimedia/beets/
.. _ubuntu details: https://launchpad.net/ubuntu/+source/beets
If you have pip_, just say ``pip install beets`` (or ``pip install --user
beets`` if you run into permissions problems).
To install without pip, download beets from `its PyPI page`_ and run ``python
setup.py install`` in the directory therein.
.. _its PyPI page: https://pypi.org/project/beets/#files
.. _its pypi page: https://pypi.org/project/beets/#files
.. _pip: https://pip.pypa.io
The best way to upgrade beets to a new version is by running ``pip install -U
@ -77,119 +78,124 @@ new versions.
.. _@b33ts: https://twitter.com/b33ts
Installing by Hand on macOS 10.11 and Higher
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Starting with version 10.11 (El Capitan), macOS has a new security feature
called `System Integrity Protection`_ (SIP) that prevents you from modifying
some parts of the system. This means that some ``pip`` commands may fail with a
permissions error. (You probably *won't* run into this if you've installed
Python yourself with `Homebrew`_ or otherwise. You can also try `MacPorts`_.)
Python yourself with Homebrew_ or otherwise. You can also try MacPorts_.)
If this happens, you can install beets for the current user only by typing
``pip install --user beets``. If you do that, you might want to add
If this happens, you can install beets for the current user only by typing ``pip
install --user beets``. If you do that, you might want to add
``~/Library/Python/3.6/bin`` to your ``$PATH``.
.. _System Integrity Protection: https://support.apple.com/en-us/HT204899
.. _Homebrew: https://brew.sh
.. _homebrew: https://brew.sh
.. _system integrity protection: https://support.apple.com/en-us/HT204899
Installing on Windows
^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~
Installing beets on Windows can be tricky. Following these steps might help you
get it right:
1. If you don't have it, `install Python`_ (you want at least Python 3.8). The
installer should give you the option to "add Python to PATH." Check this
box. If you do that, you can skip the next step.
installer should give you the option to "add Python to PATH." Check this box.
If you do that, you can skip the next step.
2. If you haven't done so already, set your ``PATH`` environment variable to
include Python and its scripts. To do so, open the "Settings" application,
then access the "System" screen, then access the "About" tab, and then hit
"Advanced system settings" located on the right side of the screen. This
should open the "System Properties" screen, then select the "Advanced" tab,
then hit the "Environmental Variables..." button, and then look for the PATH
variable in the table. Add the following to the end of the variable's value:
``;C:\Python38;C:\Python38\Scripts``. You may need to adjust these paths to
include Python and its scripts. To do so, open the "Settings" application,
then access the "System" screen, then access the "About" tab, and then hit
"Advanced system settings" located on the right side of the screen. This
should open the "System Properties" screen, then select the "Advanced" tab,
then hit the "Environmental Variables..." button, and then look for the PATH
variable in the table. Add the following to the end of the variable's value:
``;C:\Python38;C:\Python38\Scripts``. You may need to adjust these paths to
point to your Python installation.
3. Now install beets by running: ``pip install beets``
4. You're all set! Type ``beet`` at the command prompt to make sure everything's
in order.
Windows users may also want to install a context menu item for importing files
into beets. Download the `beets.reg`_ file and open it in a text file to make
sure the paths to Python match your system. Then double-click the file add the
necessary keys to your registry. You can then right-click a directory and
choose "Import with beets".
into beets. Download the beets.reg_ file and open it in a text file to make sure
the paths to Python match your system. Then double-click the file add the
necessary keys to your registry. You can then right-click a directory and choose
"Import with beets".
Because I don't use Windows myself, I may have missed something. If you have
trouble or you have more detail to contribute here, please direct it to
`the mailing list`_.
trouble or you have more detail to contribute here, please direct it to `the
mailing list`_.
.. _install Python: https://python.org/download/
.. _beets.reg: https://github.com/beetbox/beets/blob/master/extra/beets.reg
.. _install pip: https://pip.pypa.io/en/stable/installing/
.. _get-pip.py: https://bootstrap.pypa.io/get-pip.py
.. _install pip: https://pip.pypa.io/en/stable/installing/
.. _install python: https://python.org/download/
Installing on ARM (Raspberry Pi and similar)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Beets on ARM devices is not recommended for Linux novices. If you are
comfortable with light troubleshooting in tools like ``pip``, ``make``,
and beets' command-line binary dependencies (e.g. ``ffmpeg`` and
``ImageMagick``), you will probably be okay on ARM devices like the
Raspberry Pi. We have `notes for ARM`_ and an `older ARM reference`_.
Beets is generally developed on x86-64 based devices, and most plugins
target that platform as well.
comfortable with light troubleshooting in tools like ``pip``, ``make``, and
beets' command-line binary dependencies (e.g. ``ffmpeg`` and ``ImageMagick``),
you will probably be okay on ARM devices like the Raspberry Pi. We have `notes
for ARM`_ and an `older ARM reference`_. Beets is generally developed on x86-64
based devices, and most plugins target that platform as well.
.. _notes for ARM: https://github.com/beetbox/beets/discussions/4910
.. _older ARM reference: https://discourse.beets.io/t/diary-of-beets-on-arm-odroid-hc4-armbian/1993
.. _notes for arm: https://github.com/beetbox/beets/discussions/4910
.. _older arm reference: https://discourse.beets.io/t/diary-of-beets-on-arm-odroid-hc4-armbian/1993
Configuring
-----------
You'll want to set a few basic options before you start using beets. The
:doc:`configuration </reference/config>` is stored in a text file. You
can show its location by running ``beet config -p``, though it may not
exist yet. Run ``beet config -e`` to edit the configuration in your
favorite text editor. The file will start out empty, but here's good
place to start::
:doc:`configuration </reference/config>` is stored in a text file. You can show
its location by running ``beet config -p``, though it may not exist yet. Run
``beet config -e`` to edit the configuration in your favorite text editor. The
file will start out empty, but here's good place to start:
::
directory: ~/music
library: ~/data/musiclibrary.db
Change that first path to a directory where you'd like to keep your music. Then,
for ``library``, choose a good place to keep a database file that keeps an index
of your music. (The config's format is `YAML`_. You'll want to configure your
text editor to use spaces, not real tabs, for indentation. Also, ``~`` means
your home directory in these paths, even on Windows.)
of your music. (The config's format is YAML_. You'll want to configure your text
editor to use spaces, not real tabs, for indentation. Also, ``~`` means your
home directory in these paths, even on Windows.)
The default configuration assumes you want to start a new organized music folder
(that ``directory`` above) and that you'll *copy* cleaned-up music into that
empty folder using beets' ``import`` command (see below). But you can configure
beets to behave many other ways:
* Start with a new empty directory, but *move* new music in instead of copying
it (saving disk space). Put this in your config file::
- Start with a new empty directory, but *move* new music in instead of copying
it (saving disk space). Put this in your config file:
import:
move: yes
::
* Keep your current directory structure; importing should never move or copy
import:
move: yes
- Keep your current directory structure; importing should never move or copy
files but instead just correct the tags on music. Put the line ``copy: no``
under the ``import:`` heading in your config file to disable any copying or
renaming. Make sure to point ``directory`` at the place where your music is
currently stored.
* Keep your current directory structure and *do not* correct files' tags: leave
- Keep your current directory structure and *do not* correct files' tags: leave
files completely unmodified on your disk. (Corrected tags will still be stored
in beets' database, and you can use them to do renaming or tag changes later.)
Put this in your config file::
Put this in your config file:
import:
copy: no
write: no
::
import:
copy: no
write: no
to disable renaming and tag-writing.
@ -197,20 +203,19 @@ There are approximately six million other configuration options you can set
here, including the directory and file naming scheme. See
:doc:`/reference/config` for a full reference.
.. _YAML: https://yaml.org/
.. _yaml: https://yaml.org/
To check that you've set up your configuration how you want it, you can type
``beet version`` to see a list of enabled plugins or ``beet config`` to get a
complete listing of your current configuration.
Importing Your Library
----------------------
The next step is to import your music files into the beets library database.
Because this can involve modifying files and moving them around, data loss is
always a possibility, so now would be a good time to make sure you have a
recent backup of all your music. We'll wait.
always a possibility, so now would be a good time to make sure you have a recent
backup of all your music. We'll wait.
There are two good ways to bring your existing library into beets. You can
either: (a) quickly bring all your files with all their current metadata into
@ -219,18 +224,21 @@ metadata for every album you import. Option (a) is really fast, but option (b)
makes sure all your songs' tags are exactly right from the get-go. The point
about speed bears repeating: using the autotagger on a large library can take a
very long time, and it's an interactive process. So set aside a good chunk of
time if you're going to go that route. For more on the interactive
tagging process, see :doc:`tagger`.
time if you're going to go that route. For more on the interactive tagging
process, see :doc:`tagger`.
If you've got time and want to tag all your music right once and for all, do
this::
this:
::
$ beet import /path/to/my/music
(Note that by default, this command will *copy music into the directory you
specified above*. If you want to use your current directory structure, set the
``import.copy`` config option.) To take the fast,
un-autotagged path, just say::
``import.copy`` config option.) To take the fast, un-autotagged path, just say:
::
$ beet import -A /my/huge/mp3/library
@ -240,7 +248,9 @@ Adding More Music
-----------------
If you've ripped or... otherwise obtained some new music, you can add it with
the ``beet import`` command, the same way you imported your library. Like so::
the ``beet import`` command, the same way you imported your library. Like so:
::
$ beet import ~/some_great_album
@ -254,7 +264,9 @@ Seeing Your Music
If you want to query your music library, the ``beet list`` (shortened to ``beet
ls``) command is for you. You give it a :doc:`query string </reference/query>`,
which is formatted something like a Google search, and it gives you a list of
songs. Thus::
songs. Thus:
::
$ beet ls the magnetic fields
The Magnetic Fields - Distortion - Three-Way
@ -268,33 +280,40 @@ songs. Thus::
$ beet ls album:bird
The Mae Shi - Terrorbird - Revelation Six
By default, a search term will match any of a handful of :ref:`common
attributes <keywordquery>` of songs.
(They're
also implicitly joined by ANDs: a track must match *all* criteria in order to
match the query.) To narrow a search term to a particular metadata field, just
put the field before the term, separated by a : character. So ``album:bird``
only looks for ``bird`` in the "album" field of your songs. (Need to know more?
:doc:`/reference/query/` will answer all your questions.)
By default, a search term will match any of a handful of :ref:`common attributes
<keywordquery>` of songs. (They're also implicitly joined by ANDs: a track must
match *all* criteria in order to match the query.) To narrow a search term to a
particular metadata field, just put the field before the term, separated by a :
character. So ``album:bird`` only looks for ``bird`` in the "album" field of
your songs. (Need to know more? :doc:`/reference/query/` will answer all your
questions.)
The ``beet list`` command also has an ``-a`` option, which searches for albums instead of songs::
The ``beet list`` command also has an ``-a`` option, which searches for albums
instead of songs:
::
$ beet ls -a forever
Bon Iver - For Emma, Forever Ago
Freezepop - Freezepop Forever
There's also an ``-f`` option (for *format*) that lets you specify what gets displayed in the results of a search::
There's also an ``-f`` option (for *format*) that lets you specify what gets
displayed in the results of a search:
::
$ beet ls -a forever -f "[$format] $album ($year) - $artist - $title"
[MP3] For Emma, Forever Ago (2009) - Bon Iver - Flume
[AAC] Freezepop Forever (2011) - Freezepop - Harebrained Scheme
In the format option, field references like `$format` and `$year` are filled
In the format option, field references like ``$format`` and ``$year`` are filled
in with data from each result. You can see a full list of available fields by
running ``beet fields``.
Beets also has a ``stats`` command, just in case you want to see how much music
you have::
you have:
::
$ beet stats
Tracks: 13019
@ -307,25 +326,27 @@ Keep Playing
------------
This is only the beginning of your long and prosperous journey with beets. To
keep learning, take a look at :doc:`advanced` for a sampling of what else
is possible. You'll also want to glance over the :doc:`/reference/cli` page
for a more detailed description of all of beets' functionality. (Like
deleting music! That's important.)
keep learning, take a look at :doc:`advanced` for a sampling of what else is
possible. You'll also want to glance over the :doc:`/reference/cli` page for a
more detailed description of all of beets' functionality. (Like deleting music!
That's important.)
Also, check out :doc:`beets' plugins </plugins/index>`. The
real power of beets is in its extensibility---with plugins, beets can do almost
anything for your music collection.
Also, check out :doc:`beets' plugins </plugins/index>`. The real power of beets
is in its extensibility---with plugins, beets can do almost anything for your
music collection.
You can always get help using the ``beet help`` command. The plain ``beet help``
command lists all the available commands; then, for example, ``beet help
import`` gives more specific help about the ``import`` command.
If you need more of a walkthrough, you can read an illustrated one `on the
beets blog <https://beets.io/blog/walkthrough.html>`_.
If you need more of a walkthrough, you can read an illustrated one `on the beets
blog <https://beets.io/blog/walkthrough.html>`_.
Please let us know what you think of beets via `the discussion board`_ or
`Mastodon`_.
Mastodon_.
.. _mastodon: https://fosstodon.org/@beets
.. _the discussion board: https://github.com/beetbox/beets/discussions
.. _the mailing list: https://groups.google.com/group/beets-users
.. _the discussion board: https://github.com/beetbox/beets/discussions
.. _mastodon: https://fosstodon.org/@beets

View file

@ -39,7 +39,7 @@ directory and it imports the files into your library, tagging them as it goes
beets currently makes about the music you import. In time, we'd like to remove
all of these limitations.
* Your music should be organized by album into directories. That is, the tagger
- Your music should be organized by album into directories. That is, the tagger
assumes that each album is in a single directory. These directories can be
arbitrarily deep (like ``music/2010/hiphop/seattle/freshespresso/glamour``),
but any directory with music files in it is interpreted as a separate album.
@ -48,36 +48,35 @@ all of these limitations.
First, directories that look like separate parts of a *multi-disc album* are
tagged together as a single release. If two adjacent albums have a common
prefix, followed by "disc," "disk," or "CD" and then a number, they are
tagged together.
prefix, followed by "disc," "disk," or "CD" and then a number, they are tagged
together.
Second, if you have jumbled directories containing more than one album, you
can ask beets to split them apart for you based on their metadata. Use
either the ``--group-albums`` command-line flag or the *G* interactive
option described below.
can ask beets to split them apart for you based on their metadata. Use either
the ``--group-albums`` command-line flag or the *G* interactive option
described below.
* The music may have bad tags, but it's not completely untagged. This is
because beets by default infers tags based on existing metadata. But this is
not a hard and fast rule---there are a few ways to tag metadata-poor music:
- The music may have bad tags, but it's not completely untagged. This is because
beets by default infers tags based on existing metadata. But this is not a
hard and fast rule---there are a few ways to tag metadata-poor music:
* You can use the *E* or *I* options described below to search in
MusicBrainz for a specific album or song.
* The :doc:`Acoustid plugin </plugins/chroma>` extends the autotagger to
use acoustic fingerprinting to find information for arbitrary audio.
Install that plugin if you're willing to spend a little more CPU power
to get tags for unidentified albums. (But be aware that it does slow
down the process.)
* The :doc:`FromFilename plugin </plugins/fromfilename>` adds the ability
to guess tags from the filenames. Use this plugin if your tracks have
useful names (like "03 Call Me Maybe.mp3") but their tags don't reflect
that.
- You can use the *E* or *I* options described below to search in
MusicBrainz for a specific album or song.
- The :doc:`Acoustid plugin </plugins/chroma>` extends the autotagger to
use acoustic fingerprinting to find information for arbitrary audio.
Install that plugin if you're willing to spend a little more CPU power
to get tags for unidentified albums. (But be aware that it does slow
down the process.)
- The :doc:`FromFilename plugin </plugins/fromfilename>` adds the ability
to guess tags from the filenames. Use this plugin if your tracks have
useful names (like "03 Call Me Maybe.mp3") but their tags don't reflect
that.
* Currently, MP3, AAC, FLAC, ALAC, Ogg Vorbis, Monkey's Audio, WavPack,
Musepack, Windows Media, Opus, and AIFF files are supported. (Do you use
some other format? Please `file a feature request`_!)
- Currently, MP3, AAC, FLAC, ALAC, Ogg Vorbis, Monkey's Audio, WavPack,
Musepack, Windows Media, Opus, and AIFF files are supported. (Do you use some
other format? Please `file a feature request`_!)
.. _file a feature request:
https://github.com/beetbox/beets/issues/new?template=feature-request.md
.. _file a feature request: https://github.com/beetbox/beets/issues/new?template=feature-request.md
Now that that's out of the way, let's tag some music.
@ -89,44 +88,35 @@ Options
To import music, just say ``beet import MUSICDIR``. There are, of course, a few
command-line options you should know:
* ``beet import -A``: don't try to autotag anything; just import files (this
- ``beet import -A``: don't try to autotag anything; just import files (this
goes much faster than with autotagging enabled)
* ``beet import -W``: when autotagging, don't write new tags to the files
- ``beet import -W``: when autotagging, don't write new tags to the files
themselves (just keep the new metadata in beets' database)
* ``beet import -C``: don't copy imported files to your music directory; leave
- ``beet import -C``: don't copy imported files to your music directory; leave
them where they are
* ``beet import -m``: move imported files to your music directory (overrides
the ``-c`` option)
* ``beet import -l LOGFILE``: write a message to ``LOGFILE`` every time you skip
- ``beet import -m``: move imported files to your music directory (overrides the
``-c`` option)
- ``beet import -l LOGFILE``: write a message to ``LOGFILE`` every time you skip
an album or choose to take its tags "as-is" (see below) or the album is
skipped as a duplicate; this lets you come back later and reexamine albums
that weren't tagged successfully. Run ``beet import --from-logfile=LOGFILE``
rerun the importer on such paths from the logfile.
* ``beet import -q``: quiet mode. Never prompt for input and, instead,
- ``beet import -q``: quiet mode. Never prompt for input and, instead,
conservatively skip any albums that need your opinion. The ``-ql`` combination
is recommended.
* ``beet import -t``: timid mode, which is sort of the opposite of "quiet." The
- ``beet import -t``: timid mode, which is sort of the opposite of "quiet." The
importer will ask your permission for everything it does, confirming even very
good matches with a prompt.
* ``beet import -p``: automatically resume an interrupted import. The importer
- ``beet import -p``: automatically resume an interrupted import. The importer
keeps track of imports that don't finish completely (either due to a crash or
because you stop them halfway through) and, by default, prompts you to decide
whether to resume them. The ``-p`` flag automatically says "yes" to this
question. Relatedly, ``-P`` flag automatically says "no."
* ``beet import -s``: run in *singleton* mode, tagging individual tracks instead
of whole albums at a time. See the "as Tracks" choice below. This means you
- ``beet import -s``: run in *singleton* mode, tagging individual tracks instead
of whole albums at a time. See the "as Tracks" choice below. This means you
can use ``beet import -AC`` to quickly add a bunch of files to your library
without doing anything to them.
* ``beet import -g``: assume there are multiple albums contained in each
- ``beet import -g``: assume there are multiple albums contained in each
directory. The tracks contained a directory are grouped by album artist and
album name and you will be asked to import each of these groups separately.
See the "Group albums" choice below.
@ -134,7 +124,9 @@ command-line options you should know:
Similarity
----------
So you import an album into your beets library. It goes like this::
So you import an album into your beets library. It goes like this:
::
$ beet imp witchinghour
Tagging:
@ -161,7 +153,9 @@ better at making the call than a computer. So it occasionally asks for help.
Choices
-------
When beets needs your input about a match, it says something like this::
When beets needs your input about a match, it says something like this:
::
Tagging:
Beirut - Lon Gisland
@ -173,36 +167,28 @@ When beets asks you this question, it wants you to enter one of the capital
letters: A, M, S, U, T, G, E, I or B. That is, you can choose one of the
following:
* *A*: Apply the suggested changes shown and move on.
* *M*: Show more options. (See the Candidates section, below.)
* *S*: Skip this album entirely and move on to the next one.
* *U*: Import the album without changing any tags. This is a good option for
- *A*: Apply the suggested changes shown and move on.
- *M*: Show more options. (See the Candidates section, below.)
- *S*: Skip this album entirely and move on to the next one.
- *U*: Import the album without changing any tags. This is a good option for
albums that aren't in the MusicBrainz database, like your friend's operatic
faux-goth solo record that's only on two CD-Rs in the universe.
* *T*: Import the directory as *singleton* tracks, not as an album. Choose this
- *T*: Import the directory as *singleton* tracks, not as an album. Choose this
if the tracks don't form a real release---you just have one or more loner
tracks that aren't a full album. This will temporarily flip the tagger into
*singleton* mode, which attempts to match each track individually.
* *G*: Group tracks in this directory by *album artist* and *album* and import
- *G*: Group tracks in this directory by *album artist* and *album* and import
groups as albums. If the album artist for a track is not set then the artist
is used to group that track. For each group importing proceeds as for
directories. This is helpful if a directory contains multiple albums.
* *E*: Enter an artist and album to use as a search in the database. Use this
- *E*: Enter an artist and album to use as a search in the database. Use this
option if beets hasn't found any good options because the album is mistagged
or untagged.
* *I*: Enter a metadata backend ID to use as search in the database. Use this
- *I*: Enter a metadata backend ID to use as search in the database. Use this
option to specify a backend entity (for example, a MusicBrainz release or
recording) directly, by pasting its ID or the full URL. You can also specify
several IDs by separating them by a space.
* *B*: Cancel this import task altogether. No further albums will be tagged;
- *B*: Cancel this import task altogether. No further albums will be tagged;
beets shuts down immediately. The next time you attempt to import the same
directory, though, beets will ask you if you want to resume tagging where you
left off.
@ -215,7 +201,9 @@ Candidates
If you choose the M option, or if beets isn't very confident about any of the
choices it found, it will present you with a list of choices (called
candidates), like so::
candidates), like so:
::
Finding tags for "Panther - Panther".
Candidates:
@ -225,9 +213,9 @@ candidates), like so::
Here, you have many of the same options as before, but you can also enter a
number to choose one of the options that beets has found. Don't worry about
guessing---beets will show you the proposed changes and ask you to confirm
them, just like the earlier example. As the prompt suggests, you can just hit
return to select the first candidate.
guessing---beets will show you the proposed changes and ask you to confirm them,
just like the earlier example. As the prompt suggests, you can just hit return
to select the first candidate.
.. _guide-duplicates:
@ -235,7 +223,9 @@ Duplicates
----------
If beets finds an album or item in your library that seems to be the same as the
one you're importing, you may see a prompt like this::
one you're importing, you may see a prompt like this:
::
This album is already in the library!
[S]kip new, Keep all, Remove old, Merge all?
@ -243,19 +233,17 @@ one you're importing, you may see a prompt like this::
Beets wants to keep you safe from duplicates, which can be a real pain, so you
have four choices in this situation. You can skip importing the new music,
choosing to keep the stuff you already have in your library; you can keep both
the old and the new music; you can remove the existing music and choose the
new stuff; or you can merge all the new and old tracks into a single album.
If you choose that "remove" option, any duplicates will be
removed from your library database---and, if the corresponding files are located
inside of your beets library directory, the files themselves will be deleted as
well.
the old and the new music; you can remove the existing music and choose the new
stuff; or you can merge all the new and old tracks into a single album. If you
choose that "remove" option, any duplicates will be removed from your library
database---and, if the corresponding files are located inside of your beets
library directory, the files themselves will be deleted as well.
If you choose "merge", beets will try re-importing the existing and new tracks
as one bundle together.
This is particularly helpful when you have an album that's missing some tracks
and then want to import the remaining songs.
The importer will ask you the same questions as it would if you were importing
all tracks at once.
as one bundle together. This is particularly helpful when you have an album
that's missing some tracks and then want to import the remaining songs. The
importer will ask you the same questions as it would if you were importing all
tracks at once.
If you choose to keep two identically-named albums, beets can avoid storing both
in the same directory. See :ref:`aunique` for details.
@ -268,15 +256,16 @@ files, but can get confused when files don't have any metadata (or have wildly
incorrect metadata). In this case, you need *acoustic fingerprinting*, a
technology that identifies songs from the audio itself. With fingerprinting,
beets can autotag files that have very bad or missing tags. The :doc:`"chroma"
plugin </plugins/chroma>`, distributed with beets, uses the `Chromaprint`_ open-source fingerprinting technology, but it's disabled by default. That's because
it's sort of tricky to install. See the :doc:`/plugins/chroma` page for a guide
to getting it set up.
plugin </plugins/chroma>`, distributed with beets, uses the Chromaprint_
open-source fingerprinting technology, but it's disabled by default. That's
because it's sort of tricky to install. See the :doc:`/plugins/chroma` page for
a guide to getting it set up.
Before you jump into acoustic fingerprinting with both feet, though, give beets
a try without it. You may be surprised at how well metadata-based matching
works.
.. _Chromaprint: https://acoustid.org/chromaprint
.. _chromaprint: https://acoustid.org/chromaprint
Album Art, Lyrics, Genres and Such
----------------------------------
@ -292,11 +281,11 @@ Missing Albums?
---------------
If you're having trouble tagging a particular album with beets, check to make
sure the album is present in `the MusicBrainz database`_. You can search on
sure the album is present in `the MusicBrainz database`_. You can search on
their site to make sure it's cataloged there. If not, anyone can edit
MusicBrainz---so consider adding the data yourself.
.. _the MusicBrainz database: https://musicbrainz.org/
.. _the musicbrainz database: https://musicbrainz.org/
If you think beets is ignoring an album that's listed in MusicBrainz, please
`file a bug report`_.
@ -306,8 +295,9 @@ If you think beets is ignoring an album that's listed in MusicBrainz, please
I Hope That Makes Sense
-----------------------
If we haven't made the process clear, please post on `the discussion
board`_ and we'll try to improve this guide.
If we haven't made the process clear, please post on `the discussion board`_ and
we'll try to improve this guide.
.. _the discussion board: https://github.com/beetbox/beets/discussions/
.. _the mailing list: https://groups.google.com/group/beets-users
.. _the discussion board: https://github.com/beetbox/beets/discussions/

View file

@ -1,8 +1,8 @@
beets: the music geek's media organizer
=======================================
Welcome to the documentation for `beets`_, the media library management system
for obsessive music geeks.
Welcome to the documentation for beets_, the media library management system for
obsessive music geeks.
If you're new to beets, begin with the :doc:`guides/main` guide. That guide
walks you through installing beets, setting it up how you like it, and starting
@ -13,31 +13,34 @@ Then you can get a more detailed look at beets' features in the
be interested in exploring the :doc:`plugins </plugins/index>`.
If you still need help, you can drop by the ``#beets`` IRC channel on
Libera.Chat, drop by `the discussion board`_, send email to
`the mailing list`_, or `file a bug`_ in the issue tracker. Please let us know
where you think this documentation can be improved.
Libera.Chat, drop by `the discussion board`_, send email to `the mailing list`_,
or `file a bug`_ in the issue tracker. Please let us know where you think this
documentation can be improved.
.. _beets: https://beets.io/
.. _the mailing list: https://groups.google.com/group/beets-users
.. _file a bug: https://github.com/beetbox/beets/issues
.. _the discussion board: https://github.com/beetbox/beets/discussions/
.. _the mailing list: https://groups.google.com/group/beets-users
Contents
--------
.. toctree::
:maxdepth: 2
:maxdepth: 2
guides/index
reference/index
plugins/index
faq
team
contributing
code_of_conduct
dev/index
guides/index
reference/index
plugins/index
faq
team
contributing
code_of_conduct
dev/index
.. toctree::
:maxdepth: 1
:maxdepth: 1
changelog
changelog

View file

@ -2,10 +2,10 @@ AcousticBrainz Submit Plugin
============================
The ``absubmit`` plugin lets you submit acoustic analysis results to an
`AcousticBrainz`_ server. This plugin is now deprecated since the
AcousicBrainz project has been shut down.
AcousticBrainz_ server. This plugin is now deprecated since the AcousicBrainz
project has been shut down.
As an alternative the `beets-xtractor`_ plugin can be used.
As an alternative the beets-xtractor_ plugin can be used.
Warning
-------
@ -16,37 +16,37 @@ The AcousticBrainz project has shut down. To use this plugin you must set the
Installation
------------
The ``absubmit`` plugin requires the `streaming_extractor_music`_ program
to run. Its source can be found on `GitHub`_, and while it is possible to
compile the extractor from source, AcousticBrainz would prefer if you used
their binary (see the AcousticBrainz `FAQ`_).
The ``absubmit`` plugin requires the streaming_extractor_music_ program to run.
Its source can be found on GitHub_, and while it is possible to compile the
extractor from source, AcousticBrainz would prefer if you used their binary (see
the AcousticBrainz FAQ_).
Then, install ``beets`` with ``absubmit`` extra
pip install "beets[absubmit]"
Lastly, enable the plugin in your configuration (see :ref:`using-plugins`).
Lastly, enable the plugin in your configuration (see :ref:`using-plugins`).
Submitting Data
---------------
To run the analysis program and upload its results, type::
To run the analysis program and upload its results, type:
::
beet absubmit [-f] [-d] [QUERY]
By default, the command will only look for AcousticBrainz data when the tracks
don't already have it; the ``-f`` or ``--force`` switch makes it refetch
data even when it already exists. You can use the ``-d`` or ``--dry`` switch
to check which files will be analyzed, before you start a longer period
of processing.
don't already have it; the ``-f`` or ``--force`` switch makes it refetch data
even when it already exists. You can use the ``-d`` or ``--dry`` switch to check
which files will be analyzed, before you start a longer period of processing.
The plugin works on music with a MusicBrainz track ID attached. The plugin
will also skip music that the analysis tool doesn't support.
`streaming_extractor_music`_ currently supports files with the extensions
``mp3``, ``ogg``, ``oga``, ``flac``, ``mp4``, ``m4a``, ``m4r``, ``m4b``,
``m4p``, ``aac``, ``wma``, ``asf``, ``mpc``, ``wv``, ``spx``, ``tta``,
``3g2``, ``aif``, ``aiff`` and ``ape``.
The plugin works on music with a MusicBrainz track ID attached. The plugin will
also skip music that the analysis tool doesn't support.
streaming_extractor_music_ currently supports files with the extensions ``mp3``,
``ogg``, ``oga``, ``flac``, ``mp4``, ``m4a``, ``m4r``, ``m4b``, ``m4p``,
``aac``, ``wma``, ``asf``, ``mpc``, ``wv``, ``spx``, ``tta``, ``3g2``, ``aif``,
``aiff`` and ``ape``.
Configuration
-------------
@ -54,25 +54,27 @@ Configuration
To configure the plugin, make a ``absubmit:`` section in your configuration
file. The available options are:
- **auto**: Analyze every file on import. Otherwise, you need to use the
``beet absubmit`` command explicitly.
Default: ``no``
- **extractor**: The absolute path to the `streaming_extractor_music`_ binary.
- **auto**: Analyze every file on import. Otherwise, you need to use the ``beet
absubmit`` command explicitly. Default: ``no``
- **extractor**: The absolute path to the streaming_extractor_music_ binary.
Default: search for the program in your ``$PATH``
- **force**: Analyze items and submit of AcousticBrainz data even for tracks
that already have it.
Default: ``no``.
that already have it. Default: ``no``.
- **pretend**: Do not analyze and submit of AcousticBrainz data but print out
the items which would be processed.
Default: ``no``.
the items which would be processed. Default: ``no``.
- **base_url**: The base URL of the AcousticBrainz server. The plugin has no
function if this option is not set.
Default: None
function if this option is not set. Default: None
.. _acousticbrainz: https://acousticbrainz.org
.. _beets-xtractor: https://github.com/adamjakab/BeetsPluginXtractor
.. _faq: https://acousticbrainz.org/faq
.. _github: https://github.com/MTG/essentia
.. _pip: https://pip.pypa.io
.. _requests: https://requests.readthedocs.io/en/master/
.. _streaming_extractor_music: https://essentia.upf.edu/
.. _FAQ: https://acousticbrainz.org/faq
.. _pip: https://pip.pypa.io
.. _requests: https://requests.readthedocs.io/en/master/
.. _github: https://github.com/MTG/essentia
.. _AcousticBrainz: https://acousticbrainz.org
.. _beets-xtractor: https://github.com/adamjakab/BeetsPluginXtractor

View file

@ -2,51 +2,54 @@ AcousticBrainz Plugin
=====================
The ``acousticbrainz`` plugin gets acoustic-analysis information from the
`AcousticBrainz`_ project. This plugin is now deprecated since the
AcousicBrainz project has been shut down.
AcousticBrainz_ project. This plugin is now deprecated since the AcousicBrainz
project has been shut down.
As an alternative the `beets-xtractor`_ plugin can be used.
As an alternative the beets-xtractor_ plugin can be used.
.. _acousticbrainz: https://acousticbrainz.org/
.. _AcousticBrainz: https://acousticbrainz.org/
.. _beets-xtractor: https://github.com/adamjakab/BeetsPluginXtractor
Enable the ``acousticbrainz`` plugin in your configuration (see :ref:`using-plugins`) and run it by typing::
Enable the ``acousticbrainz`` plugin in your configuration (see
:ref:`using-plugins`) and run it by typing:
::
$ beet acousticbrainz [-f] [QUERY]
By default, the command will only look for AcousticBrainz data when the tracks
doesn't already have it; the ``-f`` or ``--force`` switch makes it re-download
data even when it already exists. If you specify a query, only matching tracks
will be processed; otherwise, the command processes every track in your
library.
will be processed; otherwise, the command processes every track in your library.
For all tracks with a MusicBrainz recording ID, the plugin currently sets
these fields:
For all tracks with a MusicBrainz recording ID, the plugin currently sets these
fields:
* ``average_loudness``
* ``bpm``
* ``chords_changes_rate``
* ``chords_key``
* ``chords_number_rate``
* ``chords_scale``
* ``danceable``
* ``gender``
* ``genre_rosamerica``
* ``initial_key`` (This is a built-in beets field, which can also be provided
by :doc:`/plugins/keyfinder`.)
* ``key_strength``
* ``mood_acoustic``
* ``mood_aggressive``
* ``mood_electronic``
* ``mood_happy``
* ``mood_party``
* ``mood_relaxed``
* ``mood_sad``
* ``moods_mirex``
* ``rhythm``
* ``timbre``
* ``tonal``
* ``voice_instrumental``
- ``average_loudness``
- ``bpm``
- ``chords_changes_rate``
- ``chords_key``
- ``chords_number_rate``
- ``chords_scale``
- ``danceable``
- ``gender``
- ``genre_rosamerica``
- ``initial_key`` (This is a built-in beets field, which can also be provided by
:doc:`/plugins/keyfinder`.)
- ``key_strength``
- ``mood_acoustic``
- ``mood_aggressive``
- ``mood_electronic``
- ``mood_happy``
- ``mood_party``
- ``mood_relaxed``
- ``mood_sad``
- ``moods_mirex``
- ``rhythm``
- ``timbre``
- ``tonal``
- ``voice_instrumental``
Warning
-------
@ -57,10 +60,10 @@ The AcousticBrainz project has shut down. To use this plugin you must set the
Automatic Tagging
-----------------
To automatically tag files using AcousticBrainz data during import, just
enable the ``acousticbrainz`` plugin (see :ref:`using-plugins`). When importing
new files, beets will query the AcousticBrainz API using MBID and
set the appropriate metadata.
To automatically tag files using AcousticBrainz data during import, just enable
the ``acousticbrainz`` plugin (see :ref:`using-plugins`). When importing new
files, beets will query the AcousticBrainz API using MBID and set the
appropriate metadata.
Configuration
-------------
@ -68,13 +71,10 @@ Configuration
To configure the plugin, make a ``acousticbrainz:`` section in your
configuration file. The available options are:
- **auto**: Enable AcousticBrainz during ``beet import``.
Default: ``yes``.
- **force**: Download AcousticBrainz data even for tracks that already have
it.
- **auto**: Enable AcousticBrainz during ``beet import``. Default: ``yes``.
- **force**: Download AcousticBrainz data even for tracks that already have it.
Default: ``no``.
- **tags**: Which tags from the list above to set on your files.
Default: [] (all).
- **tags**: Which tags from the list above to set on your files. Default: []
(all).
- **base_url**: The base URL of the AcousticBrainz server. The plugin has no
function if this option is not set.
Default: None
function if this option is not set. Default: None

View file

@ -1,37 +1,38 @@
Advanced Rewrite Plugin
=======================
The ``advancedrewrite`` plugin lets you easily substitute values
in your templates and path formats, similarly to the :doc:`/plugins/rewrite`.
It's recommended to read the documentation of that plugin first.
The ``advancedrewrite`` plugin lets you easily substitute values in your
templates and path formats, similarly to the :doc:`/plugins/rewrite`. It's
recommended to read the documentation of that plugin first.
The *advanced* rewrite plugin does not only support the simple rule format
of the ``rewrite`` plugin, but also an advanced format:
there, the plugin doesn't consider the value of the rewritten field,
but instead checks if the given item matches a :doc:`query </reference/query>`.
Only then, the field is replaced with the given value.
It's also possible to replace multiple fields at once,
and even supports multi-valued fields.
The *advanced* rewrite plugin does not only support the simple rule format of
the ``rewrite`` plugin, but also an advanced format: there, the plugin doesn't
consider the value of the rewritten field, but instead checks if the given item
matches a :doc:`query </reference/query>`. Only then, the field is replaced with
the given value. It's also possible to replace multiple fields at once, and even
supports multi-valued fields.
To use advanced field rewriting, first enable the ``advancedrewrite`` plugin
(see :ref:`using-plugins`).
Then, make a ``advancedrewrite:`` section in your config file to contain
your rewrite rules.
(see :ref:`using-plugins`). Then, make a ``advancedrewrite:`` section in your
config file to contain your rewrite rules.
In contrast to the normal ``rewrite`` plugin, you need to provide a list of
replacement rule objects, which can have a different syntax depending on
the rule complexity.
replacement rule objects, which can have a different syntax depending on the
rule complexity.
The simple syntax is the same as the one of the rewrite plugin and allows
to replace a single field::
The simple syntax is the same as the one of the rewrite plugin and allows to
replace a single field:
::
advancedrewrite:
- artist ODD EYE CIRCLE: 이달의 소녀 오드아이써클
The advanced syntax consists of a query to match against, as well as a map
of replacements to apply.
For example, to credit all songs of ODD EYE CIRCLE before 2023
to their original group name, you can use the following rule::
The advanced syntax consists of a query to match against, as well as a map of
replacements to apply. For example, to credit all songs of ODD EYE CIRCLE before
2023 to their original group name, you can use the following rule:
::
advancedrewrite:
- match: "mb_artistid:dec0f331-cb08-4c8e-9c9f-aeb1f0f6d88c year:..2022"
@ -39,10 +40,12 @@ to their original group name, you can use the following rule::
artist: 이달의 소녀 오드아이써클
artist_sort: LOONA / ODD EYE CIRCLE
Note how the sort name is also rewritten within the same rule.
You can specify as many fields as you'd like in the replacements map.
Note how the sort name is also rewritten within the same rule. You can specify
as many fields as you'd like in the replacements map.
If you need to work with multi-valued fields, you can use the following syntax::
If you need to work with multi-valued fields, you can use the following syntax:
::
advancedrewrite:
- match: "artist:배유빈 feat. 김미현"
@ -55,10 +58,12 @@ As a convenience, the plugin applies patterns for the ``artist`` field to the
``albumartist`` field as well. (Otherwise, you would probably want to duplicate
every rule for ``artist`` and ``albumartist``.)
Make sure to properly quote your query strings if they contain spaces,
otherwise they might not do what you expect, or even cause beets to crash.
Make sure to properly quote your query strings if they contain spaces, otherwise
they might not do what you expect, or even cause beets to crash.
Take the following example::
Take the following example:
::
advancedrewrite:
# BAD, DON'T DO THIS!
@ -69,10 +74,12 @@ Take the following example::
On the first sight, this might look sane, and replace the artist of the album
*THE ALBUM* with *New artist*. However, due to the space and missing quotes,
this query will evaluate to ``album:THE`` and match ``ALBUM`` on any field,
including ``artist``. As ``artist`` is the field being replaced,
this query will result in infinite recursion and ultimately crash beets.
including ``artist``. As ``artist`` is the field being replaced, this query will
result in infinite recursion and ultimately crash beets.
Instead, you should use the following rule::
Instead, you should use the following rule:
::
advancedrewrite:
# Note the quotes around the query string!
@ -81,11 +88,11 @@ Instead, you should use the following rule::
artist: New artist
A word of warning: This plugin theoretically only applies to templates and path
formats; it initially does not modify files' metadata tags or the values
tracked by beets' library database, but since it *rewrites all field lookups*,
it modifies the file's metadata anyway. See comments in issue :bug:`2786`.
formats; it initially does not modify files' metadata tags or the values tracked
by beets' library database, but since it *rewrites all field lookups*, it
modifies the file's metadata anyway. See comments in issue :bug:`2786`.
As an alternative to this plugin the simpler but less powerful
:doc:`/plugins/rewrite` can be used.
If you don't want to modify the item's metadata and only replace values
in file paths, you can check out the :doc:`/plugins/substitute`.
:doc:`/plugins/rewrite` can be used. If you don't want to modify the item's
metadata and only replace values in file paths, you can check out the
:doc:`/plugins/substitute`.

View file

@ -2,19 +2,19 @@ AlbumTypes Plugin
=================
The ``albumtypes`` plugin adds the ability to format and output album types,
such as "Album", "EP", "Single", etc. For the list of available album types,
see the `MusicBrainz documentation`_.
such as "Album", "EP", "Single", etc. For the list of available album types, see
the `MusicBrainz documentation`_.
To use the ``albumtypes`` plugin, enable it in your configuration
(see :ref:`using-plugins`). The plugin defines a new field ``$atypes``, which
you can use in your path formats or elsewhere.
To use the ``albumtypes`` plugin, enable it in your configuration (see
:ref:`using-plugins`). The plugin defines a new field ``$atypes``, which you can
use in your path formats or elsewhere.
.. _MusicBrainz documentation: https://musicbrainz.org/doc/Release_Group/Type
.. _musicbrainz documentation: https://musicbrainz.org/doc/Release_Group/Type
A bug introduced in beets 1.6.0 could have possibly imported broken data into
the ``albumtypes`` library field. Please follow the instructions `described
here <https://github.com/beetbox/beets/pull/4582#issuecomment-1445023493>`_ for
a sanity check and potential fix. :bug:`4528`
the ``albumtypes`` library field. Please follow the instructions `described here
<https://github.com/beetbox/beets/pull/4582#issuecomment-1445023493>`_ for a
sanity check and potential fix. :bug:`4528`
Configuration
-------------
@ -30,7 +30,9 @@ file. The available options are:
are often compilations.
- **bracket**: Defines the brackets to enclose each album type in the output.
The default configuration looks like this::
The default configuration looks like this:
::
albumtypes:
types:
@ -45,18 +47,22 @@ The default configuration looks like this::
Examples
--------
With path formats configured like::
With path formats configured like:
::
paths:
default: $albumartist/[$year]$atypes $album/...
albumtype:soundtrack: Various Artists/$album [$year]$atypes/...
comp: Various Artists/$album [$year]$atypes/...
The default plugin configuration generates paths that look like this, for
example:
The default plugin configuration generates paths that look like this, for example::
::
Aphex Twin/[1993][EP][Remix] On Remixes
Pink Floyd/[1995][Live] p·u·l·s·e
Various Artists/20th Century Lullabies [1999]
Various Artists/Ocean's Eleven [2001][OST]

View file

@ -1,13 +1,14 @@
AURA Plugin
===========
This plugin is a server implementation of the `AURA`_ specification using the
`Flask`_ framework. AURA is still a work in progress and doesn't yet have a
stable version, but this server should be kept up to date. You are advised to
read the :ref:`aura-issues` section.
This plugin is a server implementation of the AURA_ specification using the
Flask_ framework. AURA is still a work in progress and doesn't yet have a stable
version, but this server should be kept up to date. You are advised to read the
:ref:`aura-issues` section.
.. _AURA: https://auraspec.readthedocs.io
.. _Flask: https://palletsprojects.com/p/flask/
.. _aura: https://auraspec.readthedocs.io
.. _flask: https://palletsprojects.com/p/flask/
Install
-------
@ -17,18 +18,16 @@ To use the ``aura`` plugin, first enable it in your configuration (see
pip install "beets[aura]"
Usage
-----
Use ``beet aura`` to start the AURA server.
By default Flask's built-in server is used, which will give a warning about
using it in a production environment. It is safe to ignore this warning if the
server will have only a few users.
Use ``beet aura`` to start the AURA server. By default Flask's built-in server
is used, which will give a warning about using it in a production environment.
It is safe to ignore this warning if the server will have only a few users.
Alternatively, you can use ``beet aura -d`` to start the server in
`development mode`_, which will reload the server every time the AURA plugin
file is changed.
Alternatively, you can use ``beet aura -d`` to start the server in `development
mode <https://flask.palletsprojects.com/en/1.1.x/server>`__, which will reload
the server every time the AURA plugin file is changed.
You can specify the hostname and port number used by the server in your
:doc:`configuration file </reference/config>`. For more detail see the
@ -39,50 +38,48 @@ then see :ref:`aura-external-server`.
AURA is designed to separate the client and server functionality. This plugin
provides the server but not the client, so unless you like looking at JSON you
will need a separate client. Currently the only client is `AURA Web Client`_.
In order to use a local browser client with ``file:///`` see :ref:`aura-cors`.
will need a separate client. Currently the only client is `AURA Web Client`_. In
order to use a local browser client with ``file:///`` see :ref:`aura-cors`.
By default the API is served under http://127.0.0.1:8337/aura/. For example
information about the track with an id of 3 can be obtained at
http://127.0.0.1:8337/aura/tracks/3.
**Note the absence of a trailing slash**:
http://127.0.0.1:8337/aura/tracks/3/ returns a ``404 Not Found`` error.
.. _development mode: https://flask.palletsprojects.com/en/1.1.x/server
.. _AURA Web Client: https://sr.ht/~callum/aura-web-client/
**Note the absence of a trailing slash**: http://127.0.0.1:8337/aura/tracks/3/
returns a ``404 Not Found`` error.
.. _aura web client: https://sr.ht/~callum/aura-web-client/
.. _configuration:
Configuration
-------------
To configure the plugin, make an ``aura:`` section in your
configuration file. The available options are:
To configure the plugin, make an ``aura:`` section in your configuration file.
The available options are:
- **host**: The server hostname. Set this to ``0.0.0.0`` to bind to all
interfaces. Default: ``127.0.0.1``.
- **port**: The server port.
Default: ``8337``.
- **port**: The server port. Default: ``8337``.
- **cors**: A YAML list of origins to allow CORS requests from (see
:ref:`aura-cors`, below).
Default: disabled.
:ref:`aura-cors`, below). Default: disabled.
- **cors_supports_credentials**: Allow authenticated requests when using CORS.
Default: disabled.
- **page_limit**: The number of items responses should be truncated to if the
client does not specify. Default ``500``.
.. _aura-cors:
Cross-Origin Resource Sharing (CORS)
------------------------------------
`CORS`_ allows browser clients to make requests to the AURA server. You should
set the ``cors`` configuration option to a YAML list of allowed origins.
`CORS <https://en.wikipedia.org/wiki/Cross-origin_resource_sharing>`__ allows
browser clients to make requests to the AURA server. You should set the ``cors``
configuration option to a YAML list of allowed origins.
For example::
For example:
::
aura:
cors:
@ -91,24 +88,21 @@ For example::
In order to use the plugin with a local browser client accessed using
``file:///`` you must include ``'null'`` in the list of allowed origins
(including quote marks)::
(including quote marks):
::
aura:
cors:
- 'null'
Alternatively you use ``'*'`` to enable access from all origins.
Note that there are security implications if you set the origin to ``'*'``,
so please research this before using it. Note the use of quote marks when
allowing all origins.
If the server is behind a proxy that uses credentials, you might want to set
the ``cors_supports_credentials`` configuration option to true to let
in-browser clients log in. Note that this option has not been tested, so it
may not work.
.. _CORS: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
Alternatively you use ``'*'`` to enable access from all origins. Note that there
are security implications if you set the origin to ``'*'``, so please research
this before using it. Note the use of quote marks when allowing all origins.
If the server is behind a proxy that uses credentials, you might want to set the
``cors_supports_credentials`` configuration option to true to let in-browser
clients log in. Note that this option has not been tested, so it may not work.
.. _aura-external-server:
@ -119,16 +113,16 @@ If you would like to use a different WSGI server (not Flask's built-in one),
then you can! The ``beetsplug.aura`` module provides a WSGI callable called
``create_app()`` which can be used by many WSGI servers.
For example to run the AURA server using `gunicorn`_ use
``gunicorn 'beetsplug.aura:create_app()'``, or for `uWSGI`_ use
``uwsgi --http :8337 --module 'beetsplug.aura:create_app()'``.
Note that these commands just show how to use the AURA app and you would
probably use something a bit different in a production environment. Read the
relevant server's documentation to figure out what you need.
For example to run the AURA server using gunicorn_ use ``gunicorn
'beetsplug.aura:create_app()'``, or for uWSGI_ use ``uwsgi --http :8337 --module
'beetsplug.aura:create_app()'``. Note that these commands just show how to use
the AURA app and you would probably use something a bit different in a
production environment. Read the relevant server's documentation to figure out
what you need.
.. _gunicorn: https://gunicorn.org
.. _uWSGI: https://uwsgi-docs.readthedocs.io
.. _uwsgi: https://uwsgi-docs.readthedocs.io
Reverse Proxy Support
---------------------
@ -137,6 +131,8 @@ The plugin should work behind a reverse proxy without further configuration,
however this has not been tested extensively. For details of what headers must
be rewritten and a sample NGINX configuration see `Flask proxy setups`_.
.. _flask proxy setups: https://flask.palletsprojects.com/en/1.1.x/deploying/wsgi-standalone/#proxy-setups
It is (reportedly) possible to run the application under a URL prefix (for
example so you could have ``/foo/aura/server`` rather than ``/aura/server``),
but you'll have to work it out for yourself :-)
@ -145,9 +141,6 @@ If using NGINX, do **not** add a trailing slash (``/``) to the URL where the
application is running, otherwise you will get a 404. However if you are using
Apache then you **should** add a trailing slash.
.. _Flask proxy setups: https://flask.palletsprojects.com/en/1.1.x/deploying/wsgi-standalone/#proxy-setups
.. _aura-issues:
Issues
@ -160,26 +153,26 @@ implementation:
multiple ``filter`` parameters as AND. See `issue #19`_ for discussion.
- The ``bitrate`` parameter used for content negotiation is not supported.
Adding support for this is doable, but the way Flask handles acceptable MIME
types means it's a lot easier not to bother with it. This means an error
could be returned even if no transcoding was required.
types means it's a lot easier not to bother with it. This means an error could
be returned even if no transcoding was required.
It is possible that some attributes required by AURA could be absent from the
server's response if beets does not have a saved value for them. However, this
has not happened so far.
Beets fields (including flexible fields) that do not have an AURA equivalent
are not provided in any resource's attributes section, however these fields may
be used for filtering.
Beets fields (including flexible fields) that do not have an AURA equivalent are
not provided in any resource's attributes section, however these fields may be
used for filtering.
The ``mimetype`` and ``framecount`` attributes for track resources are not
supported. The first is due to beets storing the file type (e.g. ``MP3``), so
it is hard to filter by MIME type. The second is because there is no
corresponding beets field.
supported. The first is due to beets storing the file type (e.g. ``MP3``), so it
is hard to filter by MIME type. The second is because there is no corresponding
beets field.
Artists are defined by the ``artist`` field on beets Items, which means some
albums have no ``artists`` relationship. Albums only have related artists
when their beets ``albumartist`` field is the same as the ``artist`` field on
at least one of it's constituent tracks.
albums have no ``artists`` relationship. Albums only have related artists when
their beets ``albumartist`` field is the same as the ``artist`` field on at
least one of it's constituent tracks.
The only art tracked by beets is a single cover image, so only albums have
related images at the moment. This could be expanded to looking in the same

View file

@ -1,10 +1,10 @@
AutoBPM Plugin
==============
The `autobpm` plugin uses the `Librosa`_ library to calculate the BPM
of a track from its audio data and store it in the `bpm` field of your
database. It does so automatically when importing music or through
the ``beet autobpm [QUERY]`` command.
The ``autobpm`` plugin uses the Librosa_ library to calculate the BPM of a track
from its audio data and store it in the ``bpm`` field of your database. It does
so automatically when importing music or through the ``beet autobpm [QUERY]``
command.
Install
-------
@ -19,17 +19,15 @@ To use the ``autobpm`` plugin, first enable it in your configuration (see
Configuration
-------------
To configure the plugin, make a ``autobpm:`` section in your
configuration file. The available options are:
To configure the plugin, make a ``autobpm:`` section in your configuration file.
The available options are:
- **auto**: Analyze every file on import.
Otherwise, you need to use the ``beet autobpm`` command explicitly.
Default: ``yes``
- **overwrite**: Calculate a BPM even for files that already have a
`bpm` value.
Default: ``no``.
- **auto**: Analyze every file on import. Otherwise, you need to use the ``beet
autobpm`` command explicitly. Default: ``yes``
- **overwrite**: Calculate a BPM even for files that already have a ``bpm``
value. Default: ``no``.
- **beat_track_kwargs**: Any extra keyword arguments that you would like to
provide to librosa's `beat_track`_ function call, for example:
provide to librosa's beat_track_ function call, for example:
.. code-block:: yaml
@ -37,5 +35,6 @@ configuration file. The available options are:
beat_track_kwargs:
start_bpm: 160
.. _Librosa: https://github.com/librosa/librosa/
.. _beat_track: https://librosa.org/doc/latest/generated/librosa.beat.beat_track.html
.. _librosa: https://github.com/librosa/librosa/

View file

@ -11,10 +11,12 @@ First, enable the ``badfiles`` plugin (see :ref:`using-plugins`). The default
configuration defines the following default checkers, which you may need to
install yourself:
* `mp3val`_ for MP3 files
* `FLAC`_ command-line tools for FLAC files
- mp3val_ for MP3 files
- FLAC_ command-line tools for FLAC files
You can also add custom commands for a specific extension, like this::
You can also add custom commands for a specific extension, like this:
::
badfiles:
check_on_import: yes
@ -26,26 +28,33 @@ Custom commands will be run once for each file of the specified type, with the
path to the file as the last argument. Commands must return a status code
greater than zero for a file to be considered corrupt.
You can run the checkers when importing files by using the `check_on_import`
You can run the checkers when importing files by using the ``check_on_import``
option. When on, checkers will be run against every imported file and warnings
and errors will be presented when selecting a tagging option.
.. _mp3val: http://mp3val.sourceforge.net/
.. _flac: https://xiph.org/flac/
.. _mp3val: http://mp3val.sourceforge.net/
Using
-----
Type ``beet bad`` with a query according to beets' usual query syntax. For
instance, this will run a check on all songs containing the word "wolf"::
instance, this will run a check on all songs containing the word "wolf":
::
beet bad wolf
This one will run checks on a specific album::
This one will run checks on a specific album:
::
beet bad album_id:1234
Here is an example where the FLAC decoder signals a corrupt file::
Here is an example where the FLAC decoder signals a corrupt file:
::
beet bad title::^$
/tank/Music/__/00.flac: command exited with status 1
@ -54,10 +63,10 @@ Here is an example where the FLAC decoder signals a corrupt file::
state = FLAC__STREAM_DECODER_READ_FRAME
Note that the default ``mp3val`` checker is a bit verbose and can output a lot
of "stream error" messages, even for files that play perfectly well.
Generally, if more than one stream error happens, or if a stream error happens
in the middle of a file, this is a bad sign.
of "stream error" messages, even for files that play perfectly well. Generally,
if more than one stream error happens, or if a stream error happens in the
middle of a file, this is a bad sign.
By default, only errors for the bad files will be shown. In order for the
results for all of the checked files to be seen, including the uncorrupted
ones, use the ``-v`` or ``--verbose`` option.
results for all of the checked files to be seen, including the uncorrupted ones,
use the ``-v`` or ``--verbose`` option.

View file

@ -1,15 +1,17 @@
Bare-ASCII Search Plugin
========================
The ``bareasc`` plugin provides a prefixed query that searches your library using
simple ASCII character matching, with accented characters folded to their base
ASCII character. This can be useful if you want to find a track with accented
characters in the title or artist, particularly if you are not confident
you have the accents correct. It is also not unknown for the accents
The ``bareasc`` plugin provides a prefixed query that searches your library
using simple ASCII character matching, with accented characters folded to their
base ASCII character. This can be useful if you want to find a track with
accented characters in the title or artist, particularly if you are not
confident you have the accents correct. It is also not unknown for the accents
to not be correct in the database entry or wrong in the CD information.
First, enable the plugin named ``bareasc`` (see :ref:`using-plugins`).
You'll then be able to use the ``#`` prefix to use bare-ASCII matching::
First, enable the plugin named ``bareasc`` (see :ref:`using-plugins`). You'll
then be able to use the ``#`` prefix to use bare-ASCII matching:
::
$ beet ls '#dvorak'
István Kertész - REQUIEM - Dvořàk: Requiem, op.89 - Confutatis maledictis
@ -17,13 +19,16 @@ You'll then be able to use the ``#`` prefix to use bare-ASCII matching::
Command
-------
In addition to the query prefix, the plugin provides a utility ``bareasc`` command.
This command is **exactly** the same as the ``beet list`` command except that
the output is passed through the bare-ASCII transformation before being printed.
This allows you to easily check what the library data looks like in bare ASCII,
which can be useful if you are trying to work out why a query is not matching.
In addition to the query prefix, the plugin provides a utility ``bareasc``
command. This command is **exactly** the same as the ``beet list`` command
except that the output is passed through the bare-ASCII transformation before
being printed. This allows you to easily check what the library data looks like
in bare ASCII, which can be useful if you are trying to work out why a query is
not matching.
Using the same example track as above::
Using the same example track as above:
::
$ beet bareasc 'Dvořàk'
Istvan Kertesz - REQUIEM - Dvorak: Requiem, op.89 - Confutatis maledictis
@ -37,33 +42,34 @@ Notes
If the query string is all in lower case, the comparison ignores case as well as
accents.
The default ``bareasc`` prefix (``#``) is used as a comment character in some shells
so may need to be protected (for example in quotes) when typed into the command line.
The default ``bareasc`` prefix (``#``) is used as a comment character in some
shells so may need to be protected (for example in quotes) when typed into the
command line.
The bare ASCII transliteration is quite simple. It may not give the expected output
for all languages. For example, German u-umlaut ``ü`` is transformed into ASCII ``u``,
not into ``ue``.
The bare ASCII transliteration is quite simple. It may not give the expected
output for all languages. For example, German u-umlaut ``ü`` is transformed into
ASCII ``u``, not into ``ue``.
The bare ASCII transformation also changes Unicode punctuation like double quotes,
apostrophes and even some hyphens. It is often best to leave out punctuation
in the queries. Note that the punctuation changes are often not even visible
with normal terminal fonts. You can always use the ``bareasc`` command to print the
transformed entries and use a command like ``diff`` to compare with the output
from the ``list`` command.
The bare ASCII transformation also changes Unicode punctuation like double
quotes, apostrophes and even some hyphens. It is often best to leave out
punctuation in the queries. Note that the punctuation changes are often not even
visible with normal terminal fonts. You can always use the ``bareasc`` command
to print the transformed entries and use a command like ``diff`` to compare with
the output from the ``list`` command.
Configuration
-------------
To configure the plugin, make a ``bareasc:`` section in your configuration
file. The only available option is:
To configure the plugin, make a ``bareasc:`` section in your configuration file.
The only available option is:
- **prefix**: The character used to designate bare-ASCII queries.
Default: ``#``, which may need to be escaped in some shells.
- **prefix**: The character used to designate bare-ASCII queries. Default:
``#``, which may need to be escaped in some shells.
Credits
-------
The hard work in this plugin is done in Sean Burke's
`Unidecode <https://pypi.org/project/Unidecode/>`__ library.
Thanks are due to Sean and to all the people who created the Python
version and the beets extensible query architecture.
The hard work in this plugin is done in Sean Burke's `Unidecode
<https://pypi.org/project/Unidecode/>`__ library. Thanks are due to Sean and to
all the people who created the Python version and the beets extensible query
architecture.

View file

@ -1,15 +1,16 @@
Beatport Plugin
===============
The ``beatport`` plugin adds support for querying the `Beatport`_ catalogue
during the autotagging process. This can potentially be helpful for users
whose collection includes a lot of diverse electronic music releases, for which
both MusicBrainz and (to a lesser degree) `Discogs`_ show no matches.
The ``beatport`` plugin adds support for querying the Beatport_ catalogue during
the autotagging process. This can potentially be helpful for users whose
collection includes a lot of diverse electronic music releases, for which both
MusicBrainz and (to a lesser degree) Discogs_ show no matches.
.. _Discogs: https://discogs.com
.. _discogs: https://discogs.com
Installation
------------
To use the ``beatport`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install ``beets`` with ``beatport`` extra
@ -17,27 +18,29 @@ To use the ``beatport`` plugin, first enable it in your configuration (see
pip install "beets[beatport]"
You will also need to register for a `Beatport`_ account. The first time you
run the :ref:`import-cmd` command after enabling the plugin, it will ask you
to authorize with Beatport by visiting the site in a browser. On the site
you will be asked to enter your username and password to authorize beets
to query the Beatport API. You will then be displayed with a single line of
text that you should paste as a whole into your terminal. This will store the
authentication data for subsequent runs and you will not be required to repeat
the above steps.
You will also need to register for a Beatport_ account. The first time you run
the :ref:`import-cmd` command after enabling the plugin, it will ask you to
authorize with Beatport by visiting the site in a browser. On the site you will
be asked to enter your username and password to authorize beets to query the
Beatport API. You will then be displayed with a single line of text that you
should paste as a whole into your terminal. This will store the authentication
data for subsequent runs and you will not be required to repeat the above steps.
Matches from Beatport should now show up alongside matches
from MusicBrainz and other sources.
Matches from Beatport should now show up alongside matches from MusicBrainz and
other sources.
If you have a Beatport ID or a URL for a release or track you want to tag, you
can just enter one of the two at the "enter Id" prompt in the importer. You can
also search for an id like so::
also search for an id like so:
::
beet import path/to/music/library --search-id id
Configuration
-------------
This plugin can be configured like other metadata source plugins as described in :ref:`metadata-source-plugin-configuration`.
This plugin can be configured like other metadata source plugins as described in
:ref:`metadata-source-plugin-configuration`.
.. _Beatport: https://www.beatport.com/
.. _beatport: https://www.beatport.com/

View file

@ -3,23 +3,25 @@ BPD Plugin
BPD is a music player using music from a beets library. It runs as a daemon and
implements the MPD protocol, so it's compatible with all the great MPD clients
out there. I'm using `Theremin`_, `gmpc`_, `Sonata`_, and `Ario`_ successfully.
out there. I'm using Theremin_, gmpc_, Sonata_, and Ario_ successfully.
.. _ario: http://ario-player.sourceforge.net/
.. _Theremin: https://github.com/TheStalwart/Theremin
.. _gmpc: https://gmpc.wikia.com/wiki/Gnome_Music_Player_Client
.. _Sonata: http://sonata.berlios.de/
.. _Ario: http://ario-player.sourceforge.net/
.. _sonata: http://sonata.berlios.de/
.. _theremin: https://github.com/TheStalwart/Theremin
Dependencies
------------
Before you can use BPD, you'll need the media library called `GStreamer`_ (along
Before you can use BPD, you'll need the media library called GStreamer_ (along
with its Python bindings) on your system.
* On Mac OS X, you can use `Homebrew`_. Run ``brew install gstreamer
- On Mac OS X, you can use Homebrew_. Run ``brew install gstreamer
gst-plugins-base pygobject3``.
* On Linux, you need to install GStreamer 1.0 and the GObject bindings for
- On Linux, you need to install GStreamer 1.0 and the GObject bindings for
python. Under Ubuntu, they are called ``python-gi`` and ``gstreamer1.0``.
You will also need the various GStreamer plugin packages to make everything
@ -33,15 +35,17 @@ extra which installs Python bindings for ``GStreamer``:
pip install "beets[bpd]"
.. _GStreamer: https://gstreamer.freedesktop.org/download
.. _Homebrew: https://brew.sh
.. _gstreamer: https://gstreamer.freedesktop.org/download
.. _homebrew: https://brew.sh
Usage
-----
To use the ``bpd`` plugin, first enable it in your configuration (see
:ref:`using-plugins`).
Then, you can run BPD by invoking::
:ref:`using-plugins`). Then, you can run BPD by invoking:
::
$ beet bpd
@ -50,15 +54,12 @@ long list of available clients`_. Here are my favorites:
.. _a long list of available clients: https://mpd.wikia.com/wiki/Clients
* Linux: `gmpc`_, `Sonata`_
- Linux: gmpc_, Sonata_
- Mac: Theremin_
- Windows: I don't know. Get in touch if you have a recommendation.
- iPhone/iPod touch: Rigelian_
* Mac: `Theremin`_
* Windows: I don't know. Get in touch if you have a recommendation.
* iPhone/iPod touch: `Rigelian`_
.. _Rigelian: https://www.rigelian.net/
.. _rigelian: https://www.rigelian.net/
One nice thing about MPD's (and thus BPD's) client-server architecture is that
the client can just as easily on a different computer from the server as it can
@ -68,21 +69,18 @@ on your headless server box. Rad!
Configuration
-------------
To configure the plugin, make a ``bpd:`` section in your configuration file.
The available options are:
To configure the plugin, make a ``bpd:`` section in your configuration file. The
available options are:
- **host**:
Default: Bind to all interfaces.
- **port**:
Default: 6600
- **password**:
Default: No password.
- **volume**: Initial volume, as a percentage.
Default: 100
- **control_port**: Port for the internal control socket.
Default: 6601
- **host**: Default: Bind to all interfaces.
- **port**: Default: 6600
- **password**: Default: No password.
- **volume**: Initial volume, as a percentage. Default: 100
- **control_port**: Port for the internal control socket. Default: 6601
Here's an example::
Here's an example:
::
bpd:
host: 127.0.0.1
@ -93,49 +91,49 @@ Here's an example::
Implementation Notes
--------------------
In the real MPD, the user can browse a music directory as it appears on disk.
In beets, we like to abstract away from the directory structure. Therefore, BPD
In the real MPD, the user can browse a music directory as it appears on disk. In
beets, we like to abstract away from the directory structure. Therefore, BPD
creates a "virtual" directory structure (artist/album/track) to present to
clients. This is static for now and cannot be reconfigured like the real
on-disk directory structure can. (Note that an obvious solution to this is just
string matching on items' destination, but this requires examining the entire
library Python-side for every query.)
clients. This is static for now and cannot be reconfigured like the real on-disk
directory structure can. (Note that an obvious solution to this is just string
matching on items' destination, but this requires examining the entire library
Python-side for every query.)
BPD plays music using GStreamer's ``playbin`` player, which has a simple API
but doesn't support many advanced playback features.
BPD plays music using GStreamer's ``playbin`` player, which has a simple API but
doesn't support many advanced playback features.
Differences from the real MPD
-----------------------------
BPD currently supports version 0.16 of `the MPD protocol`_, but several of the
commands and features are "pretend" implementations or have slightly different
behaviour to their MPD equivalents. BPD aims to look enough like MPD that it
can interact with the ecosystem of clients, but doesn't try to be
a fully-fledged MPD replacement in terms of its playback capabilities.
behaviour to their MPD equivalents. BPD aims to look enough like MPD that it can
interact with the ecosystem of clients, but doesn't try to be a fully-fledged
MPD replacement in terms of its playback capabilities.
.. _the MPD protocol: https://www.musicpd.org/doc/protocol/
.. _the mpd protocol: https://www.musicpd.org/doc/protocol/
These are some of the known differences between BPD and MPD:
* BPD doesn't currently support versioned playlists. Many clients, however, use
- BPD doesn't currently support versioned playlists. Many clients, however, use
plchanges instead of playlistinfo to get the current playlist, so plchanges
contains a dummy implementation that just calls playlistinfo.
* Stored playlists aren't supported (BPD understands the commands though).
* The ``stats`` command always send zero for ``playtime``, which is supposed to
- Stored playlists aren't supported (BPD understands the commands though).
- The ``stats`` command always send zero for ``playtime``, which is supposed to
indicate the amount of time the server has spent playing music. BPD doesn't
currently keep track of this.
* The ``update`` command regenerates the directory tree from the beets database
- The ``update`` command regenerates the directory tree from the beets database
synchronously, whereas MPD does this in the background.
* Advanced playback features like cross-fade, ReplayGain and MixRamp are not
- Advanced playback features like cross-fade, ReplayGain and MixRamp are not
supported due to BPD's simple audio player backend.
* Advanced query syntax is not currently supported.
* Clients can't use the ``tagtypes`` mask to hide fields.
* BPD's ``random`` mode is not deterministic and doesn't support priorities.
* Mounts and streams are not supported. BPD can only play files from disk.
* Stickers are not supported (although this is basically a flexattr in beets
- Advanced query syntax is not currently supported.
- Clients can't use the ``tagtypes`` mask to hide fields.
- BPD's ``random`` mode is not deterministic and doesn't support priorities.
- Mounts and streams are not supported. BPD can only play files from disk.
- Stickers are not supported (although this is basically a flexattr in beets
nomenclature so this is feasible to add).
* There is only a single password, and is enabled it grants access to all
- There is only a single password, and is enabled it grants access to all
features rather than having permissions-based granularity.
* Partitions and alternative outputs are not supported; BPD can only play one
- Partitions and alternative outputs are not supported; BPD can only play one
song at a time.
* Client channels are not implemented.
- Client channels are not implemented.

View file

@ -10,17 +10,21 @@ Usage
To use the ``bpm`` plugin, first enable it in your configuration (see
:ref:`using-plugins`).
Then, play a song you want to measure in your favorite media player and type::
Then, play a song you want to measure in your favorite media player and type:
beet bpm <song>
::
beet bpm <song>
You'll be prompted to press Enter three times to the rhythm. This typically
allows to determine the BPM within 5% accuracy.
The plugin works best if you wrap it in a script that gets the playing song.
for instance, with ``mpc`` you can do something like::
The plugin works best if you wrap it in a script that gets the playing song. for
instance, with ``mpc`` you can do something like:
beet bpm $(mpc |head -1|tr -d "-")
::
beet bpm $(mpc |head -1|tr -d "-")
If :ref:`import.write <config-import-write>` is ``yes``, the song's tags are
written to disk.
@ -28,14 +32,12 @@ written to disk.
Configuration
-------------
To configure the plugin, make a ``bpm:`` section in your configuration file.
The available options are:
To configure the plugin, make a ``bpm:`` section in your configuration file. The
available options are:
- **max_strokes**: The maximum number of strokes to accept when tapping out the
BPM.
Default: 3.
- **overwrite**: Overwrite the track's existing BPM.
Default: ``yes``.
BPM. Default: 3.
- **overwrite**: Overwrite the track's existing BPM. Default: ``yes``.
Credit
------

View file

@ -1,15 +1,13 @@
BPSync Plugin
=============
This plugin provides the ``bpsync`` command, which lets you fetch metadata
from Beatport for albums and tracks that already have Beatport IDs.
This plugin works similarly to :doc:`/plugins/mbsync`.
If you have downloaded music from Beatport, this can speed
up the initial import if you just import "as-is" and then use ``bpsync`` to
get up-to-date tags that are written to the files according to your beets
configuration.
This plugin provides the ``bpsync`` command, which lets you fetch metadata from
Beatport for albums and tracks that already have Beatport IDs. This plugin works
similarly to :doc:`/plugins/mbsync`.
If you have downloaded music from Beatport, this can speed up the initial import
if you just import "as-is" and then use ``bpsync`` to get up-to-date tags that
are written to the files according to your beets configuration.
Usage
-----
@ -18,17 +16,17 @@ Enable the ``bpsync`` plugin in your configuration (see :ref:`using-plugins`)
and then run ``beet bpsync QUERY`` to fetch updated metadata for a part of your
collection (or omit the query to run over your whole library).
This plugin treats albums and singletons (non-album tracks) separately. It
first processes all matching singletons and then proceeds on to full albums.
The same query is used to search for both kinds of entities.
This plugin treats albums and singletons (non-album tracks) separately. It first
processes all matching singletons and then proceeds on to full albums. The same
query is used to search for both kinds of entities.
The command has a few command-line options:
* To preview the changes that would be made without applying them, use the
- To preview the changes that would be made without applying them, use the
``-p`` (``--pretend``) flag.
* By default, files will be moved (renamed) according to their metadata if
they are inside your beets library directory. To disable this, use the
``-M`` (``--nomove``) command-line option.
* If you have the ``import.write`` configuration option enabled, then this
plugin will write new metadata to files' tags. To disable this, use the
``-W`` (``--nowrite``) option.
- By default, files will be moved (renamed) according to their metadata if they
are inside your beets library directory. To disable this, use the ``-M``
(``--nomove``) command-line option.
- If you have the ``import.write`` configuration option enabled, then this
plugin will write new metadata to files' tags. To disable this, use the ``-W``
(``--nowrite``) option.

View file

@ -8,14 +8,17 @@ smaller subfolders by grouping albums or artists alphabetically (e.g. *A-F*,
*G-M*, *N-Z*).
To use the ``bucket`` plugin, first enable it in your configuration (see
:ref:`using-plugins`).
The plugin provides a :ref:`template function
<template-functions>` called ``%bucket`` for use in path format expressions::
:ref:`using-plugins`). The plugin provides a :ref:`template function
<template-functions>` called ``%bucket`` for use in path format expressions:
::
paths:
default: /%bucket{$year}/%bucket{$artist}/$albumartist-$album-$year
Then, define your ranges in the ``bucket:`` section of the config file::
Then, define your ranges in the ``bucket:`` section of the config file:
::
bucket:
bucket_alpha: ['A-F', 'G-M', 'N-Z']
@ -30,17 +33,16 @@ The definition of a range is somewhat loose, and multiple formats are allowed:
alphanumeric characters in the string you provide. For example, ``ABCD``,
``A-D``, ``A->D``, and ``[AD]`` are all equivalent.
- For year ranges: digits characters are extracted and the two extreme years
define the range. For example, ``1975-77``, ``1975,76,77`` and ``1975-1977`` are
equivalent. If no upper bound is given, the range is extended to current year
(unless a later range is defined). For example, ``1975`` encompasses all years
from 1975 until now.
define the range. For example, ``1975-77``, ``1975,76,77`` and ``1975-1977``
are equivalent. If no upper bound is given, the range is extended to current
year (unless a later range is defined). For example, ``1975`` encompasses all
years from 1975 until now.
The ``%bucket`` template function guesses whether to use alpha- or year-style
buckets depending on the text it receives. It can guess wrong if, for example,
an artist or album happens to begin with four digits. Provide ``alpha`` as the
second argument to the template to avoid this automatic detection: for
example, use ``%bucket{$artist,alpha}``.
second argument to the template to avoid this automatic detection: for example,
use ``%bucket{$artist,alpha}``.
Configuration
-------------
@ -49,29 +51,28 @@ To configure the plugin, make a ``bucket:`` section in your configuration file.
The available options are:
- **bucket_alpha**: Ranges to use for all substitutions occurring on textual
fields.
Default: none.
fields. Default: none.
- **bucket_alpha_regex**: A ``range: regex`` mapping (one per line) where
``range`` is one of the `bucket_alpha` ranges and ``value`` is a regex that
overrides original range definition.
Default: none.
``range`` is one of the ``bucket_alpha`` ranges and ``value`` is a regex that
overrides original range definition. Default: none.
- **bucket_year**: Ranges to use for all substitutions occurring on the
``$year`` field.
Default: none.
``$year`` field. Default: none.
- **extrapolate**: Enable this if you want to group your files into multiple
year ranges without enumerating them all. This option will generate year
bucket names by reproducing characteristics of declared buckets.
Default: ``no``
bucket names by reproducing characteristics of declared buckets. Default:
``no``
Here's an example::
Here's an example:
bucket:
bucket_year: ['2000-05']
extrapolate: true
bucket_alpha: ['A - D', 'E - L', 'M - R', 'S - Z']
bucket_alpha_regex:
'A - D': ^[0-9a-dA-D…äÄ]
::
This configuration creates five-year ranges for any input year.
The `A - D` bucket now matches also all artists starting with ä or Ä and 0 to 9
and … (ellipsis). The other alpha buckets work as ranges.
bucket:
bucket_year: ['2000-05']
extrapolate: true
bucket_alpha: ['A - D', 'E - L', 'M - R', 'S - Z']
bucket_alpha_regex:
'A - D': ^[0-9a-dA-D…äÄ]
This configuration creates five-year ranges for any input year. The ``A - D``
bucket now matches also all artists starting with ä or Ä and 0 to 9 and …
(ellipsis). The other alpha buckets work as ranges.

View file

@ -4,18 +4,19 @@ Chromaprint/Acoustid Plugin
Acoustic fingerprinting is a technique for identifying songs from the way they
"sound" rather from their existing metadata. That means that beets' autotagger
can theoretically use fingerprinting to tag files that don't have any ID3
information at all (or have completely incorrect data). This plugin uses an
open-source fingerprinting technology called `Chromaprint`_ and its associated
Web service, called `Acoustid`_.
information at all (or have completely incorrect data). This plugin uses an
open-source fingerprinting technology called Chromaprint_ and its associated Web
service, called Acoustid_.
.. _Chromaprint: https://acoustid.org/chromaprint
.. _acoustid: https://acoustid.org/
.. _chromaprint: https://acoustid.org/chromaprint
Turning on fingerprinting can increase the accuracy of the
autotagger---especially on files with very poor metadata---but it comes at a
cost. First, it can be trickier to set up than beets itself (you need to set up
the native fingerprinting library, whereas all of the beets core is written in
pure Python). Also, fingerprinting takes significantly more CPU and memory than
pure Python). Also, fingerprinting takes significantly more CPU and memory than
ordinary tagging---which means that imports will go substantially slower.
If you're willing to pay the performance cost for fingerprinting, read on!
@ -23,80 +24,83 @@ If you're willing to pay the performance cost for fingerprinting, read on!
Installing Dependencies
-----------------------
To get fingerprinting working, you'll need to install three things:
To get fingerprinting working, you'll need to install three things:
1. `pyacoustid`_ Python library (version 0.6 or later). You can install it by
1. pyacoustid_ Python library (version 0.6 or later). You can install it by
installing ``beets`` with ``chroma`` extra
.. code-block:: bash
pip install "beets[chroma]"
2. the `Chromaprint`_ library_ or |command-line-tool|_
2. the Chromaprint_ library_ or |command-line-tool|_
3. an |audio-decoder|_
.. |command-line-tool| replace:: command line tool
.. |audio-decoder| replace:: audio decoder
.. |audio-decoder| replace:: audio decoder
.. _command-line-tool:
Installing the Binary Command-Line Tool
'''''''''''''''''''''''''''''''''''''''
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The simplest way to get up and running, especially on Windows, is to
`download`_ the appropriate Chromaprint binary package and place the
``fpcalc`` (or ``fpcalc.exe``) on your shell search path. On Windows, this
means something like ``C:\\Program Files``. On OS X or Linux, put the
executable somewhere like ``/usr/local/bin``.
The simplest way to get up and running, especially on Windows, is to download_
the appropriate Chromaprint binary package and place the ``fpcalc`` (or
``fpcalc.exe``) on your shell search path. On Windows, this means something like
``C:\\Program Files``. On OS X or Linux, put the executable somewhere like
``/usr/local/bin``.
.. _download: https://acoustid.org/chromaprint
.. _library:
Installing the Library
''''''''''''''''''''''
~~~~~~~~~~~~~~~~~~~~~~
On OS X and Linux, you can also use a library installed by your package
manager, which has some advantages (automatic upgrades, etc.). The Chromaprint
site has links to packages for major Linux distributions. If you use
`Homebrew`_ on Mac OS X, you can install the library with ``brew install
chromaprint``.
.. _Homebrew: https://brew.sh/
On OS X and Linux, you can also use a library installed by your package manager,
which has some advantages (automatic upgrades, etc.). The Chromaprint site has
links to packages for major Linux distributions. If you use Homebrew_ on Mac OS
X, you can install the library with ``brew install chromaprint``.
.. _audio-decoder:
.. _homebrew: https://brew.sh/
Audio Decoder
'''''''''''''
~~~~~~~~~~~~~
You will also need a mechanism for decoding audio files supported by the
`audioread`_ library:
audioread_ library:
* OS X has a number of decoders already built into Core Audio, so there's no
- OS X has a number of decoders already built into Core Audio, so there's no
need to install anything.
* On Linux, you can install `GStreamer`_ with `PyGObject`_, `FFmpeg`_, or
`MAD`_ with `pymad`_. How you install these will depend on your
distribution.
For example, on Ubuntu, run ``apt-get install gstreamer1.0 python-gi``. On
Arch Linux, you want ``pacman -S gstreamer python2-gobject``. If you use
GStreamer, be sure to install its codec plugins also (``gst-plugins-good``,
etc.).
- On Linux, you can install GStreamer_ with PyGObject_, FFmpeg_, or MAD_ with
pymad_. How you install these will depend on your distribution. For example,
on Ubuntu, run ``apt-get install gstreamer1.0 python-gi``. On Arch Linux, you
want ``pacman -S gstreamer python2-gobject``. If you use GStreamer, be sure to
install its codec plugins also (``gst-plugins-good``, etc.).
Note that if you install beets in a virtualenv, you'll need it to have
``--system-site-packages`` enabled for Python to see the GStreamer bindings.
* On Windows, builds are provided by `GStreamer`_
- On Windows, builds are provided by GStreamer_
.. _audioread: https://github.com/beetbox/audioread
.. _core audio: https://developer.apple.com/technologies/mac/audio-and-video.html
.. _ffmpeg: https://ffmpeg.org/
.. _gstreamer: https://gstreamer.freedesktop.org/
.. _mad: https://www.underbit.com/products/mad/
.. _pyacoustid: https://github.com/beetbox/pyacoustid
.. _FFmpeg: https://ffmpeg.org/
.. _pygobject: https://wiki.gnome.org/Projects/PyGObject
.. _pymad: https://spacepants.org/src/pymad/
.. _MAD: https://www.underbit.com/products/mad/
.. _Core Audio: https://developer.apple.com/technologies/mac/audio-and-video.html
.. _Gstreamer: https://gstreamer.freedesktop.org/
.. _PyGObject: https://wiki.gnome.org/Projects/PyGObject
To decode audio formats (MP3, FLAC, etc.) with GStreamer, you'll need the
standard set of Gstreamer plugins. For example, on Ubuntu, install the packages
@ -107,16 +111,16 @@ Usage
-----
Once you have all the dependencies sorted out, enable the ``chroma`` plugin in
your configuration (see :ref:`using-plugins`) to benefit from fingerprinting
the next time you run ``beet import``. (The plugin doesn't produce any obvious
output by default. If you want to confirm that it's enabled, you can try
running in verbose mode once with ``beet -v import``.)
your configuration (see :ref:`using-plugins`) to benefit from fingerprinting the
next time you run ``beet import``. (The plugin doesn't produce any obvious
output by default. If you want to confirm that it's enabled, you can try running
in verbose mode once with ``beet -v import``.)
You can also use the ``beet fingerprint`` command to generate fingerprints for
items already in your library. (Provide a query to fingerprint a subset of your
library.) The generated fingerprints will be stored in the library database.
If you have the ``import.write`` config option enabled, they will also be
written to files' metadata.
library.) The generated fingerprints will be stored in the library database. If
you have the ``import.write`` config option enabled, they will also be written
to files' metadata.
.. _submitfp:
@ -125,7 +129,9 @@ Configuration
There is one configuration option in the ``chroma:`` section, ``auto``, which
controls whether to fingerprint files during the import process. To disable
fingerprint-based autotagging, set it to ``no``, like so::
fingerprint-based autotagging, set it to ``no``, like so:
::
chroma:
auto: no
@ -133,11 +139,13 @@ fingerprint-based autotagging, set it to ``no``, like so::
Submitting Fingerprints
-----------------------
You can help expand the `Acoustid`_ database by submitting fingerprints for the
You can help expand the Acoustid_ database by submitting fingerprints for the
music in your collection. To do this, first `get an API key`_ from the Acoustid
service. Just use an OpenID or MusicBrainz account to log in and you'll get a
short token string. Then, add the key to your ``config.yaml`` as the
value ``apikey`` in a section called ``acoustid`` like so::
short token string. Then, add the key to your ``config.yaml`` as the value
``apikey`` in a section called ``acoustid`` like so:
::
acoustid:
apikey: AbCd1234
@ -146,4 +154,4 @@ Then, run ``beet submit``. (You can also provide a query to submit a subset of
your library.) The command will use stored fingerprints if they're available;
otherwise it will fingerprint each file before submitting it.
.. _get an API key: https://acoustid.org/api-key
.. _get an api key: https://acoustid.org/api-key

View file

@ -1,44 +1,40 @@
Convert Plugin
==============
The ``convert`` plugin lets you convert parts of your collection to a
directory of your choice, transcoding audio and embedding album art along the
way. It can transcode to and from any format using a configurable command
line. Optionally an m3u playlist file containing all the converted files can be
saved to the destination path.
The ``convert`` plugin lets you convert parts of your collection to a directory
of your choice, transcoding audio and embedding album art along the way. It can
transcode to and from any format using a configurable command line. Optionally
an m3u playlist file containing all the converted files can be saved to the
destination path.
Installation
------------
To use the ``convert`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). By default, the plugin depends on `FFmpeg`_ to
transcode the audio, so you might want to install it.
.. _FFmpeg: https://ffmpeg.org
:ref:`using-plugins`). By default, the plugin depends on FFmpeg_ to transcode
the audio, so you might want to install it.
.. _ffmpeg: https://ffmpeg.org
Usage
-----
To convert a part of your collection, run ``beet convert QUERY``. The
command will transcode all the files matching the query to the
destination directory given by the ``-d`` (``--dest``) option or the
``dest`` configuration. The path layout mirrors that of your library,
but it may be customized through the ``paths`` configuration. Files
that have been previously converted---and thus already exist in the
destination directory---will be skipped.
To convert a part of your collection, run ``beet convert QUERY``. The command
will transcode all the files matching the query to the destination directory
given by the ``-d`` (``--dest``) option or the ``dest`` configuration. The path
layout mirrors that of your library, but it may be customized through the
``paths`` configuration. Files that have been previously converted---and thus
already exist in the destination directory---will be skipped.
The plugin uses a command-line program to transcode the audio. With the
``-f`` (``--format``) option you can choose the transcoding command
and customize the available commands
:ref:`through the configuration <convert-format-config>`.
The plugin uses a command-line program to transcode the audio. With the ``-f``
(``--format``) option you can choose the transcoding command and customize the
available commands :ref:`through the configuration <convert-format-config>`.
Unless the ``-y`` (``--yes``) flag is set, the command will list all
the items to be converted and ask for your confirmation.
Unless the ``-y`` (``--yes``) flag is set, the command will list all the items
to be converted and ask for your confirmation.
The ``-a`` (or ``--album``) option causes the command
to match albums instead of tracks.
The ``-a`` (or ``--album``) option causes the command to match albums instead of
tracks.
By default, the command places converted files into the destination directory
and leaves your library pristine. To instead back up your original files into
@ -51,18 +47,18 @@ them.
By default, files that do not need to be transcoded will be copied to their
destination. Passing the ``-l`` (``--link``) flag creates symbolic links
instead, passing ``-H`` (``--hardlink``) creates hard links.
Note that album art embedding is disabled for files that are linked.
Refer to the ``link`` and ``hardlink`` options below.
instead, passing ``-H`` (``--hardlink``) creates hard links. Note that album art
embedding is disabled for files that are linked. Refer to the ``link`` and
``hardlink`` options below.
The ``-m`` (or ``--playlist``) option enables the plugin to create an m3u8
playlist file in the destination folder given by the ``-d`` (``--dest``) option
or the ``dest`` configuration. The path to the playlist file can either be
absolute or relative to the ``dest`` directory. The contents will always be
relative paths to media files, which tries to ensure compatibility when read
from external drives or on computers other than the one used for the
conversion. There is one caveat though: A list generated on Unix/macOS can't be
read on Windows and vice versa.
from external drives or on computers other than the one used for the conversion.
There is one caveat though: A list generated on Unix/macOS can't be read on
Windows and vice versa.
Depending on the beets user's settings a generated playlist potentially could
contain unicode characters. This is supported, playlists are written in `M3U8
@ -71,31 +67,31 @@ format`_.
Configuration
-------------
To configure the plugin, make a ``convert:`` section in your configuration
file. The available options are:
To configure the plugin, make a ``convert:`` section in your configuration file.
The available options are:
- **auto**: Import transcoded versions of your files automatically during
imports. With this option enabled, the importer will transcode all (in the
default configuration) non-MP3 files over the maximum bitrate before adding
them to your library.
Default: ``no``.
them to your library. Default: ``no``.
- **auto_keep**: Convert your files automatically on import to **dest** but
import the non transcoded version. It uses the default format you have
defined in your config file.
Default: ``no``.
import the non transcoded version. It uses the default format you have defined
in your config file. Default: ``no``.
.. note:: You probably want to use only one of the `auto` and `auto_keep`
options, not both. Enabling both will convert your files twice on import,
which you probably don't want.
.. note::
You probably want to use only one of the ``auto`` and ``auto_keep``
options, not both. Enabling both will convert your files twice on import,
which you probably don't want.
- **tmpdir**: The directory where temporary files will be stored during import.
Default: none (system default),
- **copy_album_art**: Copy album art when copying or transcoding albums matched
using the ``-a`` option. Default: ``no``.
- **album_art_maxwidth**: Downscale album art if it's too big. The resize
operation reduces image width to at most ``maxwidth`` pixels while
preserving the aspect ratio. The specified image size will apply to both
embedded album art and external image files.
operation reduces image width to at most ``maxwidth`` pixels while preserving
the aspect ratio. The specified image size will apply to both embedded album
art and external image files.
- **dest**: The directory where the files will be converted (or copied) to.
Default: none.
- **embed**: Embed album art in converted items. Default: ``yes``.
@ -103,64 +99,61 @@ file. The available options are:
``inherit``.
- **max_bitrate**: By default, the plugin does not transcode files that are
already in the destination format. This option instead also transcodes files
with high bitrates, even if they are already in the same format as the
output. Note that this does not guarantee that all converted files will have
a lower bitrate---that depends on the encoder and its configuration.
Default: none.
with high bitrates, even if they are already in the same format as the output.
Note that this does not guarantee that all converted files will have a lower
bitrate---that depends on the encoder and its configuration. Default: none.
- **no_convert**: Does not transcode items matching the query string provided
(see :doc:`/reference/query`). For example, to not convert AAC or WMA formats, you can use ``format:AAC, format:WMA`` or
``path::\.(m4a|wma)$``. If you only want to transcode WMA format, you can use a negative query, e.g., ``^path::\.(wma)$``, to not convert any other format except WMA.
(see :doc:`/reference/query`). For example, to not convert AAC or WMA formats,
you can use ``format:AAC, format:WMA`` or ``path::\.(m4a|wma)$``. If you only
want to transcode WMA format, you can use a negative query, e.g.,
``^path::\.(wma)$``, to not convert any other format except WMA.
- **never_convert_lossy_files**: Cross-conversions between lossy codecs---such
as mp3, ogg vorbis, etc.---makes little sense as they will decrease quality
even further. If set to ``yes``, lossy files are always copied.
Default: ``no``.
- **paths**: The directory structure and naming scheme for the converted
files. Uses the same format as the top-level ``paths`` section (see
:ref:`path-format-config`).
Default: Reuse your top-level path format settings.
even further. If set to ``yes``, lossy files are always copied. Default:
``no``.
- **paths**: The directory structure and naming scheme for the converted files.
Uses the same format as the top-level ``paths`` section (see
:ref:`path-format-config`). Default: Reuse your top-level path format
settings.
- **quiet**: Prevent the plugin from announcing every file it processes.
Default: ``false``.
- **threads**: The number of threads to use for parallel encoding.
By default, the plugin will detect the number of processors available and use
them all.
- **threads**: The number of threads to use for parallel encoding. By default,
the plugin will detect the number of processors available and use them all.
- **link**: By default, files that do not need to be transcoded will be copied
to their destination. This option creates symbolic links instead. Note that
options such as ``embed`` that modify the output files after the transcoding
step will cause the original files to be modified as well if ``link`` is
enabled. For this reason, album-art embedding is disabled
for files that are linked.
Default: ``false``.
- **hardlink**: This options works similar to ``link``, but it creates
hard links instead of symlinks.
This option overrides ``link``. Only works when converting to a directory
on the same filesystem as the library.
Default: ``false``.
- **delete_originals**: Transcoded files will be copied or moved to their destination, depending on the import configuration. By default, the original files are not modified by the plugin. This option deletes the original files after the transcoding step has completed.
Default: ``false``.
enabled. For this reason, album-art embedding is disabled for files that are
linked. Default: ``false``.
- **hardlink**: This options works similar to ``link``, but it creates hard
links instead of symlinks. This option overrides ``link``. Only works when
converting to a directory on the same filesystem as the library. Default:
``false``.
- **delete_originals**: Transcoded files will be copied or moved to their
destination, depending on the import configuration. By default, the original
files are not modified by the plugin. This option deletes the original files
after the transcoding step has completed. Default: ``false``.
- **playlist**: The name of a playlist file that should be written on each run
of the plugin. A relative file path (e.g `playlists/mylist.m3u8`) is allowed
as well. The final destination of the playlist file will always be relative
to the destination path (``dest``, ``--dest``, ``-d``). This configuration is
overridden by the ``-m`` (``--playlist``) command line option.
Default: none.
of the plugin. A relative file path (e.g ``playlists/mylist.m3u8``) is allowed
as well. The final destination of the playlist file will always be relative to
the destination path (``dest``, ``--dest``, ``-d``). This configuration is
overridden by the ``-m`` (``--playlist``) command line option. Default: none.
You can also configure the format to use for transcoding (see the next
section):
You can also configure the format to use for transcoding (see the next section):
- **format**: The name of the format to transcode to when none is specified on
the command line.
Default: ``mp3``.
the command line. Default: ``mp3``.
- **formats**: A set of formats and associated command lines for transcoding
each.
.. _convert-format-config:
Configuring the transcoding command
```````````````````````````````````
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can customize the transcoding command through the ``formats`` map
and select a command with the ``--format`` command-line option or the
``format`` configuration.
You can customize the transcoding command through the ``formats`` map and select
a command with the ``--format`` command-line option or the ``format``
configuration.
::
@ -172,25 +165,25 @@ and select a command with the ``--format`` command-line option or the
extension: spx
wav: ffmpeg -i $source -y -acodec pcm_s16le $dest
In this example ``beet convert`` will use the *speex* command by
default. To convert the audio to `wav`, run ``beet convert -f wav``.
This will also use the format key (``wav``) as the file extension.
In this example ``beet convert`` will use the *speex* command by default. To
convert the audio to ``wav``, run ``beet convert -f wav``. This will also use
the format key (``wav``) as the file extension.
Each entry in the ``formats`` map consists of a key (the name of the
format) as well as the command and optionally the file extension.
``extension`` is the filename extension to be used for newly transcoded
files. If only the command is given as a string or the extension is not
provided, the file extension defaults to the format's name. ``command`` is the
command to use to transcode audio. The tokens ``$source`` and ``$dest`` in the
command are replaced with the paths to the existing and new file.
Each entry in the ``formats`` map consists of a key (the name of the format) as
well as the command and optionally the file extension. ``extension`` is the
filename extension to be used for newly transcoded files. If only the command is
given as a string or the extension is not provided, the file extension defaults
to the format's name. ``command`` is the command to use to transcode audio. The
tokens ``$source`` and ``$dest`` in the command are replaced with the paths to
the existing and new file.
The plugin in comes with default commands for the most common audio
formats: `mp3`, `alac`, `flac`, `aac`, `opus`, `ogg`, `wma`. For
details have a look at the output of ``beet config -d``.
The plugin in comes with default commands for the most common audio formats:
``mp3``, ``alac``, ``flac``, ``aac``, ``opus``, ``ogg``, ``wma``. For details
have a look at the output of ``beet config -d``.
For a one-command-fits-all solution use the ``convert.command`` and
``convert.extension`` options. If these are set, the formats are ignored
and the given command is used for all conversions.
``convert.extension`` options. If these are set, the formats are ignored and the
given command is used for all conversions.
::
@ -198,31 +191,38 @@ and the given command is used for all conversions.
command: ffmpeg -i $source -y -vn -aq 2 $dest
extension: mp3
Gapless MP3 encoding
````````````````````
~~~~~~~~~~~~~~~~~~~~
While FFmpeg cannot produce "`gapless`_" MP3s by itself, you can create them
by using `LAME`_ directly. Use a shell script like this to pipe the output of
FFmpeg into the LAME tool::
While FFmpeg cannot produce "gapless_" MP3s by itself, you can create them by
using LAME_ directly. Use a shell script like this to pipe the output of FFmpeg
into the LAME tool:
::
#!/bin/sh
ffmpeg -i "$1" -f wav - | lame -V 2 --noreplaygain - "$2"
Then configure the ``convert`` plugin to use the script::
Then configure the ``convert`` plugin to use the script:
::
convert:
command: /path/to/script.sh $source $dest
extension: mp3
This strategy configures FFmpeg to produce a WAV file with an accurate length
header for LAME to use. Using ``--noreplaygain`` disables gain analysis; you
can use the :doc:`/plugins/replaygain` to do this analysis. See the LAME
`documentation`_ and the `HydrogenAudio wiki`_ for other LAME configuration
header for LAME to use. Using ``--noreplaygain`` disables gain analysis; you can
use the :doc:`/plugins/replaygain` to do this analysis. See the LAME
documentation_ and the `HydrogenAudio wiki`_ for other LAME configuration
options and a thorough discussion of MP3 encoding.
.. _documentation: https://lame.sourceforge.io/index.php
.. _HydrogenAudio wiki: https://wiki.hydrogenaud.io/index.php?title=LAME
.. _gapless: https://wiki.hydrogenaud.io/index.php?title=Gapless_playback
.. _LAME: https://lame.sourceforge.io/index.php
.. _M3U8 format: https://en.wikipedia.org/wiki/M3U#M3U8
.. _hydrogenaudio wiki: https://wiki.hydrogenaud.io/index.php?title=LAME
.. _lame: https://lame.sourceforge.io/index.php
.. _m3u8 format: https://en.wikipedia.org/wiki/M3U#M3U8

View file

@ -1,20 +1,24 @@
Deezer Plugin
==============
=============
The ``deezer`` plugin provides metadata matches for the importer using the
`Deezer`_ `Album`_ and `Track`_ APIs.
Deezer_ Album_ and Track_ APIs.
.. _Deezer: https://www.deezer.com
.. _Album: https://developers.deezer.com/api/album
.. _Track: https://developers.deezer.com/api/track
.. _album: https://developers.deezer.com/api/album
.. _deezer: https://www.deezer.com
.. _track: https://developers.deezer.com/api/track
Basic Usage
-----------
First, enable the ``deezer`` plugin (see :ref:`using-plugins`).
You can enter the URL for an album or song on Deezer at the ``enter Id``
prompt during import::
You can enter the URL for an album or song on Deezer at the ``enter Id`` prompt
during import:
::
Enter search, enter Id, aBort, eDit, edit Candidates, plaY? i
Enter release ID: https://www.deezer.com/en/album/572261
@ -22,6 +26,10 @@ prompt during import::
Configuration
-------------
This plugin can be configured like other metadata source plugins as described in :ref:`metadata-source-plugin-configuration`.
This plugin can be configured like other metadata source plugins as described in
:ref:`metadata-source-plugin-configuration`.
The ``deezer`` plugin provides an additional command ``deezerupdate`` to update the ``rank`` information from Deezer. The ``rank`` (ranges from 0 to 1M) is a global indicator of a song's popularity on Deezer that is updated daily based on streams. The higher the ``rank``, the more popular the track is.
The ``deezer`` plugin provides an additional command ``deezerupdate`` to update
the ``rank`` information from Deezer. The ``rank`` (ranges from 0 to 1M) is a
global indicator of a song's popularity on Deezer that is updated daily based on
streams. The higher the ``rank``, the more popular the track is.

View file

@ -1,15 +1,15 @@
Discogs Plugin
==============
The ``discogs`` plugin extends the autotagger's search capabilities to
include matches from the `Discogs`_ database.
The ``discogs`` plugin extends the autotagger's search capabilities to include
matches from the Discogs_ database.
Files can be imported as albums or as singletons. Since `Discogs`_ matches are
always based on `Discogs`_ releases, the album tag is written even to
singletons. This enhances the importers results when reimporting as (full or
partial) albums later on.
Files can be imported as albums or as singletons. Since Discogs_ matches are
always based on Discogs_ releases, the album tag is written even to singletons.
This enhances the importers results when reimporting as (full or partial) albums
later on.
.. _Discogs: https://discogs.com
.. _discogs: https://discogs.com
Installation
------------
@ -21,7 +21,7 @@ To use the ``discogs`` plugin, first enable it in your configuration (see
pip install "beets[discogs]"
You will also need to register for a `Discogs`_ account, and provide
You will also need to register for a Discogs_ account, and provide
authentication credentials via a personal access token or an OAuth2
authorization.
@ -29,59 +29,56 @@ Matches from Discogs will now show up during import alongside matches from
MusicBrainz. The search terms sent to the Discogs API are based on the artist
and album tags of your tracks. If those are empty no query will be issued.
If you have a Discogs ID for an album you want to tag, you can also enter it
at the "enter Id" prompt in the importer.
If you have a Discogs ID for an album you want to tag, you can also enter it at
the "enter Id" prompt in the importer.
OAuth Authorization
```````````````````
~~~~~~~~~~~~~~~~~~~
The first time you run the :ref:`import-cmd` command after enabling the plugin,
it will ask you to authorize with Discogs by visiting the site in a browser.
Subsequent runs will not require re-authorization.
Authentication via Personal Access Token
````````````````````````````````````````
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As an alternative to OAuth, you can get a token from Discogs and add it to
your configuration.
To get a personal access token (called a "user token" in the `python3-discogs-client`_
documentation):
As an alternative to OAuth, you can get a token from Discogs and add it to your
configuration. To get a personal access token (called a "user token" in the
python3-discogs-client_ documentation):
#. login to `Discogs`_;
#. visit the `Developer settings page <https://www.discogs.com/settings/developers>`_;
#. press the *Generate new token* button;
#. copy the generated token;
#. place it in your configuration in the ``discogs`` section as the ``user_token`` option:
1. login to Discogs_;
2. visit the `Developer settings page
<https://www.discogs.com/settings/developers>`_;
3. press the *Generate new token* button;
4. copy the generated token;
5. place it in your configuration in the ``discogs`` section as the
``user_token`` option:
.. code-block:: yaml
discogs:
user_token: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
discogs:
user_token: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Configuration
-------------
This plugin can be configured like other metadata source plugins as described in :ref:`metadata-source-plugin-configuration`.
This plugin can be configured like other metadata source plugins as described in
:ref:`metadata-source-plugin-configuration`.
There is one additional option in the ``discogs:`` section, ``index_tracks``.
Index tracks (see the `Discogs guidelines
<https://support.discogs.com/hc/en-us/articles/360005055373-Database-Guidelines-12-Tracklisting#Index_Tracks_And_Headings>`_),
along with headers, mark divisions between distinct works on the same release
or within works. When ``index_tracks`` is enabled:
Index tracks (see the `Discogs guidelines`_) along with headers, mark divisions
between distinct works on the same release or within works. When
``index_tracks`` is enabled:
.. code-block:: yaml
discogs:
index_tracks: yes
beets will incorporate the names of the divisions containing each track into
the imported track's title.
beets will incorporate the names of the divisions containing each track into the
imported track's title.
For example, importing
`this album
<https://www.discogs.com/Handel-Sutherland-Kirkby-Kwella-Nelson-Watkinson-Bowman-Rolfe-Johnson-Elliott-Partridge-Thomas-The-A/release/2026070>`_
would result in track names like:
For example, importing `divisions album`_ would result in track names like:
.. code-block:: text
@ -101,21 +98,21 @@ This option is useful when importing classical music.
Other configurations available under ``discogs:`` are:
- **append_style_genre**: Appends the Discogs style (if found) to the genre
tag. This can be useful if you want more granular genres to categorize your
music. For example, a release in Discogs might have a genre of "Electronic"
and a style of "Techno": enabling this setting would set the genre to be
- **append_style_genre**: Appends the Discogs style (if found) to the genre tag.
This can be useful if you want more granular genres to categorize your music.
For example, a release in Discogs might have a genre of "Electronic" and a
style of "Techno": enabling this setting would set the genre to be
"Electronic, Techno" (assuming default separator of ``", "``) instead of just
"Electronic".
Default: ``False``
- **separator**: How to join multiple genre and style values from Discogs into
a string.
Default: ``", "``
- **search_limit**: The maximum number of results to return from Discogs. This is
useful if you want to limit the number of results returned to speed up
searches.
Default: ``5``
"Electronic". Default: ``False``
- **separator**: How to join multiple genre and style values from Discogs into a
string. Default: ``", "``
- **search_limit**: The maximum number of results to return from Discogs. This
is useful if you want to limit the number of results returned to speed up
searches. Default: ``5``
.. _discogs guidelines: https://support.discogs.com/hc/en-us/articles/360005055373-Database-Guidelines-12-Tracklisting#Index_Tracks_And_Headings
.. _divisions album: https://www.discogs.com/Handel-Sutherland-Kirkby-Kwella-Nelson-Watkinson-Bowman-Rolfe-Johnson-Elliott-Partridge-Thomas-The-A/release/2026070
Troubleshooting
---------------
@ -126,12 +123,13 @@ please start by searching for `a similar issue on the repo
Here are two things you can try:
* Try deleting the token file (``~/.config/beets/discogs_token.json`` by
- Try deleting the token file (``~/.config/beets/discogs_token.json`` by
default) to force re-authorization.
* Make sure that your system clock is accurate. The Discogs servers can reject
- Make sure that your system clock is accurate. The Discogs servers can reject
your request if your clock is too out of sync.
Matching tracks by Discogs ID is not yet supported. The ``--group-albums``
option in album import mode provides an alternative to singleton mode for autotagging tracks that are not in album-related folders.
option in album import mode provides an alternative to singleton mode for
autotagging tracks that are not in album-related folders.
.. _python3-discogs-client: https://github.com/joalla/discogs_client

View file

@ -1,8 +1,8 @@
Duplicates Plugin
=================
This plugin adds a new command, ``duplicates`` or ``dup``, which finds
and lists duplicate tracks or albums in your collection.
This plugin adds a new command, ``duplicates`` or ``dup``, which finds and lists
duplicate tracks or albums in your collection.
Usage
-----
@ -10,31 +10,31 @@ Usage
To use the ``duplicates`` plugin, first enable it in your configuration (see
:ref:`using-plugins`).
By default, the ``beet duplicates`` command lists the names of tracks
in your library that are duplicates. It assumes that Musicbrainz track
and album ids are unique to each track or album. That is, it lists
every track or album with an ID that has been seen before in the
library.
You can customize the output format, count the number of duplicate
tracks or albums, and list all tracks that have duplicates or just the
duplicates themselves via command-line switches ::
By default, the ``beet duplicates`` command lists the names of tracks in your
library that are duplicates. It assumes that Musicbrainz track and album ids are
unique to each track or album. That is, it lists every track or album with an ID
that has been seen before in the library. You can customize the output format,
count the number of duplicate tracks or albums, and list all tracks that have
duplicates or just the duplicates themselves via command-line switches
-h, --help show this help message and exit
-f FMT, --format=FMT print with custom format
-a, --album show duplicate albums instead of tracks
-c, --count count duplicate tracks or albums
-C PROG, --checksum=PROG
report duplicates based on arbitrary command
-d, --delete delete items from library and disk
-F, --full show all versions of duplicate tracks or albums
-s, --strict report duplicates only if all attributes are set
-k, --key report duplicates based on keys (can be used multiple times)
-M, --merge merge duplicate items
-m DEST, --move=DEST move items to dest
-o DEST, --copy=DEST copy items to dest
-p, --path print paths for matched items or albums
-t TAG, --tag=TAG tag matched items with 'k=v' attribute
-r, --remove remove items from library
::
-h, --help show this help message and exit
-f FMT, --format=FMT print with custom format
-a, --album show duplicate albums instead of tracks
-c, --count count duplicate tracks or albums
-C PROG, --checksum=PROG
report duplicates based on arbitrary command
-d, --delete delete items from library and disk
-F, --full show all versions of duplicate tracks or albums
-s, --strict report duplicates only if all attributes are set
-k, --key report duplicates based on keys (can be used multiple times)
-M, --merge merge duplicate items
-m DEST, --move=DEST move items to dest
-o DEST, --copy=DEST copy items to dest
-p, --path print paths for matched items or albums
-t TAG, --tag=TAG tag matched items with 'k=v' attribute
-r, --remove remove items from library
Configuration
-------------
@ -42,117 +42,132 @@ Configuration
To configure the plugin, make a ``duplicates:`` section in your configuration
file. The available options mirror the command-line options:
- **album**: List duplicate albums instead of tracks.
Default: ``no``.
- **checksum**: Use an arbitrary command to compute a checksum
of items. This overrides the ``keys`` option the first time it is run;
however, because it caches the resulting checksum as ``flexattrs`` in the
database, you can use ``--key=name_of_the_checksumming_program
--key=any_other_keys`` (or set the ``keys`` configuration option) the second
time around.
Default: ``ffmpeg -i {file} -f crc -``.
- **copy**: A destination base directory into which to copy matched
items.
- **album**: List duplicate albums instead of tracks. Default: ``no``.
- **checksum**: Use an arbitrary command to compute a checksum of items. This
overrides the ``keys`` option the first time it is run; however, because it
caches the resulting checksum as ``flexattrs`` in the database, you can use
``--key=name_of_the_checksumming_program --key=any_other_keys`` (or set the
``keys`` configuration option) the second time around. Default: ``ffmpeg -i
{file} -f crc -``.
- **copy**: A destination base directory into which to copy matched items.
Default: none (disabled).
- **count**: Print a count of duplicate tracks or albums in the format
``$albumartist - $album - $title: $count`` (for tracks) or ``$albumartist -
$album: $count`` (for albums).
Default: ``no``.
- **delete**: Remove matched items from the library and from the disk.
Default: ``no``
- **format**: A specific format with which to print every track
or album. This uses the same template syntax as beets'
:doc:`path formats</reference/pathformat>`. The usage is inspired by, and
therefore similar to, the :ref:`list <list-cmd>` command.
Default: :ref:`format_item`
$album: $count`` (for albums). Default: ``no``.
- **delete**: Remove matched items from the library and from the disk. Default:
``no``
- **format**: A specific format with which to print every track or album. This
uses the same template syntax as beets' :doc:`path
formats</reference/pathformat>`. The usage is inspired by, and therefore
similar to, the :ref:`list <list-cmd>` command. Default: :ref:`format_item`
- **full**: List every track or album that has duplicates, not just the
duplicates themselves.
Default: ``no``
- **keys**: Define in which track or album fields duplicates are to be
searched. By default, the plugin uses the musicbrainz track and album IDs for
this purpose. Using the ``keys`` option (as a YAML list in the configuration
file, or as space-delimited strings in the command-line), you can extend this
behavior to consider other attributes.
Default: ``[mb_trackid, mb_albumid]``
- **merge**: Merge duplicate items by consolidating tracks and-or
metadata where possible.
- **move**: A destination base directory into which it will move matched
items.
duplicates themselves. Default: ``no``
- **keys**: Define in which track or album fields duplicates are to be searched.
By default, the plugin uses the musicbrainz track and album IDs for this
purpose. Using the ``keys`` option (as a YAML list in the configuration file,
or as space-delimited strings in the command-line), you can extend this
behavior to consider other attributes. Default: ``[mb_trackid, mb_albumid]``
- **merge**: Merge duplicate items by consolidating tracks and-or metadata where
possible.
- **move**: A destination base directory into which it will move matched items.
Default: none (disabled).
- **path**: Output the path instead of metadata when listing duplicates.
Default: ``no``.
- **strict**: Do not report duplicate matches if some of the
attributes are not defined (ie. null or empty).
Default: ``no``
- **strict**: Do not report duplicate matches if some of the attributes are not
defined (ie. null or empty). Default: ``no``
- **tag**: A ``key=value`` pair. The plugin will add a new ``key`` attribute
with ``value`` value as a flexattr to the database for duplicate items.
Default: ``no``.
- **tiebreak**: Dictionary of lists of attributes keyed by ``items``
or ``albums`` to use when choosing duplicates. By default, the
tie-breaking procedure favors the most complete metadata attribute
set. If you would like to consider the lower bitrates as duplicates,
for example, set ``tiebreak: items: [bitrate]``.
Default: ``{}``.
- **tiebreak**: Dictionary of lists of attributes keyed by ``items`` or
``albums`` to use when choosing duplicates. By default, the tie-breaking
procedure favors the most complete metadata attribute set. If you would like
to consider the lower bitrates as duplicates, for example, set ``tiebreak:
items: [bitrate]``. Default: ``{}``.
- **remove**: Remove matched items from the library, but not from the disk.
Default: ``no``.
Examples
--------
List all duplicate tracks in your collection::
List all duplicate tracks in your collection:
beet duplicates
::
List all duplicate tracks from 2008::
beet duplicates
beet duplicates year:2008
List all duplicate tracks from 2008:
Print out a unicode histogram of duplicate track years using `spark`_::
::
beet duplicates -f '$year' | spark
▆▁▆█▄▇▇▄▇▇▁█▇▆▇▂▄█▁██▂█▁▁██▁█▂▇▆▂▇█▇▇█▆▆▇█▇█▇▆██▂▇
beet duplicates year:2008
Print out a listing of all albums with duplicate tracks, and respective
counts::
Print out a unicode histogram of duplicate track years using spark_:
beet duplicates -ac
::
The same as the above but include the original album, and show the path::
beet duplicates -f '$year' | spark
▆▁▆█▄▇▇▄▇▇▁█▇▆▇▂▄█▁██▂█▁▁██▁█▂▇▆▂▇█▇▇█▆▆▇█▇█▇▆██▂▇
beet duplicates -acf '$path'
Print out a listing of all albums with duplicate tracks, and respective counts:
Get tracks with the same title, artist, and album::
::
beet duplicates -k title -k albumartist -k album
beet duplicates -ac
Compute Adler CRC32 or MD5 checksums, storing them as flexattrs, and report
back duplicates based on those values::
The same as the above but include the original album, and show the path:
beet dup -C 'ffmpeg -i {file} -f crc -'
beet dup -C 'md5sum {file}'
::
Copy highly danceable items to ``party`` directory::
beet duplicates -acf '$path'
beet dup --copy /tmp/party
Get tracks with the same title, artist, and album:
Move likely duplicates to ``trash`` directory::
::
beet dup --move ${HOME}/.Trash
beet duplicates -k title -k albumartist -k album
Delete items (careful!), if they're Nickelback::
Compute Adler CRC32 or MD5 checksums, storing them as flexattrs, and report back
duplicates based on those values:
beet duplicates --delete -k albumartist -k albumartist:nickelback
::
Tag duplicate items with some flag::
beet dup -C 'ffmpeg -i {file} -f crc -'
beet dup -C 'md5sum {file}'
beet duplicates --tag dup=1
Copy highly danceable items to ``party`` directory:
Ignore items with undefined keys::
::
beet duplicates --strict
beet dup --copy /tmp/party
Merge and delete duplicate albums with different missing tracks::
Move likely duplicates to ``trash`` directory:
beet duplicates --album --merge --delete
::
beet dup --move ${HOME}/.Trash
Delete items (careful!), if they're Nickelback:
::
beet duplicates --delete -k albumartist -k albumartist:nickelback
Tag duplicate items with some flag:
::
beet duplicates --tag dup=1
Ignore items with undefined keys:
::
beet duplicates --strict
Merge and delete duplicate albums with different missing tracks:
::
beet duplicates --album --merge --delete
.. _spark: https://github.com/holman/spark

View file

@ -5,9 +5,11 @@ The ``edit`` plugin lets you modify music metadata using your favorite text
editor.
Enable the ``edit`` plugin in your configuration (see :ref:`using-plugins`) and
then type::
then type:
beet edit QUERY
::
beet edit QUERY
Your text editor (i.e., the command in your ``$VISUAL`` or ``$EDITOR``
environment variable) will open with a list of tracks to edit. Make your changes
@ -19,15 +21,17 @@ Command-Line Options
The ``edit`` command has these command-line options:
- ``-a`` or ``--album``: Edit albums instead of individual items.
- ``-f FIELD`` or ``--field FIELD``: Specify an additional field to edit
(in addition to the defaults set in the configuration).
- ``-f FIELD`` or ``--field FIELD``: Specify an additional field to edit (in
addition to the defaults set in the configuration).
- ``--all``: Edit *all* available fields.
Interactive Usage
-----------------
The ``edit`` plugin can also be invoked during an import session. If enabled, it
adds two new options to the user prompt::
adds two new options to the user prompt:
::
[A]pply, More candidates, Skip, Use as-is, as Tracks, Group albums, Enter search, enter Id, aBort, eDit, edit Candidates?
@ -38,8 +42,8 @@ adds two new options to the user prompt::
Please note that currently the interactive usage of the plugin will only allow
you to change the item-level fields. In case you need to edit the album-level
fields, the recommended approach is to invoke the plugin via the command line
in album mode (``beet edit -a QUERY``) after the import.
fields, the recommended approach is to invoke the plugin via the command line in
album mode (``beet edit -a QUERY``) after the import.
Also, please be aware that the ``edit Candidates`` choice can only be used with
the matches found during the initial search (and currently not supporting the
@ -50,11 +54,10 @@ cases where you already have a specific candidate ID that you want to edit.
Configuration
-------------
To configure the plugin, make an ``edit:`` section in your configuration
file. The available options are:
To configure the plugin, make an ``edit:`` section in your configuration file.
The available options are:
- **itemfields**: A space-separated list of item fields to include in the
editor by default.
Default: ``track title artist album``
- **itemfields**: A space-separated list of item fields to include in the editor
by default. Default: ``track title artist album``
- **albumfields**: The same when editing albums (with the ``-a`` option).
Default: ``album albumartist``

View file

@ -25,15 +25,14 @@ This behavior can be disabled with the ``auto`` config option (see below).
.. _image-similarity-check:
Image Similarity
''''''''''''''''
~~~~~~~~~~~~~~~~
When importing a lot of files with the ``auto`` option, one may be reluctant to
overwrite existing embedded art for all of them.
You can tell beets to avoid embedding images that are too different from the
existing ones.
This works by computing the perceptual hashes (`PHASH`_) of the two images and
checking that the difference between the two does not exceed a
existing ones. This works by computing the perceptual hashes (PHASH_) of the two
images and checking that the difference between the two does not exceed a
threshold. You can set the threshold with the ``compare_threshold`` option.
A threshold of 0 (the default) disables similarity checking and always embeds
@ -41,7 +40,7 @@ new images. Set the threshold to another number---we recommend between 10 and
100---to adjust the sensitivity of the comparison. The smaller the threshold
number, the more similar the images must be.
This feature requires `ImageMagick`_.
This feature requires ImageMagick_.
Configuration
-------------
@ -49,40 +48,37 @@ Configuration
To configure the plugin, make an ``embedart:`` section in your configuration
file. The available options are:
- **auto**: Enable automatic album art embedding.
Default: ``yes``.
- **compare_threshold**: How similar candidate art must be to
existing art to be written to the file (see :ref:`image-similarity-check`).
Default: 0 (disabled).
- **auto**: Enable automatic album art embedding. Default: ``yes``.
- **compare_threshold**: How similar candidate art must be to existing art to be
written to the file (see :ref:`image-similarity-check`). Default: 0
(disabled).
- **ifempty**: Avoid embedding album art for files that already have art
embedded.
Default: ``no``.
- **maxwidth**: A maximum width to downscale images before embedding
them (the original image file is not altered). The resize operation reduces
image width to at most ``maxwidth`` pixels. The height is recomputed so that
the aspect ratio is preserved. See also :ref:`image-resizing` for further
caveats about image resizing.
Default: 0 (disabled).
embedded. Default: ``no``.
- **maxwidth**: A maximum width to downscale images before embedding them (the
original image file is not altered). The resize operation reduces image width
to at most ``maxwidth`` pixels. The height is recomputed so that the aspect
ratio is preserved. See also :ref:`image-resizing` for further caveats about
image resizing. Default: 0 (disabled).
- **quality**: The JPEG quality level to use when compressing images (when
``maxwidth`` is set). This should be either a number from 1 to 100 or 0 to
use the default quality. 6575 is usually a good starting point. The default
``maxwidth`` is set). This should be either a number from 1 to 100 or 0 to use
the default quality. 6575 is usually a good starting point. The default
behavior depends on the imaging tool used for scaling: ImageMagick tries to
estimate the input image quality and uses 92 if it cannot be determined, and
PIL defaults to 75.
Default: 0 (disabled)
PIL defaults to 75. Default: 0 (disabled)
- **remove_art_file**: Automatically remove the album art file for the album
after it has been embedded. This option is best used alongside the
:doc:`FetchArt </plugins/fetchart>` plugin to download art with the purpose of
directly embedding it into the file's metadata without an "intermediate"
album art file.
Default: ``no``.
directly embedding it into the file's metadata without an "intermediate" album
art file. Default: ``no``.
Note: ``compare_threshold`` option requires `ImageMagick`_, and ``maxwidth``
requires either `ImageMagick`_ or `Pillow`_.
Note: ``compare_threshold`` option requires ImageMagick_, and ``maxwidth``
requires either ImageMagick_ or Pillow_.
.. _Pillow: https://github.com/python-pillow/Pillow
.. _ImageMagick: https://www.imagemagick.org/
.. _PHASH: http://www.fmwconcepts.com/misc_tests/perceptual_hash_test_results_510/
.. _imagemagick: https://www.imagemagick.org/
.. _phash: http://www.fmwconcepts.com/misc_tests/perceptual_hash_test_results_510/
.. _pillow: https://github.com/python-pillow/Pillow
Manually Embedding and Extracting Art
-------------------------------------
@ -90,29 +86,28 @@ Manually Embedding and Extracting Art
The ``embedart`` plugin provides a couple of commands for manually managing
embedded album art:
* ``beet embedart [-f IMAGE] QUERY``: embed images in every track of the
albums matching the query. If the ``-f`` (``--file``) option is given, then
use a specific image file from the filesystem; otherwise, each album embeds
its own currently associated album art. The command prompts for confirmation
before making the change unless you specify the ``-y`` (``--yes``) option.
* ``beet embedart [-u IMAGE_URL] QUERY``: embed image specified in the URL
into every track of the albums matching the query. The ``-u`` (``--url``) option can be used to specify the URL of the image to be used. The command prompts for confirmation before making the change unless you specify the ``-y`` (``--yes``) option.
* ``beet extractart [-a] [-n FILE] QUERY``: extracts the images for all albums
- ``beet embedart [-f IMAGE] QUERY``: embed images in every track of the albums
matching the query. If the ``-f`` (``--file``) option is given, then use a
specific image file from the filesystem; otherwise, each album embeds its own
currently associated album art. The command prompts for confirmation before
making the change unless you specify the ``-y`` (``--yes``) option.
- ``beet embedart [-u IMAGE_URL] QUERY``: embed image specified in the URL into
every track of the albums matching the query. The ``-u`` (``--url``) option
can be used to specify the URL of the image to be used. The command prompts
for confirmation before making the change unless you specify the ``-y``
(``--yes``) option.
- ``beet extractart [-a] [-n FILE] QUERY``: extracts the images for all albums
matching the query. The images are placed inside the album folder. You can
specify the destination file name using the ``-n`` option, but leave off the
extension: it will be chosen automatically. The destination filename is
specified using the ``art_filename`` configuration option. It defaults to
``cover`` if it's not specified via ``-o`` nor the config.
Using ``-a``, the extracted image files are automatically associated with the
corresponding album.
* ``beet extractart -o FILE QUERY``: extracts the image from an item matching
``cover`` if it's not specified via ``-o`` nor the config. Using ``-a``, the
extracted image files are automatically associated with the corresponding
album.
- ``beet extractart -o FILE QUERY``: extracts the image from an item matching
the query and stores it in a file. You have to specify the destination file
using the ``-o`` option, but leave off the extension: it will be chosen
automatically.
* ``beet clearart QUERY``: removes all embedded images from all items matching
- ``beet clearart QUERY``: removes all embedded images from all items matching
the query. The command prompts for confirmation before making the change
unless you specify the ``-y`` (``--yes``) option.

View file

@ -1,11 +1,11 @@
EmbyUpdate Plugin
=================
``embyupdate`` is a plugin that lets you automatically update `Emby`_'s library
``embyupdate`` is a plugin that lets you automatically update Emby_'s library
whenever you change your beets library.
To use it, first enable the your configuration (see :ref:`using-plugins`).
Then, install ``beets`` with ``embyupdate`` extra
To use it, first enable the your configuration (see :ref:`using-plugins`). Then,
install ``beets`` with ``embyupdate`` extra
.. code-block:: bash
@ -22,26 +22,27 @@ that using an ``emby`` section in your ``config.yaml``
username: user
apikey: apikey
With that all in place, you'll see beets send the "update" command to your Emby server every time you change your beets library.
With that all in place, you'll see beets send the "update" command to your Emby
server every time you change your beets library.
.. _Emby: https://emby.media/
.. _emby: https://emby.media/
Configuration
-------------
The available options under the ``emby:`` section are:
- **host**: The Emby server host. You also can include ``http://`` or ``https://``.
Default: ``localhost``
- **port**: The Emby server port.
Default: 8096
- **username**: A username of an Emby user that is allowed to refresh the library.
- **host**: The Emby server host. You also can include ``http://`` or
``https://``. Default: ``localhost``
- **port**: The Emby server port. Default: 8096
- **username**: A username of an Emby user that is allowed to refresh the
library.
- **userid**: A user ID of an Emby user that is allowed to refresh the library.
(This is only necessary for private users i.e. when the user is hidden from
login screens)
- **apikey**: An Emby API key for the user.
- **password**: The password for the user. (This is only necessary if no API
key is provided.)
- **password**: The password for the user. (This is only necessary if no API key
is provided.)
You can choose to authenticate either with ``apikey`` or ``password``, but only
one of those two is required.

View file

@ -1,54 +1,56 @@
Export Plugin
=============
The ``export`` plugin lets you get data from the items and export the content
as `JSON`_, `CSV`_, or `XML`_.
The ``export`` plugin lets you get data from the items and export the content as
JSON_, CSV_, or XML_.
.. _JSON: https://www.json.org
.. _CSV: https://fileinfo.com/extension/csv
.. _XML: https://fileinfo.com/extension/xml
.. _csv: https://fileinfo.com/extension/csv
Enable the ``export`` plugin (see :ref:`using-plugins` for help). Then, type ``beet export`` followed by a :doc:`query </reference/query>` to get the data from
your library. For example, run this::
.. _json: https://www.json.org
.. _xml: https://fileinfo.com/extension/xml
Enable the ``export`` plugin (see :ref:`using-plugins` for help). Then, type
``beet export`` followed by a :doc:`query </reference/query>` to get the data
from your library. For example, run this:
::
$ beet export beatles
to print a JSON file containing information about your Beatles tracks.
Command-Line Options
--------------------
The ``export`` command has these command-line options:
* ``--include-keys`` or ``-i``: Choose the properties to include in the output
- ``--include-keys`` or ``-i``: Choose the properties to include in the output
data. The argument is a comma-separated list of simple glob patterns where
``*`` matches any string. For example::
``*`` matches any string. For example:
::
$ beet export -i 'title,mb*' beatles
will include the ``title`` property and all properties starting with
``mb``. You can add the ``-i`` option multiple times to the command
line.
will include the ``title`` property and all properties starting with ``mb``.
You can add the ``-i`` option multiple times to the command line.
* ``--library`` or ``-l``: Show data from the library database instead of the
- ``--library`` or ``-l``: Show data from the library database instead of the
files' tags.
* ``--album`` or ``-a``: Show data from albums instead of tracks (implies
- ``--album`` or ``-a``: Show data from albums instead of tracks (implies
``--library``).
* ``--output`` or ``-o``: Path for an output file. If not informed, will print
- ``--output`` or ``-o``: Path for an output file. If not informed, will print
the data in the console.
* ``--append``: Appends the data to the file instead of writing.
* ``--format`` or ``-f``: Specifies the format the data will be exported as. If not informed, JSON will be used by default. The format options include csv, json, `jsonlines <https://jsonlines.org/>`_ and xml.
- ``--append``: Appends the data to the file instead of writing.
- ``--format`` or ``-f``: Specifies the format the data will be exported as. If
not informed, JSON will be used by default. The format options include csv,
json, `jsonlines <https://jsonlines.org/>`_ and xml.
Configuration
-------------
To configure the plugin, make a ``export:`` section in your configuration
file.
To configure the plugin, make a ``export:`` section in your configuration file.
For JSON export, these options are available under the ``json`` and
``jsonlines`` keys:
@ -57,19 +59,22 @@ For JSON export, these options are available under the ``json`` and
- **separators**: A ``[item_separator, dict_separator]`` tuple.
- **sort_keys**: Sorts the keys in JSON dictionaries.
Those options match the options from the `Python json module`_.
Similarly, these options are available for the CSV format under the ``csv``
key:
Those options match the options from the `Python json module`_. Similarly, these
options are available for the CSV format under the ``csv`` key:
- **delimiter**: Used as the separating character between fields. The default value is a comma (,).
- **dialect**: The kind of CSV file to produce. The default is `excel`.
- **delimiter**: Used as the separating character between fields. The default
value is a comma (,).
- **dialect**: The kind of CSV file to produce. The default is ``excel``.
These options match the options from the `Python csv module`_.
.. _Python json module: https://docs.python.org/2/library/json.html#basic-usage
.. _Python csv module: https://docs.python.org/3/library/csv.html#csv-fmt-params
.. _python csv module: https://docs.python.org/3/library/csv.html#csv-fmt-params
The default options look like this::
.. _python json module: https://docs.python.org/2/library/json.html#basic-usage
The default options look like this:
::
export:
json:

View file

@ -28,57 +28,51 @@ Configuration
To configure the plugin, make a ``fetchart:`` section in your configuration
file. The available options are:
- **auto**: Enable automatic album art fetching during import.
Default: ``yes``.
- **auto**: Enable automatic album art fetching during import. Default: ``yes``.
- **cautious**: Pick only trusted album art by ignoring filenames that do not
contain one of the keywords in ``cover_names``.
Default: ``no``.
- **cover_names**: Prioritize images containing words in this list.
Default: ``cover front art album folder``.
contain one of the keywords in ``cover_names``. Default: ``no``.
- **cover_names**: Prioritize images containing words in this list. Default:
``cover front art album folder``.
- **minwidth**: Only images with a width bigger or equal to ``minwidth`` are
considered as valid album art candidates. Default: 0.
- **maxwidth**: A maximum image width to downscale fetched images if they are
too big. The resize operation reduces image width to at most ``maxwidth``
pixels. The height is recomputed so that the aspect ratio is preserved. See
the section on :ref:`cover-art-archive-maxwidth` below for additional
information regarding the Cover Art Archive source.
Default: 0 (no maximum is enforced).
information regarding the Cover Art Archive source. Default: 0 (no maximum is
enforced).
- **quality**: The JPEG quality level to use when compressing images (when
``maxwidth`` is set). This should be either a number from 1 to 100 or 0 to
use the default quality. 6575 is usually a good starting point. The default
``maxwidth`` is set). This should be either a number from 1 to 100 or 0 to use
the default quality. 6575 is usually a good starting point. The default
behavior depends on the imaging tool used for scaling: ImageMagick tries to
estimate the input image quality and uses 92 if it cannot be determined, and
PIL defaults to 75.
Default: 0 (disabled)
PIL defaults to 75. Default: 0 (disabled)
- **max_filesize**: The maximum size of a target piece of cover art in bytes.
When using an ImageMagick backend this sets
``-define jpeg:extent=max_filesize``. Using PIL this will reduce JPG quality
by up to 50% to attempt to reach the target filesize. Neither method is
*guaranteed* to reach the target size, however in most cases it should
succeed.
Default: 0 (disabled)
- **enforce_ratio**: Only images with a width:height ratio of 1:1 are
considered as valid album art candidates if set to ``yes``.
It is also possible to specify a certain deviation to the exact ratio to
still be considered valid. This can be done either in pixels
(``enforce_ratio: 10px``) or as a percentage of the longer edge
(``enforce_ratio: 0.5%``). Default: ``no``.
- **sources**: List of sources to search for images. An asterisk `*` expands
to all available sources.
Default: ``filesystem coverart itunes amazon albumart``, i.e., everything but
``wikipedia``, ``google``, ``fanarttv`` and ``lastfm``. Enable those sources
for more matches at the cost of some speed. They are searched in the given
order, thus in the default config, no remote (Web) art source are queried if
local art is found in the filesystem. To use a local image as fallback,
move it to the end of the list. For even more fine-grained control over
the search order, see the section on :ref:`album-art-sources` below.
When using an ImageMagick backend this sets ``-define
jpeg:extent=max_filesize``. Using PIL this will reduce JPG quality by up to
50% to attempt to reach the target filesize. Neither method is *guaranteed* to
reach the target size, however in most cases it should succeed. Default: 0
(disabled)
- **enforce_ratio**: Only images with a width:height ratio of 1:1 are considered
as valid album art candidates if set to ``yes``. It is also possible to
specify a certain deviation to the exact ratio to still be considered valid.
This can be done either in pixels (``enforce_ratio: 10px``) or as a percentage
of the longer edge (``enforce_ratio: 0.5%``). Default: ``no``.
- **sources**: List of sources to search for images. An asterisk ``*`` expands
to all available sources. Default: ``filesystem coverart itunes amazon
albumart``, i.e., everything but ``wikipedia``, ``google``, ``fanarttv`` and
``lastfm``. Enable those sources for more matches at the cost of some speed.
They are searched in the given order, thus in the default config, no remote
(Web) art source are queried if local art is found in the filesystem. To use a
local image as fallback, move it to the end of the list. For even more
fine-grained control over the search order, see the section on
:ref:`album-art-sources` below.
- **google_key**: Your Google API key (to enable the Google Custom Search
backend).
Default: None.
- **google_engine**: The custom search engine to use.
Default: The `beets custom search engine`_, which searches the entire web.
- **fanarttv_key**: The personal API key for requesting art from
fanart.tv. See below.
backend). Default: None.
- **google_engine**: The custom search engine to use. Default: The `beets custom
search engine`_, which searches the entire web.
- **fanarttv_key**: The personal API key for requesting art from fanart.tv. See
below.
- **lastfm_key**: The personal API key for requesting art from Last.fm. See
below.
- **store_source**: If enabled, fetchart stores the artwork's source in a
@ -87,64 +81,70 @@ file. The available options are:
- **high_resolution**: If enabled, fetchart retrieves artwork in the highest
resolution it can find (warning: image files can sometimes reach >20MB).
Default: ``no``.
- **deinterlace**: If enabled, `Pillow`_ or `ImageMagick`_ backends are
instructed to store cover art as non-progressive JPEG. You might need this if
you use DAPs that don't support progressive images.
Default: ``no``.
- **deinterlace**: If enabled, Pillow_ or ImageMagick_ backends are instructed
to store cover art as non-progressive JPEG. You might need this if you use
DAPs that don't support progressive images. Default: ``no``.
- **cover_format**: If enabled, forced the cover image into the specified
format. Most often, this will be either ``JPEG`` or ``PNG`` [#imgformats]_.
Also respects ``deinterlace``.
Default: None (leave unchanged).
format. Most often, this will be either ``JPEG`` or ``PNG`` (see
image-formats_). Also respects ``deinterlace``. Default: None (leave
unchanged).
Note: ``maxwidth`` and ``enforce_ratio`` options require either `ImageMagick`_
or `Pillow`_.
Note: ``maxwidth`` and ``enforce_ratio`` options require either ImageMagick_ or
Pillow_.
.. note::
Previously, there was a ``remote_priority`` option to specify when to
look for art on the filesystem. This is
still respected, but a deprecation message will be shown until you
replace this configuration with the new ``filesystem`` value in the
``sources`` array.
Previously, there was a ``remote_priority`` option to specify when to look
for art on the filesystem. This is still respected, but a deprecation
message will be shown until you replace this configuration with the new
``filesystem`` value in the ``sources`` array.
.. _image-formats:
.. admonition:: Image formats
Other image formats are available, though the full list depends on your
system and what backend you are using. If you're using the ImageMagick
backend, you can use ``magick identify -list format`` to get a full list of
all supported formats, and you can use the Python function
PIL.features.pilinfo() to print a list of all supported formats in Pillow
(``python3 -c 'import PIL.features as f; f.pilinfo()'``).
.. _beets custom search engine: https://cse.google.com.au:443/cse/publicurl?cx=001442825323518660753:hrh5ch1gjzm
.. _Pillow: https://github.com/python-pillow/Pillow
.. _ImageMagick: https://www.imagemagick.org/
.. [#imgformats] Other image formats are available, though the full list
depends on your system and what backend you are using. If you're using the
ImageMagick backend, you can use ``magick identify -list format`` to get a
full list of all supported formats, and you can use the Python function
PIL.features.pilinfo() to print a list of all supported formats in Pillow
(``python3 -c 'import PIL.features as f; f.pilinfo()'``).
Here's an example that makes plugin select only images that contain ``front`` or
``back`` keywords in their filenames and prioritizes the iTunes source over
others::
others:
::
fetchart:
cautious: true
cover_names: front back
sources: itunes *
Manually Fetching Album Art
---------------------------
Use the ``fetchart`` command to download album art after albums have already
been imported::
been imported:
::
$ beet fetchart [-f] [query]
By default, the command will only look for album art when the album doesn't
already have it; the ``-f`` or ``--force`` switch makes it search for art
in Web databases regardless. If you specify a query, only matching albums will
be processed; otherwise, the command processes every album in your library.
already have it; the ``-f`` or ``--force`` switch makes it search for art in Web
databases regardless. If you specify a query, only matching albums will be
processed; otherwise, the command processes every album in your library.
Display Only Missing Album Art
------------------------------
Use the ``fetchart`` command with the ``-q`` switch in order to display only missing
art::
Use the ``fetchart`` command with the ``-q`` switch in order to display only
missing art:
::
$ beet fetchart [-q] [query]
@ -157,7 +157,7 @@ fetched, or for which artwork could not be found will be printed.
Image Resizing
--------------
Beets can resize images using `Pillow`_, `ImageMagick`_, or a server-side resizing
Beets can resize images using Pillow_, ImageMagick_, or a server-side resizing
proxy. If either Pillow or ImageMagick is installed, beets will use those;
otherwise, it falls back to the resizing proxy. If the resizing proxy is used,
no resizing is performed for album art found on the filesystem---only downloaded
@ -169,9 +169,6 @@ On some versions of Windows, the program can be shadowed by a system-provided
``convert.exe``. On these systems, you may need to modify your ``%PATH%``
environment variable so that ImageMagick comes first or use Pillow instead.
.. _Pillow: https://github.com/python-pillow/Pillow
.. _ImageMagick: https://www.imagemagick.org/
.. _album-art-sources:
Album Art Sources
@ -179,9 +176,8 @@ Album Art Sources
By default, this plugin searches for art in the local filesystem as well as on
the Cover Art Archive, the iTunes Store, Amazon, and AlbumArt.org, in that
order.
You can reorder the sources or remove
some to speed up the process using the ``sources`` configuration option.
order. You can reorder the sources or remove some to speed up the process using
the ``sources`` configuration option.
When looking for local album art, beets checks for image files located in the
same folder as the music files you're importing. Beets prefers to use an image
@ -190,8 +186,10 @@ the absence of well-known names, it will use any image file in the same folder
as your music files.
For some of the art sources, the backend service can match artwork by various
criteria. If you want finer control over the search order in such cases, you
can use this alternative syntax for the ``sources`` option::
criteria. If you want finer control over the search order in such cases, you can
use this alternative syntax for the ``sources`` option:
::
fetchart:
sources:
@ -203,73 +201,72 @@ can use this alternative syntax for the ``sources`` option::
where listing a source without matching criteria will default to trying all
available strategies. Entries of the forms ``coverart: release releasegroup``
and ``coverart: *`` are also valid.
Currently, only the ``coverart`` source supports multiple criteria:
namely, ``release`` and ``releasegroup``, which refer to the
respective MusicBrainz IDs.
and ``coverart: *`` are also valid. Currently, only the ``coverart`` source
supports multiple criteria: namely, ``release`` and ``releasegroup``, which
refer to the respective MusicBrainz IDs.
When you choose to apply changes during an import, beets will search for art as
described above. For "as-is" imports (and non-autotagged imports using the
described above. For "as-is" imports (and non-autotagged imports using the
``-A`` flag), beets only looks for art on the local filesystem.
Google custom search
''''''''''''''''''''
~~~~~~~~~~~~~~~~~~~~
To use the google image search backend you need to
`register for a Google API key`_. Set the ``google_key`` configuration
option to your key, then add ``google`` to the list of sources in your
configuration.
To use the google image search backend you need to `register for a Google API
key`_. Set the ``google_key`` configuration option to your key, then add
``google`` to the list of sources in your configuration.
.. _register for a Google API key: https://console.developers.google.com.
.. _register for a google api key: https://console.developers.google.com.
Optionally, you can `define a custom search engine`_. Get your search engine's
token and use it for your ``google_engine`` configuration option. The
default engine searches the entire web for cover art.
token and use it for your ``google_engine`` configuration option. The default
engine searches the entire web for cover art.
.. _define a custom search engine: https://www.google.com/cse/all
Note that the Google custom search API is limited to 100 queries per day.
After that, the fetchart plugin will fall back on other declared data sources.
Note that the Google custom search API is limited to 100 queries per day. After
that, the fetchart plugin will fall back on other declared data sources.
Fanart.tv
'''''''''
~~~~~~~~~
Although not strictly necessary right now, you might think about
`registering a personal fanart.tv API key`_. Set the ``fanarttv_key``
configuration option to your key, then add ``fanarttv`` to the list of sources
in your configuration.
Although not strictly necessary right now, you might think about `registering a
personal fanart.tv API key`_. Set the ``fanarttv_key`` configuration option to
your key, then add ``fanarttv`` to the list of sources in your configuration.
.. _registering a personal fanart.tv API key: https://fanart.tv/get-an-api-key/
.. _registering a personal fanart.tv api key: https://fanart.tv/get-an-api-key/
More detailed information can be found `on their Wiki`_. Specifically, the
personal key will give you earlier access to new art.
.. _on their Wiki: https://wiki.fanart.tv/General/personal%20api/
.. _on their wiki: https://wiki.fanart.tv/General/personal%20api/
Last.fm
'''''''
~~~~~~~
To use the Last.fm backend, you need to `register for a Last.fm API key`_. Set
the ``lastfm_key`` configuration option to your API key, then add ``lastfm`` to
the list of sources in your configuration.
.. _register for a Last.fm API key: https://www.last.fm/api/account/create
.. _register for a last.fm api key: https://www.last.fm/api/account/create
Spotify
'''''''
~~~~~~~
Spotify backend is enabled by default and will update album art if a valid Spotify album id is found.
Spotify backend is enabled by default and will update album art if a valid
Spotify album id is found.
.. _beautifulsoup: https://www.crummy.com/software/BeautifulSoup/bs4/doc/
.. _pip: https://pip.pypa.io
.. _BeautifulSoup: https://www.crummy.com/software/BeautifulSoup/bs4/doc/
Cover Art URL
'''''''''''''
~~~~~~~~~~~~~
The `fetchart` plugin can also use a flexible attribute field ``cover_art_url``
where you can manually specify the image URL to be used as cover art. Any custom
plugin can use this field to provide the cover art and ``fetchart`` will use it
as a source.
The ``fetchart`` plugin can also use a flexible attribute field
``cover_art_url`` where you can manually specify the image URL to be used as
cover art. Any custom plugin can use this field to provide the cover art and
``fetchart`` will use it as a source.
.. _cover-art-archive-maxwidth:
@ -277,20 +274,24 @@ Cover Art Archive Pre-sized Thumbnails
--------------------------------------
The CAA provides pre-sized thumbnails of width 250, 500, and 1200 pixels. If you
set the `maxwidth` option to one of these values, the corresponding image will
be downloaded, saving `beets` the need to scale down the image. It can also
set the ``maxwidth`` option to one of these values, the corresponding image will
be downloaded, saving ``beets`` the need to scale down the image. It can also
speed up the downloading process, as some cover arts can sometimes be very
large.
Storing the Artwork's Source
----------------------------
Storing the current artwork's source might be used to narrow down
``fetchart`` commands. For example, if some albums have artwork placed
manually in their directories that should not be replaced by a forced
album art fetch, you could do
Storing the current artwork's source might be used to narrow down ``fetchart``
commands. For example, if some albums have artwork placed manually in their
directories that should not be replaced by a forced album art fetch, you could
do
``beet fetchart -f ^art_source:filesystem``
The values written to ``art_source`` are the same names used in the ``sources``
configuration value.
.. _imagemagick: https://www.imagemagick.org/
.. _pillow: https://github.com/python-pillow/Pillow

View file

@ -1,8 +1,8 @@
FileFilter Plugin
=================
The ``filefilter`` plugin allows you to skip files during import using
regular expressions.
The ``filefilter`` plugin allows you to skip files during import using regular
expressions.
To use the ``filefilter`` plugin, enable it in your configuration (see
:ref:`using-plugins`).
@ -10,18 +10,20 @@ To use the ``filefilter`` plugin, enable it in your configuration (see
Configuration
-------------
To configure the plugin, make a ``filefilter:`` section in your
configuration file. The available options are:
To configure the plugin, make a ``filefilter:`` section in your configuration
file. The available options are:
- **path**: A regular expression to filter files based on their path and name.
Default: ``.*`` (import everything)
- **album_path** and **singleton_path**: You may specify different regular
expressions used for imports of albums and singletons. This way, you can
automatically skip singletons when importing albums if the names (and paths)
of the files are distinguishable via a regex. The regexes defined here
take precedence over the global ``path`` option.
of the files are distinguishable via a regex. The regexes defined here take
precedence over the global ``path`` option.
Here's an example::
Here's an example:
::
filefilter:
path: .*\d\d[^/]+$

View file

@ -2,10 +2,10 @@ Fish Plugin
===========
The ``fish`` plugin adds a ``beet fish`` command that creates a `Fish shell`_
tab-completion file named ``beet.fish`` in ``~/.config/fish/completions``.
This enables tab-completion of ``beet`` commands for the `Fish shell`_.
tab-completion file named ``beet.fish`` in ``~/.config/fish/completions``. This
enables tab-completion of ``beet`` commands for the `Fish shell`_.
.. _Fish shell: https://fishshell.com/
.. _fish shell: https://fishshell.com/
Configuration
-------------
@ -24,11 +24,11 @@ For users not accustomed to tab completion… After you type ``beet`` followed b
a space in your shell prompt and then the ``TAB`` key, you should see a list of
the beets commands (and their abbreviated versions) that can be invoked in your
current environment. Similarly, typing ``beet -<TAB>`` will show you all the
option flags available to you, which also applies to subcommands such as
``beet import -<TAB>``. If you type ``beet ls`` followed by a space and then the
and the ``TAB`` key, you will see a list of all the album/track fields that can
be used in beets queries. For example, typing ``beet ls ge<TAB>`` will complete
to ``genre:`` and leave you ready to type the rest of your query.
option flags available to you, which also applies to subcommands such as ``beet
import -<TAB>``. If you type ``beet ls`` followed by a space and then the and
the ``TAB`` key, you will see a list of all the album/track fields that can be
used in beets queries. For example, typing ``beet ls ge<TAB>`` will complete to
``genre:`` and leave you ready to type the rest of your query.
Options
-------
@ -41,17 +41,16 @@ commands and option flags.
If you want generated completions to also contain album/track field *values* for
the items in your library, you can use the ``-e`` or ``--extravalues`` option.
For example: ``beet fish -e genre`` or ``beet fish -e genre -e albumartist``
In the latter case, subsequently typing ``beet list genre: <TAB>`` will display
a list of all the genres in your library and ``beet list albumartist: <TAB>``
will show a list of the album artists in your library. Keep in mind that all of
these values will be put into the generated completions file, so use this option
with care when specified fields contain a large number of values. Libraries with,
for example, very large numbers of genres/artists may result in higher memory
For example: ``beet fish -e genre`` or ``beet fish -e genre -e albumartist`` In
the latter case, subsequently typing ``beet list genre: <TAB>`` will display a
list of all the genres in your library and ``beet list albumartist: <TAB>`` will
show a list of the album artists in your library. Keep in mind that all of these
values will be put into the generated completions file, so use this option with
care when specified fields contain a large number of values. Libraries with, for
example, very large numbers of genres/artists may result in higher memory
utilization, completion latency, et cetera. This option is not meant to replace
database queries altogether.
By default, the completion file will be generated at
``~/.config/fish/completions/``.
If you want to save it somewhere else, you can use the ``-o`` or ``--output``
option.
``~/.config/fish/completions/``. If you want to save it somewhere else, you can
use the ``-o`` or ``--output`` option.

View file

@ -1,6 +1,6 @@
Freedesktop Plugin
==================
The ``freedesktop`` plugin created .directory files in your album folders.
This plugin is now deprecated and replaced by the :doc:`/plugins/thumbnails`
with the ``dolphin`` option enabled.
The ``freedesktop`` plugin created .directory files in your album folders. This
plugin is now deprecated and replaced by the :doc:`/plugins/thumbnails` with the
``dolphin`` option enabled.

View file

@ -1,13 +1,12 @@
FromFilename Plugin
===================
The ``fromfilename`` plugin helps to tag albums that are missing tags
altogether but where the filenames contain useful information like the artist
and title.
The ``fromfilename`` plugin helps to tag albums that are missing tags altogether
but where the filenames contain useful information like the artist and title.
When you attempt to import a track that's missing a title, this plugin will
look at the track's filename and guess its track number, title, and artist.
These will be used to search in MusicBrainz and match track ordering.
When you attempt to import a track that's missing a title, this plugin will look
at the track's filename and guess its track number, title, and artist. These
will be used to search in MusicBrainz and match track ordering.
To use the ``fromfilename`` plugin, enable it in your configuration
(see :ref:`using-plugins`).
To use the ``fromfilename`` plugin, enable it in your configuration (see
:ref:`using-plugins`).

View file

@ -10,8 +10,8 @@ tracks in your library like "Tellin' Me Things" by the artist "Blakroc feat.
RZA". If you prefer to tag this as "Tellin' Me Things feat. RZA" by "Blakroc",
then this plugin is for you.
To use the ``ftintitle`` plugin, enable it in your configuration
(see :ref:`using-plugins`).
To use the ``ftintitle`` plugin, enable it in your configuration (see
:ref:`using-plugins`).
Configuration
-------------
@ -19,23 +19,22 @@ Configuration
To configure the plugin, make a ``ftintitle:`` section in your configuration
file. The available options are:
- **auto**: Enable metadata rewriting during import.
Default: ``yes``.
- **drop**: Remove featured artists entirely instead of adding them to the
title field.
Default: ``no``.
- **format**: Defines the format for the featuring X part of the new title field.
In this format the ``{0}`` is used to define where the featured artists are placed.
Default: ``feat. {0}``
- **keep_in_artist**: Keep the featuring X part in the artist field. This can
be useful if you still want to be able to search for features in the artist
field.
Default: ``no``.
- **auto**: Enable metadata rewriting during import. Default: ``yes``.
- **drop**: Remove featured artists entirely instead of adding them to the title
field. Default: ``no``.
- **format**: Defines the format for the featuring X part of the new title
field. In this format the ``{0}`` is used to define where the featured artists
are placed. Default: ``feat. {0}``
- **keep_in_artist**: Keep the featuring X part in the artist field. This can be
useful if you still want to be able to search for features in the artist
field. Default: ``no``.
Running Manually
----------------
From the command line, type::
From the command line, type:
::
$ beet ftintitle [QUERY]
@ -45,4 +44,4 @@ your entire collection.
Use the ``-d`` flag to remove featured artists (equivalent of the ``drop``
config option).
.. _MusicBrainz style: https://musicbrainz.org/doc/Style
.. _musicbrainz style: https://musicbrainz.org/doc/Style

View file

@ -5,8 +5,10 @@ The ``fuzzy`` plugin provides a prefixed query that searches your library using
fuzzy pattern matching. This can be useful if you want to find a track with
complicated characters in the title.
First, enable the plugin named ``fuzzy`` (see :ref:`using-plugins`).
You'll then be able to use the ``~`` prefix to use fuzzy matching::
First, enable the plugin named ``fuzzy`` (see :ref:`using-plugins`). You'll then
be able to use the ``~`` prefix to use fuzzy matching:
::
$ beet ls '~Vareoldur'
Sigur Rós - Valtari - Varðeldur
@ -14,11 +16,10 @@ You'll then be able to use the ``~`` prefix to use fuzzy matching::
Configuration
-------------
To configure the plugin, make a ``fuzzy:`` section in your configuration
file. The available options are:
To configure the plugin, make a ``fuzzy:`` section in your configuration file.
The available options are:
- **threshold**: The "sensitivity" of the fuzzy match. A value of 1.0 will
show only perfect matches and a value of 0.0 will match everything.
Default: 0.7.
- **prefix**: The character used to designate fuzzy queries.
Default: ``~``, which may need to be escaped in some shells.
- **threshold**: The "sensitivity" of the fuzzy match. A value of 1.0 will show
only perfect matches and a value of 0.0 will match everything. Default: 0.7.
- **prefix**: The character used to designate fuzzy queries. Default: ``~``,
which may need to be escaped in some shells.

View file

@ -1,5 +1,5 @@
Gmusic Plugin
=============
The ``gmusic`` plugin interfaced beets to Google Play Music. It has been
removed after the shutdown of this service.
The ``gmusic`` plugin interfaced beets to Google Play Music. It has been removed
after the shutdown of this service.

View file

@ -3,43 +3,42 @@ Hook Plugin
Internally, beets uses *events* to tell plugins when something happens. For
example, one event fires when the importer finishes processes a song, and
another triggers just before the ``beet`` command exits.
The ``hook`` plugin lets you run commands in response to these events.
another triggers just before the ``beet`` command exits. The ``hook`` plugin
lets you run commands in response to these events.
.. _hook-configuration:
Configuration
-------------
To configure the plugin, make a ``hook`` section in your configuration
file. The available options are:
To configure the plugin, make a ``hook`` section in your configuration file. The
available options are:
- **hooks**: A list of events and the commands to run
(see :ref:`individual-hook-configuration`). Default: Empty.
- **hooks**: A list of events and the commands to run (see
:ref:`individual-hook-configuration`). Default: Empty.
.. _individual-hook-configuration:
Configuring Each Hook
'''''''''''''''''''''
~~~~~~~~~~~~~~~~~~~~~
Each element under ``hooks`` should have these keys:
- **event**: The name of the event that will trigger this hook.
See the :ref:`plugin events <plugin_events>` documentation for a list
of possible values.
- **event**: The name of the event that will trigger this hook. See the
:ref:`plugin events <plugin_events>` documentation for a list of possible
values.
- **command**: The command to run when this hook executes.
.. _command-substitution:
Command Substitution
''''''''''''''''''''
~~~~~~~~~~~~~~~~~~~~
Commands can access the parameters of events using `Python string
formatting`_. Use ``{name}`` in your command and the plugin will substitute it
with the named value. The name can also refer to a field, as in
``{album.path}``.
Commands can access the parameters of events using `Python string formatting`_.
Use ``{name}`` in your command and the plugin will substitute it with the named
value. The name can also refer to a field, as in ``{album.path}``.
.. _Python string formatting: https://www.python.org/dev/peps/pep-3101/
.. _python string formatting: https://www.python.org/dev/peps/pep-3101/
You can find a list of all available events and their arguments in the
:ref:`plugin events <plugin_events>` documentation.

View file

@ -2,9 +2,8 @@ IHate Plugin
============
The ``ihate`` plugin allows you to automatically skip things you hate during
import or warn you about them. You specify queries (see
:doc:`/reference/query`) and the plugin skips (or warns about) albums or items
that match any query.
import or warn you about them. You specify queries (see :doc:`/reference/query`)
and the plugin skips (or warns about) albums or items that match any query.
To use the ``ihate`` plugin, enable it in your configuration (see
:ref:`using-plugins`).
@ -12,15 +11,17 @@ To use the ``ihate`` plugin, enable it in your configuration (see
Configuration
-------------
To configure the plugin, make an ``ihate:`` section in your configuration
file. The available options are:
To configure the plugin, make an ``ihate:`` section in your configuration file.
The available options are:
- **skip**: Never import items and albums that match a query in this list.
Default: ``[]`` (empty list).
- **warn**: Print a warning message for matches in this list of queries.
Default: ``[]``.
Here's an example::
Here's an example:
::
ihate:
warn:

View file

@ -1,8 +1,8 @@
ImportAdded Plugin
==================
The ``importadded`` plugin is useful when an existing collection is imported
and the time when albums and items were added should be preserved.
The ``importadded`` plugin is useful when an existing collection is imported and
the time when albums and items were added should be preserved.
To use the ``importadded`` plugin, enable it in your configuration (see
:ref:`using-plugins`).
@ -11,30 +11,29 @@ Usage
-----
The :abbr:`mtime (modification time)` of files that are imported into the
library are assumed to represent the time when the items were originally
added.
library are assumed to represent the time when the items were originally added.
The ``item.added`` field is populated as follows:
* For singleton items with no album, ``item.added`` is set to the item's file
- For singleton items with no album, ``item.added`` is set to the item's file
mtime before it was imported.
* For items that are part of an album, ``album.added`` and ``item.added`` are
- For items that are part of an album, ``album.added`` and ``item.added`` are
set to the oldest mtime of the files in the album before they were imported.
The mtime of album directories is ignored.
This plugin can optionally be configured to also preserve mtimes at
import using the ``preserve_mtimes`` option.
This plugin can optionally be configured to also preserve mtimes at import using
the ``preserve_mtimes`` option.
When ``preserve_write_mtimes`` option is set, this plugin preserves
mtimes after each write to files using the ``item.added`` attribute.
When ``preserve_write_mtimes`` option is set, this plugin preserves mtimes after
each write to files using the ``item.added`` attribute.
File modification times are preserved as follows:
* For all items:
- For all items:
* ``item.mtime`` is set to the mtime of the file
from which the item is imported from.
* The mtime of the file ``item.path`` is set to ``item.mtime``.
- ``item.mtime`` is set to the mtime of the file from which the item is
imported from.
- The mtime of the file ``item.path`` is set to ``item.mtime``.
Note that there is no ``album.mtime`` field in the database and that the mtime
of album directories on disk aren't preserved.
@ -42,16 +41,13 @@ of album directories on disk aren't preserved.
Configuration
-------------
To configure the plugin, make an ``importadded:`` section in your
configuration file. There are two options available:
To configure the plugin, make an ``importadded:`` section in your configuration
file. There are two options available:
- **preserve_mtimes**: After importing files, re-set their mtimes to their
original value.
Default: ``no``.
original value. Default: ``no``.
- **preserve_write_mtimes**: After writing files, re-set their mtimes to their
original value.
Default: ``no``.
original value. Default: ``no``.
Reimport
--------

View file

@ -3,45 +3,43 @@ ImportFeeds Plugin
This plugin helps you keep track of newly imported music in your library.
To use the ``importfeeds`` plugin, enable it in your configuration
(see :ref:`using-plugins`).
To use the ``importfeeds`` plugin, enable it in your configuration (see
:ref:`using-plugins`).
Configuration
-------------
To configure the plugin, make an ``importfeeds:`` section in your
configuration file. The available options are:
To configure the plugin, make an ``importfeeds:`` section in your configuration
file. The available options are:
- **absolute_path**: Use absolute paths instead of relative paths. Some
applications may need this to work properly.
Default: ``no``.
- **dir**: The output directory.
Default: Your beets library directory.
applications may need this to work properly. Default: ``no``.
- **dir**: The output directory. Default: Your beets library directory.
- **formats**: Select the kind of output. Use one or more of:
- **m3u**: Catalog the imports in a centralized playlist.
- **m3u_multi**: Create a new playlist for each import (uniquely named by
appending the date and track/album name).
- **m3u_session**: Create a new playlist for each import session. The file
is named as ``m3u_name`` appending the date and time the import session
was started.
- **link**: Create a symlink for each imported item. This is the
recommended setting to propagate beets imports to your iTunes library:
just drag and drop the ``dir`` folder on the iTunes dock icon.
- **echo**: Do not write a playlist file at all, but echo a list of new
file paths to the terminal.
- **m3u**: Catalog the imports in a centralized playlist.
- **m3u_multi**: Create a new playlist for each import (uniquely named by
appending the date and track/album name).
- **m3u_session**: Create a new playlist for each import session. The file
is named as ``m3u_name`` appending the date and time the import session
was started.
- **link**: Create a symlink for each imported item. This is the
recommended setting to propagate beets imports to your iTunes library:
just drag and drop the ``dir`` folder on the iTunes dock icon.
- **echo**: Do not write a playlist file at all, but echo a list of new
file paths to the terminal.
Default: None.
- **m3u_name**: Playlist name used by the ``m3u`` format and as a prefix used
by the ``m3u_session`` format.
Default: ``imported.m3u``.
- **relative_to**: Make the m3u paths relative to another
folder than where the playlist is being written. If you're using importfeeds
to generate a playlist for MPD, you should set this to the root of your music
library.
Default: None.
Here's an example configuration for this plugin::
- **m3u_name**: Playlist name used by the ``m3u`` format and as a prefix used by
the ``m3u_session`` format. Default: ``imported.m3u``.
- **relative_to**: Make the m3u paths relative to another folder than where the
playlist is being written. If you're using importfeeds to generate a playlist
for MPD, you should set this to the root of your music library. Default: None.
Here's an example configuration for this plugin:
::
importfeeds:
formats: m3u link

View file

@ -13,7 +13,8 @@ Using Plugins
-------------
To use one of the plugins included with beets (see the rest of this page for a
list), just use the ``plugins`` option in your :doc:`config.yaml </reference/config>` file:
list), just use the ``plugins`` option in your :doc:`config.yaml
</reference/config>` file:
.. code-block:: sh
@ -23,7 +24,8 @@ The value for ``plugins`` can be a space-separated list of plugin names or a
YAML list like ``[foo, bar]``. You can see which plugins are currently enabled
by typing ``beet version``.
Each plugin has its own set of options that can be defined in a section bearing its name:
Each plugin has its own set of options that can be defined in a section bearing
its name:
.. code-block:: yaml
@ -33,8 +35,8 @@ Each plugin has its own set of options that can be defined in a section bearing
auto: true
Some plugins have special dependencies that you'll need to install. The
documentation page for each plugin will list them in the setup instructions.
For some, you can use ``pip``'s "extras" feature to install the dependencies:
documentation page for each plugin will list them in the setup instructions. For
some, you can use ``pip``'s "extras" feature to install the dependencies:
.. code-block:: sh
@ -49,8 +51,7 @@ Some plugins provide sources for metadata in addition to MusicBrainz. These
plugins share the following configuration option:
- **source_weight**: Penalty applied to matches during import. Set to 0.0 to
disable.
Default: ``0.5``.
disable. Default: ``0.5``.
For example, to equally consider matches from Discogs and MusicBrainz add the
following to your configuration:
@ -62,85 +63,84 @@ following to your configuration:
discogs:
source_weight: 0.0
.. toctree::
:hidden:
:hidden:
absubmit
acousticbrainz
advancedrewrite
albumtypes
aura
autobpm
badfiles
bareasc
beatport
bpd
bpm
bpsync
bucket
chroma
convert
deezer
discogs
duplicates
edit
embedart
embyupdate
export
fetchart
filefilter
fish
freedesktop
fromfilename
ftintitle
fuzzy
gmusic
hook
ihate
importadded
importfeeds
info
inline
ipfs
keyfinder
kodiupdate
lastgenre
lastimport
limit
listenbrainz
loadext
lyrics
mbcollection
mbsubmit
mbsync
metasync
missing
mpdstats
mpdupdate
musicbrainz
parentwork
permissions
play
playlist
plexupdate
random
replace
replaygain
rewrite
scrub
smartplaylist
sonosupdate
spotify
subsonicplaylist
subsonicupdate
substitute
the
thumbnails
types
unimported
web
zero
absubmit
acousticbrainz
advancedrewrite
albumtypes
aura
autobpm
badfiles
bareasc
beatport
bpd
bpm
bpsync
bucket
chroma
convert
deezer
discogs
duplicates
edit
embedart
embyupdate
export
fetchart
filefilter
fish
freedesktop
fromfilename
ftintitle
fuzzy
gmusic
hook
ihate
importadded
importfeeds
info
inline
ipfs
keyfinder
kodiupdate
lastgenre
lastimport
limit
listenbrainz
loadext
lyrics
mbcollection
mbsubmit
mbsync
metasync
missing
mpdstats
mpdupdate
musicbrainz
parentwork
permissions
play
playlist
plexupdate
random
replace
replaygain
rewrite
scrub
smartplaylist
sonosupdate
spotify
subsonicplaylist
subsonicupdate
substitute
the
thumbnails
types
unimported
web
zero
.. _autotagger_extensions:
@ -148,259 +148,263 @@ Autotagger Extensions
---------------------
:doc:`chroma <chroma>`
Use acoustic fingerprinting to identify audio files with
missing or incorrect metadata.
Use acoustic fingerprinting to identify audio files with missing or
incorrect metadata.
:doc:`deezer <deezer>`
Search for releases in the `Deezer`_ database.
Search for releases in the Deezer_ database.
:doc:`discogs <discogs>`
Search for releases in the `Discogs`_ database.
Search for releases in the Discogs_ database.
:doc:`fromfilename <fromfilename>`
Guess metadata for untagged tracks from their filenames.
Guess metadata for untagged tracks from their filenames.
:doc:`musicbrainz <musicbrainz>`
Search for releases in the `MusicBrainz`_ database.
Search for releases in the MusicBrainz_ database.
:doc:`spotify <spotify>`
Search for releases in the `Spotify`_ database.
Search for releases in the Spotify_ database.
.. _deezer: https://www.deezer.com
.. _Deezer: https://www.deezer.com
.. _Discogs: https://www.discogs.com
.. _MusicBrainz: https://www.musicbrainz.com
.. _Spotify: https://www.spotify.com
.. _discogs: https://www.discogs.com
.. _musicbrainz: https://www.musicbrainz.com
.. _spotify: https://www.spotify.com
Metadata
--------
:doc:`absubmit <absubmit>`
Analyse audio with the `streaming_extractor_music`_ program and submit the metadata to an AcousticBrainz server
Analyse audio with the streaming_extractor_music_ program and submit the
metadata to an AcousticBrainz server
:doc:`acousticbrainz <acousticbrainz>`
Fetch various AcousticBrainz metadata
Fetch various AcousticBrainz metadata
:doc:`autobpm <autobpm>`
Use `Librosa`_ to calculate the BPM from the audio.
Use Librosa_ to calculate the BPM from the audio.
:doc:`bpm <bpm>`
Measure tempo using keystrokes.
Measure tempo using keystrokes.
:doc:`bpsync <bpsync>`
Fetch updated metadata from Beatport.
Fetch updated metadata from Beatport.
:doc:`edit <edit>`
Edit metadata from a text editor.
Edit metadata from a text editor.
:doc:`embedart <embedart>`
Embed album art images into files' metadata.
Embed album art images into files' metadata.
:doc:`fetchart <fetchart>`
Fetch album cover art from various sources.
Fetch album cover art from various sources.
:doc:`ftintitle <ftintitle>`
Move "featured" artists from the artist field to the title
field.
Move "featured" artists from the artist field to the title field.
:doc:`keyfinder <keyfinder>`
Use the `KeyFinder`_ program to detect the musical
key from the audio.
Use the KeyFinder_ program to detect the musical key from the audio.
:doc:`importadded <importadded>`
Use file modification times for guessing the value for
the `added` field in the database.
Use file modification times for guessing the value for the ``added`` field
in the database.
:doc:`lastgenre <lastgenre>`
Fetch genres based on Last.fm tags.
Fetch genres based on Last.fm tags.
:doc:`lastimport <lastimport>`
Collect play counts from Last.fm.
Collect play counts from Last.fm.
:doc:`lyrics <lyrics>`
Automatically fetch song lyrics.
Automatically fetch song lyrics.
:doc:`mbsync <mbsync>`
Fetch updated metadata from MusicBrainz.
Fetch updated metadata from MusicBrainz.
:doc:`metasync <metasync>`
Fetch metadata from local or remote sources
Fetch metadata from local or remote sources
:doc:`mpdstats <mpdstats>`
Connect to `MPD`_ and update the beets library with play
statistics (last_played, play_count, skip_count, rating).
Connect to MPD_ and update the beets library with play statistics
(last_played, play_count, skip_count, rating).
:doc:`parentwork <parentwork>`
Fetch work titles and works they are part of.
Fetch work titles and works they are part of.
:doc:`replaygain <replaygain>`
Calculate volume normalization for players that support it.
Calculate volume normalization for players that support it.
:doc:`scrub <scrub>`
Clean extraneous metadata from music files.
Clean extraneous metadata from music files.
:doc:`zero <zero>`
Nullify fields by pattern or unconditionally.
Nullify fields by pattern or unconditionally.
.. _keyfinder: http://www.ibrahimshaath.co.uk/keyfinder/
.. _librosa: https://github.com/librosa/librosa/
.. _Librosa: https://github.com/librosa/librosa/
.. _KeyFinder: http://www.ibrahimshaath.co.uk/keyfinder/
.. _streaming_extractor_music: https://acousticbrainz.org/download
Path Formats
------------
:doc:`albumtypes <albumtypes>`
Format album type in path formats.
Format album type in path formats.
:doc:`bucket <bucket>`
Group your files into bucket directories that cover different
field values ranges.
Group your files into bucket directories that cover different field values
ranges.
:doc:`inline <inline>`
Use Python snippets to customize path format strings.
Use Python snippets to customize path format strings.
:doc:`rewrite <rewrite>`
Substitute values in path formats.
Substitute values in path formats.
:doc:`advancedrewrite <advancedrewrite>`
Substitute field values for items matching a query.
Substitute field values for items matching a query.
:doc:`substitute <substitute>`
As an alternative to :doc:`rewrite <rewrite>`, use this plugin. The main
difference between them is that this plugin never modifies the files
metadata.
As an alternative to :doc:`rewrite <rewrite>`, use this plugin. The main
difference between them is that this plugin never modifies the files
metadata.
:doc:`the <the>`
Move patterns in path formats (i.e., move "a" and "the" to the
end).
Move patterns in path formats (i.e., move "a" and "the" to the end).
Interoperability
----------------
:doc:`aura <aura>`
A server implementation of the `AURA`_ specification.
A server implementation of the AURA_ specification.
:doc:`badfiles <badfiles>`
Check audio file integrity.
Check audio file integrity.
:doc:`embyupdate <embyupdate>`
Automatically notifies `Emby`_ whenever the beets library changes.
Automatically notifies Emby_ whenever the beets library changes.
:doc:`fish <fish>`
Adds `Fish shell`_ tab autocompletion to ``beet`` commands.
Adds `Fish shell`_ tab autocompletion to ``beet`` commands.
:doc:`importfeeds <importfeeds>`
Keep track of imported files via ``.m3u`` playlist file(s) or symlinks.
Keep track of imported files via ``.m3u`` playlist file(s) or symlinks.
:doc:`ipfs <ipfs>`
Import libraries from friends and get albums from them via ipfs.
Import libraries from friends and get albums from them via ipfs.
:doc:`kodiupdate <kodiupdate>`
Automatically notifies `Kodi`_ whenever the beets library
changes.
Automatically notifies Kodi_ whenever the beets library changes.
:doc:`mpdupdate <mpdupdate>`
Automatically notifies `MPD`_ whenever the beets library
changes.
Automatically notifies MPD_ whenever the beets library changes.
:doc:`play <play>`
Play beets queries in your music player.
Play beets queries in your music player.
:doc:`playlist <playlist>`
Use M3U playlists to query the beets library.
Use M3U playlists to query the beets library.
:doc:`plexupdate <plexupdate>`
Automatically notifies `Plex`_ whenever the beets library
changes.
Automatically notifies Plex_ whenever the beets library changes.
:doc:`smartplaylist <smartplaylist>`
Generate smart playlists based on beets queries.
Generate smart playlists based on beets queries.
:doc:`sonosupdate <sonosupdate>`
Automatically notifies `Sonos`_ whenever the beets library
changes.
Automatically notifies Sonos_ whenever the beets library changes.
:doc:`thumbnails <thumbnails>`
Get thumbnails with the cover art on your album folders.
Get thumbnails with the cover art on your album folders.
:doc:`subsonicupdate <subsonicupdate>`
Automatically notifies `Subsonic`_ whenever the beets
library changes.
Automatically notifies Subsonic_ whenever the beets library changes.
.. _aura: https://auraspec.readthedocs.io
.. _AURA: https://auraspec.readthedocs.io
.. _Emby: https://emby.media
.. _Fish shell: https://fishshell.com/
.. _Plex: https://plex.tv
.. _Kodi: https://kodi.tv
.. _Sonos: https://sonos.com
.. _Subsonic: http://www.subsonic.org/
.. _emby: https://emby.media
.. _fish shell: https://fishshell.com/
.. _kodi: https://kodi.tv
.. _plex: https://plex.tv
.. _sonos: https://sonos.com
.. _subsonic: http://www.subsonic.org/
Miscellaneous
-------------
:doc:`bareasc <bareasc>`
Search albums and tracks with bare ASCII string matching.
Search albums and tracks with bare ASCII string matching.
:doc:`bpd <bpd>`
A music player for your beets library that emulates `MPD`_ and is
compatible with `MPD clients`_.
A music player for your beets library that emulates MPD_ and is compatible
with `MPD clients`_.
:doc:`convert <convert>`
Transcode music and embed album art while exporting to
a different directory.
Transcode music and embed album art while exporting to a different
directory.
:doc:`duplicates <duplicates>`
List duplicate tracks or albums.
List duplicate tracks or albums.
:doc:`export <export>`
Export data from queries to a format.
Export data from queries to a format.
:doc:`filefilter <filefilter>`
Automatically skip files during the import process based
on regular expressions.
Automatically skip files during the import process based on regular
expressions.
:doc:`fuzzy <fuzzy>`
Search albums and tracks with fuzzy string matching.
Search albums and tracks with fuzzy string matching.
:doc:`hook <hook>`
Run a command when an event is emitted by beets.
Run a command when an event is emitted by beets.
:doc:`ihate <ihate>`
Automatically skip albums and tracks during the import process.
Automatically skip albums and tracks during the import process.
:doc:`info <info>`
Print music files' tags to the console.
Print music files' tags to the console.
:doc:`loadext <loadext>`
Load SQLite extensions.
Load SQLite extensions.
:doc:`mbcollection <mbcollection>`
Maintain your MusicBrainz collection list.
Maintain your MusicBrainz collection list.
:doc:`mbsubmit <mbsubmit>`
Print an album's tracks in a MusicBrainz-friendly format.
Print an album's tracks in a MusicBrainz-friendly format.
:doc:`missing <missing>`
List missing tracks.
List missing tracks.
`mstream`_
A music streaming server + webapp that can be used alongside beets.
mstream_
A music streaming server + webapp that can be used alongside beets.
:doc:`random <random>`
Randomly choose albums and tracks from your library.
Randomly choose albums and tracks from your library.
:doc:`spotify <spotify>`
Create Spotify playlists from the Beets library.
Create Spotify playlists from the Beets library.
:doc:`types <types>`
Declare types for flexible attributes.
Declare types for flexible attributes.
:doc:`web <web>`
An experimental Web-based GUI for beets.
An experimental Web-based GUI for beets.
.. _mpd: https://www.musicpd.org/
.. _mpd clients: https://mpd.wikia.com/wiki/Clients
.. _MPD: https://www.musicpd.org/
.. _MPD clients: https://mpd.wikia.com/wiki/Clients
.. _mstream: https://github.com/IrosTheBeggar/mStream
.. _other-plugins:
@ -408,204 +412,248 @@ Miscellaneous
Other Plugins
-------------
In addition to the plugins that come with beets, there are several plugins
that are maintained by the beets community. To use an external plugin, there
are two options for installation:
In addition to the plugins that come with beets, there are several plugins that
are maintained by the beets community. To use an external plugin, there are two
options for installation:
* Make sure it's in the Python path (known as ``sys.path`` to developers). This
- Make sure it's in the Python path (known as ``sys.path`` to developers). This
just means the plugin has to be installed on your system (e.g., with a
``setup.py`` script or a command like ``pip`` or ``easy_install``).
* Set the ``pluginpath`` config variable to point to the directory containing the
plugin. (See :doc:`/reference/config`.)
- Set the ``pluginpath`` config variable to point to the directory containing
the plugin. (See :doc:`/reference/config`.)
Once the plugin is installed, enable it by placing its name on the ``plugins``
line in your config file.
Here are a few of the plugins written by the beets community:
`beets-alternatives`_
Manages external files.
beets-alternatives_
Manages external files.
`beet-amazon`_
Adds Amazon.com as a tagger data source.
beet-amazon_
Adds Amazon.com as a tagger data source.
`beets-artistcountry`_
Fetches the artist's country of origin from MusicBrainz.
beets-artistcountry_
Fetches the artist's country of origin from MusicBrainz.
`beets-autofix`_
Automates repetitive tasks to keep your library in order.
beets-autofix_
Automates repetitive tasks to keep your library in order.
`beets-autogenre`_
Assigns genres to your library items using the :doc:`lastgenre <lastgenre>`
and `beets-xtractor`_ plugins as well as additional rules.
beets-autogenre_
Assigns genres to your library items using the :doc:`lastgenre <lastgenre>`
and beets-xtractor_ plugins as well as additional rules.
`beets-audible`_
Adds Audible as a tagger data source and provides
other features for managing audiobook collections.
beets-audible_
Adds Audible as a tagger data source and provides other features for
managing audiobook collections.
`beets-barcode`_
Lets you scan or enter barcodes for physical media to
search for their metadata.
beets-barcode_
Lets you scan or enter barcodes for physical media to search for their
metadata.
`beetcamp`_
Enables **bandcamp.com** autotagger with a fairly extensive amount of metadata.
beetcamp_
Enables **bandcamp.com** autotagger with a fairly extensive amount of
metadata.
`beetstream`_
Server implementation of the `Subsonic API`_ specification, serving the
beets library and (:doc:`smartplaylist <smartplaylist>` plugin generated)
M3U playlists, allowing you to stream your music on a multitude of clients.
beetstream_
Server implementation of the `Subsonic API`_ specification, serving the
beets library and (:doc:`smartplaylist <smartplaylist>` plugin generated)
M3U playlists, allowing you to stream your music on a multitude of clients.
`beets-bpmanalyser`_
Analyses songs and calculates their tempo (BPM).
beets-bpmanalyser_
Analyses songs and calculates their tempo (BPM).
`beets-check`_
Automatically checksums your files to detect corruption.
beets-check_
Automatically checksums your files to detect corruption.
`A cmus plugin`_
Integrates with the `cmus`_ console music player.
Integrates with the cmus_ console music player.
`beets-copyartifacts`_
Helps bring non-music files along during import.
beets-copyartifacts_
Helps bring non-music files along during import.
`beets-describe`_
Gives you the full picture of a single attribute of your library items.
beets-describe_
Gives you the full picture of a single attribute of your library items.
`drop2beets`_
Automatically imports singles as soon as they are dropped in a
folder (using Linux's ``inotify``). You can also set a sub-folders
hierarchy to set flexible attributes by the way.
drop2beets_
Automatically imports singles as soon as they are dropped in a folder (using
Linux's ``inotify``). You can also set a sub-folders hierarchy to set
flexible attributes by the way.
`dsedivec`_
Has two plugins: ``edit`` and ``moveall``.
dsedivec_
Has two plugins: ``edit`` and ``moveall``.
`beets-filetote`_
Helps bring non-music extra files, attachments, and artifacts during
imports and CLI file manipulation actions (`beet move`, etc.).
beets-filetote_
Helps bring non-music extra files, attachments, and artifacts during imports
and CLI file manipulation actions (``beet move``, etc.).
`beets-follow`_
Lets you check for new albums from artists you like.
beets-follow_
Lets you check for new albums from artists you like.
`beetFs`_
Is a FUSE filesystem for browsing the music in your beets library.
(Might be out of date.)
beetFs_
Is a FUSE filesystem for browsing the music in your beets library. (Might be
out of date.)
`beets-goingrunning`_
Generates playlists to go with your running sessions.
beets-goingrunning_
Generates playlists to go with your running sessions.
`beets-ibroadcast`_
Uploads tracks to the `iBroadcast`_ cloud service.
beets-ibroadcast_
Uploads tracks to the iBroadcast_ cloud service.
`beets-id3extract`_
Maps arbitrary ID3 tags to beets custom fields.
beets-id3extract_
Maps arbitrary ID3 tags to beets custom fields.
`beets-importreplace`_
Lets you perform regex replacements on incoming
metadata.
beets-importreplace_
Lets you perform regex replacements on incoming metadata.
`beets-jiosaavn`_
Adds JioSaavn.com as a tagger data source.
beets-jiosaavn_
Adds JioSaavn.com as a tagger data source.
`beets-more`_
Finds versions of indexed releases with more tracks, like deluxe and anniversary editions.
beets-more_
Finds versions of indexed releases with more tracks, like deluxe and
anniversary editions.
`beets-mosaic`_
Generates a montage of a mosaic from cover art.
beets-mosaic_
Generates a montage of a mosaic from cover art.
`beets-mpd-utils`_
Plugins to interface with `MPD`_. Comes with ``mpd_tracker`` (track play/skip counts from MPD) and ``mpd_dj`` (auto-add songs to your queue.)
beets-mpd-utils_
Plugins to interface with MPD_. Comes with ``mpd_tracker`` (track play/skip
counts from MPD) and ``mpd_dj`` (auto-add songs to your queue.)
`beets-noimport`_
Adds and removes directories from the incremental import skip list.
beets-noimport_
Adds and removes directories from the incremental import skip list.
`beets-originquery`_
Augments MusicBrainz queries with locally-sourced data
to improve autotagger results.
beets-originquery_
Augments MusicBrainz queries with locally-sourced data to improve autotagger
results.
`beets-plexsync`_
Allows you to sync your Plex library with your beets library, create smart playlists in Plex, and import online playlists (from services like Spotify) into Plex.
beets-plexsync_
Allows you to sync your Plex library with your beets library, create smart
playlists in Plex, and import online playlists (from services like Spotify)
into Plex.
`beets-setlister`_
Generate playlists from the setlists of a given artist.
beets-setlister_
Generate playlists from the setlists of a given artist.
`beet-summarize`_
Can compute lots of counts and statistics about your music
library.
beet-summarize_
Can compute lots of counts and statistics about your music library.
`beets-usertag`_
Lets you use keywords to tag and organize your music.
beets-usertag_
Lets you use keywords to tag and organize your music.
`beets-webm3u`_
Serves the (:doc:`smartplaylist <smartplaylist>` plugin generated) M3U
playlists via HTTP.
beets-webm3u_
Serves the (:doc:`smartplaylist <smartplaylist>` plugin generated) M3U
playlists via HTTP.
`beets-webrouter`_
Serves multiple beets webapps (e.g. :doc:`web <web>`, `beets-webm3u`_,
`beetstream`_, :doc:`aura <aura>`) using a single command/process/host/port,
each under a different path.
beets-webrouter_
Serves multiple beets webapps (e.g. :doc:`web <web>`, beets-webm3u_,
beetstream_, :doc:`aura <aura>`) using a single command/process/host/port,
each under a different path.
`whatlastgenre`_
Fetches genres from various music sites.
whatlastgenre_
Fetches genres from various music sites.
`beets-xtractor`_
Extracts low- and high-level musical information from your songs.
beets-xtractor_
Extracts low- and high-level musical information from your songs.
`beets-ydl`_
Downloads audio from youtube-dl sources and import into beets.
beets-ydl_
Downloads audio from youtube-dl sources and import into beets.
`beets-ytimport`_
Download and import your liked songs from YouTube into beets.
beets-ytimport_
Download and import your liked songs from YouTube into beets.
`beets-yearfixer`_
Attempts to fix all missing ``original_year`` and ``year`` fields.
beets-yearfixer_
Attempts to fix all missing ``original_year`` and ``year`` fields.
`beets-youtube`_
Adds YouTube Music as a tagger data source.
beets-youtube_
Adds YouTube Music as a tagger data source.
.. _a cmus plugin: https://github.com/coolkehon/beets/blob/master/beetsplug/cmus.py
.. _beet-amazon: https://github.com/jmwatte/beet-amazon
.. _beet-musicbrainz-collection: https://github.com/jeffayle/Beet-MusicBrainz-Collection/
.. _beet-summarize: https://github.com/steven-murray/beet-summarize
.. _beetcamp: https://github.com/snejus/beetcamp
.. _beetfs: https://github.com/jbaiter/beetfs
.. _beets-alternatives: https://github.com/geigerzaehler/beets-alternatives
.. _beets-artistcountry: https://github.com/agrausem/beets-artistcountry
.. _beets-audible: https://github.com/Neurrone/beets-audible
.. _beets-autofix: https://github.com/adamjakab/BeetsPluginAutofix
.. _beets-autogenre: https://github.com/mgoltzsche/beets-autogenre
.. _beets-barcode: https://github.com/8h2a/beets-barcode
.. _beetcamp: https://github.com/snejus/beetcamp
.. _beetstream: https://github.com/BinaryBrain/Beetstream
.. _Subsonic API: http://www.subsonic.org/pages/api.jsp
.. _beets-check: https://github.com/geigerzaehler/beets-check
.. _beets-copyartifacts: https://github.com/adammillerio/beets-copyartifacts
.. _dsedivec: https://github.com/dsedivec/beets-plugins
.. _beets-artistcountry: https://github.com/agrausem/beets-artistcountry
.. _beetFs: https://github.com/jbaiter/beetfs
.. _Beet-MusicBrainz-Collection:
https://github.com/jeffayle/Beet-MusicBrainz-Collection/
.. _A cmus plugin:
https://github.com/coolkehon/beets/blob/master/beetsplug/cmus.py
.. _cmus: http://cmus.sourceforge.net/
.. _beet-amazon: https://github.com/jmwatte/beet-amazon
.. _beets-alternatives: https://github.com/geigerzaehler/beets-alternatives
.. _beets-filetote: https://github.com/gtronset/beets-filetote
.. _beets-follow: https://github.com/nolsto/beets-follow
.. _beets-ibroadcast: https://github.com/ctrueden/beets-ibroadcast
.. _iBroadcast: https://ibroadcast.com/
.. _beets-id3extract: https://github.com/bcotton/beets-id3extract
.. _beets-importreplace: https://github.com/edgars-supe/beets-importreplace
.. _beets-setlister: https://github.com/tomjaspers/beets-setlister
.. _beets-noimport: https://gitlab.com/tiago.dias/beets-noimport
.. _whatlastgenre: https://github.com/YetAnotherNerd/whatlastgenre/tree/master/plugin/beets
.. _beets-usertag: https://github.com/igordertigor/beets-usertag
.. _beets-plexsync: https://github.com/arsaboo/beets-plexsync
.. _beets-jiosaavn: https://github.com/arsaboo/beets-jiosaavn
.. _beets-youtube: https://github.com/arsaboo/beets-youtube
.. _beets-ydl: https://github.com/vmassuchetto/beets-ydl
.. _beets-ytimport: https://github.com/mgoltzsche/beets-ytimport
.. _beet-summarize: https://github.com/steven-murray/beet-summarize
.. _beets-mosaic: https://github.com/SusannaMaria/beets-mosaic
.. _beets-goingrunning: https://pypi.org/project/beets-goingrunning
.. _beets-xtractor: https://github.com/adamjakab/BeetsPluginXtractor
.. _beets-yearfixer: https://github.com/adamjakab/BeetsPluginYearFixer
.. _beets-autofix: https://github.com/adamjakab/BeetsPluginAutofix
.. _beets-describe: https://github.com/adamjakab/BeetsPluginDescribe
.. _beets-bpmanalyser: https://github.com/adamjakab/BeetsPluginBpmAnalyser
.. _beets-originquery: https://github.com/x1ppy/beets-originquery
.. _drop2beets: https://github.com/martinkirch/drop2beets
.. _beets-audible: https://github.com/Neurrone/beets-audible
.. _beets-check: https://github.com/geigerzaehler/beets-check
.. _beets-copyartifacts: https://github.com/adammillerio/beets-copyartifacts
.. _beets-describe: https://github.com/adamjakab/BeetsPluginDescribe
.. _beets-filetote: https://github.com/gtronset/beets-filetote
.. _beets-follow: https://github.com/nolsto/beets-follow
.. _beets-goingrunning: https://pypi.org/project/beets-goingrunning
.. _beets-ibroadcast: https://github.com/ctrueden/beets-ibroadcast
.. _beets-id3extract: https://github.com/bcotton/beets-id3extract
.. _beets-importreplace: https://github.com/edgars-supe/beets-importreplace
.. _beets-jiosaavn: https://github.com/arsaboo/beets-jiosaavn
.. _beets-more: https://forgejo.sny.sh/sun/beetsplug/src/branch/main/more
.. _beets-mosaic: https://github.com/SusannaMaria/beets-mosaic
.. _beets-mpd-utils: https://github.com/thekakkun/beets-mpd-utils
.. _beets-noimport: https://gitlab.com/tiago.dias/beets-noimport
.. _beets-originquery: https://github.com/x1ppy/beets-originquery
.. _beets-plexsync: https://github.com/arsaboo/beets-plexsync
.. _beets-setlister: https://github.com/tomjaspers/beets-setlister
.. _beets-usertag: https://github.com/igordertigor/beets-usertag
.. _beets-webm3u: https://github.com/mgoltzsche/beets-webm3u
.. _beets-webrouter: https://github.com/mgoltzsche/beets-webrouter
.. _beets-autogenre: https://github.com/mgoltzsche/beets-autogenre
.. _beets-xtractor: https://github.com/adamjakab/BeetsPluginXtractor
.. _beets-ydl: https://github.com/vmassuchetto/beets-ydl
.. _beets-yearfixer: https://github.com/adamjakab/BeetsPluginYearFixer
.. _beets-youtube: https://github.com/arsaboo/beets-youtube
.. _beets-ytimport: https://github.com/mgoltzsche/beets-ytimport
.. _beetstream: https://github.com/BinaryBrain/Beetstream
.. _cmus: http://cmus.sourceforge.net/
.. _drop2beets: https://github.com/martinkirch/drop2beets
.. _dsedivec: https://github.com/dsedivec/beets-plugins
.. _ibroadcast: https://ibroadcast.com/
.. _subsonic api: http://www.subsonic.org/pages/api.jsp
.. _whatlastgenre: https://github.com/YetAnotherNerd/whatlastgenre/tree/master/plugin/beets

View file

@ -1,45 +1,52 @@
Info Plugin
===========
The ``info`` plugin provides a command that dumps the current tag values for
any file format supported by beets. It works like a supercharged version of
`mp3info`_ or `id3v2`_.
The ``info`` plugin provides a command that dumps the current tag values for any
file format supported by beets. It works like a supercharged version of mp3info_
or id3v2_.
Enable the ``info`` plugin in your configuration (see :ref:`using-plugins`) and
then type::
then type:
::
$ beet info /path/to/music.flac
and the plugin will enumerate all the tags in the specified file. It also
accepts multiple filenames in a single command-line.
You can also enter a :doc:`query </reference/query>` to inspect music from
your library::
You can also enter a :doc:`query </reference/query>` to inspect music from your
library:
::
$ beet info beatles
If you just want to see specific properties you can use the
``--include-keys`` option to filter them. The argument is a
comma-separated list of field names. For example::
If you just want to see specific properties you can use the ``--include-keys``
option to filter them. The argument is a comma-separated list of field names.
For example:
::
$ beet info -i 'title,mb_artistid' beatles
Will only show the ``title`` and ``mb_artistid`` properties. You can add the
Will only show the ``title`` and ``mb_artistid`` properties. You can add the
``-i`` option multiple times to the command line.
Additional command-line options include:
* ``--library`` or ``-l``: Show data from the library database instead of the
- ``--library`` or ``-l``: Show data from the library database instead of the
files' tags.
* ``--album`` or ``-a``: Show data from albums instead of tracks (implies
- ``--album`` or ``-a``: Show data from albums instead of tracks (implies
``--library``).
* ``--summarize`` or ``-s``: Merge all the information from multiple files
into a single list of values. If the tags differ across the files, print
- ``--summarize`` or ``-s``: Merge all the information from multiple files into
a single list of values. If the tags differ across the files, print
``[various]``.
* ``--format`` or ``-f``: Specify a specific format with which to print every
- ``--format`` or ``-f``: Specify a specific format with which to print every
item. This uses the same template syntax as beets :doc:`path formats
</reference/pathformat>`.
* ``--keys-only`` or ``-k``: Show the name of the tags without the values.
- ``--keys-only`` or ``-k``: Show the name of the tags without the values.
.. _id3v2: http://id3v2.sourceforge.net
.. _mp3info: https://www.ibiblio.org/mp3info/

View file

@ -2,20 +2,21 @@ Inline Plugin
=============
The ``inline`` plugin lets you use Python to customize your path formats. Using
it, you can define template fields in your beets configuration file and refer
to them from your template strings in the ``paths:`` section (see
it, you can define template fields in your beets configuration file and refer to
them from your template strings in the ``paths:`` section (see
:doc:`/reference/config/`).
To use the ``inline`` plugin, enable it in your configuration
(see :ref:`using-plugins`).
Then, make a ``item_fields:`` block in your config file. Under this key, every line defines a
new template field; the key is the name of the field (you'll use the name to
refer to the field in your templates) and the value is a Python expression or
function body. The Python code has all of a track's fields in scope, so you can
refer to any normal attributes (such as ``artist`` or ``title``) as Python
variables.
To use the ``inline`` plugin, enable it in your configuration (see
:ref:`using-plugins`). Then, make a ``item_fields:`` block in your config file.
Under this key, every line defines a new template field; the key is the name of
the field (you'll use the name to refer to the field in your templates) and the
value is a Python expression or function body. The Python code has all of a
track's fields in scope, so you can refer to any normal attributes (such as
``artist`` or ``title``) as Python variables.
Here are a couple of examples of expressions::
Here are a couple of examples of expressions:
::
item_fields:
initial: albumartist[0].upper() + u'.'
@ -26,18 +27,21 @@ Note that YAML syntax allows newlines in values if the subsequent lines are
indented.
These examples define ``$initial`` and ``$disc_and_track`` fields that can be
referenced in path templates like so::
referenced in path templates like so:
::
paths:
default: $initial/$artist/$album%aunique{}/$disc_and_track $title
Block Definitions
-----------------
If you need to use statements like ``import``, you can write a Python function
body instead of a single expression. In this case, you'll need to ``return``
a result for the value of the path field, like so::
body instead of a single expression. In this case, you'll need to ``return`` a
result for the value of the path field, like so:
::
item_fields:
filename: |
@ -48,17 +52,18 @@ a result for the value of the path field, like so::
You might want to use the YAML syntax for "block literals," in which a leading
``|`` character indicates a multi-line block of text.
Album Fields
------------
The above examples define fields for *item* templates, but you can also define
fields for *album* templates. Use the ``album_fields`` configuration section.
In this context, all existing album fields are available as variables along
with ``items``, which is a list of items in the album.
fields for *album* templates. Use the ``album_fields`` configuration section. In
this context, all existing album fields are available as variables along with
``items``, which is a list of items in the album.
This example defines a ``$bitrate`` field for albums as the average of the
tracks' fields::
tracks' fields:
::
album_fields:
bitrate: |

View file

@ -2,15 +2,15 @@ IPFS Plugin
===========
The ``ipfs`` plugin makes it easy to share your library and music with friends.
The plugin uses `ipfs`_ for storing the library and file content.
The plugin uses ipfs_ for storing the library and file content.
.. _ipfs: https://ipfs.io/
Installation
------------
This plugin requires `go-ipfs`_ to be running as a daemon and that the
associated ``ipfs`` command is on the user's ``$PATH``.
This plugin requires go-ipfs_ to be running as a daemon and that the associated
``ipfs`` command is on the user's ``$PATH``.
.. _go-ipfs: https://github.com/ipfs/go-ipfs
@ -24,51 +24,54 @@ This plugin can store and retrieve music individually, or it can share entire
library databases.
Adding
''''''
~~~~~~
To add albums to ipfs, making them shareable, use the ``-a`` or ``--add``
flag. If used without arguments it will add all albums in the local library.
When added, all items and albums will get an "ipfs" field in the database
containing the hash of that specific file/folder. Newly imported albums will
be added automatically to ipfs by default (see below).
To add albums to ipfs, making them shareable, use the ``-a`` or ``--add`` flag.
If used without arguments it will add all albums in the local library. When
added, all items and albums will get an "ipfs" field in the database containing
the hash of that specific file/folder. Newly imported albums will be added
automatically to ipfs by default (see below).
Retrieving
''''''''''
~~~~~~~~~~
You can give the ipfs hash for some music to a friend. They can get that album
from ipfs, and import it into beets, using the ``-g`` or ``--get`` flag. If
the argument passed to the ``-g`` flag isn't an ipfs hash, it will be used as
a query instead, getting all albums matching the query.
from ipfs, and import it into beets, using the ``-g`` or ``--get`` flag. If the
argument passed to the ``-g`` flag isn't an ipfs hash, it will be used as a
query instead, getting all albums matching the query.
Sharing Libraries
'''''''''''''''''
~~~~~~~~~~~~~~~~~
Using the ``-p`` or ``--publish`` flag, a copy of the local library will be
published to ipfs. Only albums/items with ipfs records in the database will
published, and local paths will be stripped from the library. A hash of the
library will be returned to the user.
A friend can then import this remote library by using the ``-i`` or
``--import`` flag. To tag an imported library with a specific name by passing
a name as the second argument to ``-i,`` after the hash. The content of all
remote libraries will be combined into an additional library as long as the
content doesn't already exist in the joined library.
A friend can then import this remote library by using the ``-i`` or ``--import``
flag. To tag an imported library with a specific name by passing a name as the
second argument to ``-i,`` after the hash. The content of all remote libraries
will be combined into an additional library as long as the content doesn't
already exist in the joined library.
When remote libraries has been imported you can search them by using the
``-l`` or ``--list`` flag. The hash of albums matching the query will be
returned, and this can then be used with ``-g`` to fetch and import the album
to the local library.
When remote libraries has been imported you can search them by using the ``-l``
or ``--list`` flag. The hash of albums matching the query will be returned, and
this can then be used with ``-g`` to fetch and import the album to the local
library.
Ipfs can be mounted as a FUSE file system. This means that music in a remote
library can be streamed directly, without importing them to the local library
first. If the ``/ipfs`` folder is mounted then matching queries will be sent
to the :doc:`/plugins/play` using the ``-m`` or ``--play`` flag.
first. If the ``/ipfs`` folder is mounted then matching queries will be sent to
the :doc:`/plugins/play` using the ``-m`` or ``--play`` flag.
Configuration
-------------
The ipfs plugin will automatically add imported albums to ipfs and add those
hashes to the database. This can be turned off by setting the ``auto`` option
in the ``ipfs:`` section of the config to ``no``.
hashes to the database. This can be turned off by setting the ``auto`` option in
the ``ipfs:`` section of the config to ``no``.
If the setting ``nocopy`` is true (defaults false) then the plugin will pass the ``--nocopy`` option when adding things to ipfs. If the filestore option of ipfs is enabled this will mean files are neither removed from beets nor copied somewhere else.
If the setting ``nocopy`` is true (defaults false) then the plugin will pass the
``--nocopy`` option when adding things to ipfs. If the filestore option of ipfs
is enabled this will mean files are neither removed from beets nor copied
somewhere else.

View file

@ -1,11 +1,10 @@
Key Finder Plugin
=================
The `keyfinder` plugin uses either the `KeyFinder`_ or `keyfinder-cli`_
program to detect the musical key of a track from its audio data and store
it in the `initial_key` field of your database. It does so
automatically when importing music or through the ``beet keyfinder
[QUERY]`` command.
The ``keyfinder`` plugin uses either the KeyFinder_ or keyfinder-cli_ program to
detect the musical key of a track from its audio data and store it in the
``initial_key`` field of your database. It does so automatically when importing
music or through the ``beet keyfinder [QUERY]`` command.
To use the ``keyfinder`` plugin, enable it in your configuration (see
:ref:`using-plugins`).
@ -13,23 +12,20 @@ To use the ``keyfinder`` plugin, enable it in your configuration (see
Configuration
-------------
To configure the plugin, make a ``keyfinder:`` section in your
configuration file. The available options are:
To configure the plugin, make a ``keyfinder:`` section in your configuration
file. The available options are:
- **auto**: Analyze every file on
import. Otherwise, you need to use the ``beet keyfinder`` command
explicitly.
Default: ``yes``
- **auto**: Analyze every file on import. Otherwise, you need to use the ``beet
keyfinder`` command explicitly. Default: ``yes``
- **bin**: The name of the program use for key analysis. You can use either
`KeyFinder`_ or `keyfinder-cli`_.
If you installed the KeyFinder GUI on a Mac, for example, you want
something like
``/Applications/KeyFinder.app/Contents/MacOS/KeyFinder``.
If using `keyfinder-cli`_, the binary must be named ``keyfinder-cli``.
Default: ``KeyFinder`` (i.e., search for the program in your ``$PATH``)..
KeyFinder_ or keyfinder-cli_. If you installed the KeyFinder GUI on a Mac, for
example, you want something like
``/Applications/KeyFinder.app/Contents/MacOS/KeyFinder``. If using
keyfinder-cli_, the binary must be named ``keyfinder-cli``. Default:
``KeyFinder`` (i.e., search for the program in your ``$PATH``)..
- **overwrite**: Calculate a key even for files that already have an
`initial_key` value.
Default: ``no``.
``initial_key`` value. Default: ``no``.
.. _keyfinder: http://www.ibrahimshaath.co.uk/keyfinder/
.. _KeyFinder: http://www.ibrahimshaath.co.uk/keyfinder/
.. _keyfinder-cli: https://github.com/EvanPurkhiser/keyfinder-cli/

View file

@ -1,14 +1,15 @@
KodiUpdate Plugin
=================
The ``kodiupdate`` plugin lets you automatically update `Kodi`_'s music
library whenever you change your beets library.
The ``kodiupdate`` plugin lets you automatically update Kodi_'s music library
whenever you change your beets library.
To use ``kodiupdate`` plugin, enable it in your configuration
(see :ref:`using-plugins`).
Then, you'll want to configure the specifics of your Kodi host.
You can do that using a ``kodi:`` section in your ``config.yaml``,
which looks like this::
To use ``kodiupdate`` plugin, enable it in your configuration (see
:ref:`using-plugins`). Then, you'll want to configure the specifics of your Kodi
host. You can do that using a ``kodi:`` section in your ``config.yaml``, which
looks like this:
::
kodi:
host: localhost
@ -16,7 +17,9 @@ which looks like this::
user: kodi
pwd: kodi
To update multiple Kodi instances, specify them as an array::
To update multiple Kodi instances, specify them as an array:
::
kodi:
- host: x.x.x.x
@ -28,7 +31,6 @@ To update multiple Kodi instances, specify them as an array::
user: kodi2
pwd: kodi2
To use the ``kodiupdate`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install ``beets`` with ``kodiupdate`` extra
@ -38,23 +40,20 @@ To use the ``kodiupdate`` plugin, first enable it in your configuration (see
You'll also need to enable JSON-RPC in Kodi.
In Kodi's interface, navigate to System/Settings/Network/Services and choose "Allow control of Kodi via HTTP."
In Kodi's interface, navigate to System/Settings/Network/Services and choose
"Allow control of Kodi via HTTP."
With that all in place, you'll see beets send the "update" command to your Kodi
host every time you change your beets library.
.. _Kodi: https://kodi.tv/
.. _kodi: https://kodi.tv/
Configuration
-------------
The available options under the ``kodi:`` section are:
- **host**: The Kodi host name.
Default: ``localhost``
- **port**: The Kodi host port.
Default: 8080
- **user**: The Kodi host user.
Default: ``kodi``
- **pwd**: The Kodi host password.
Default: ``kodi``
- **host**: The Kodi host name. Default: ``localhost``
- **port**: The Kodi host port. Default: 8080
- **user**: The Kodi host user. Default: ``kodi``
- **pwd**: The Kodi host password. Default: ``kodi``

View file

@ -1,11 +1,10 @@
LastGenre Plugin
================
The ``lastgenre`` plugin fetches *tags* from `Last.fm`_ and assigns them as genres
The ``lastgenre`` plugin fetches *tags* from Last.fm_ and assigns them as genres
to your albums and items.
.. _Last.fm: https://last.fm/
.. _last.fm: https://last.fm/
Installation
------------
@ -20,30 +19,33 @@ To use the ``lastgenre`` plugin, first enable it in your configuration (see
Usage
-----
The plugin chooses genres based on a *whitelist*, meaning that only certain
tags can be considered genres. This way, tags like "my favorite music" or "seen
live" won't be considered genres. The plugin ships with a fairly extensive
`internal whitelist`_, but you can set your own in the config file using the
``whitelist`` configuration value or forgo a whitelist altogether by setting
the option to ``no``.
The plugin chooses genres based on a *whitelist*, meaning that only certain tags
can be considered genres. This way, tags like "my favorite music" or "seen live"
won't be considered genres. The plugin ships with a fairly extensive `internal
whitelist`_, but you can set your own in the config file using the ``whitelist``
configuration value or forgo a whitelist altogether by setting the option to
``no``.
The genre list file should contain one genre per line. Blank lines are ignored.
For the curious, the default genre list is generated by a `script that scrapes
Wikipedia`_.
.. _script that scrapes Wikipedia: https://gist.github.com/1241307
.. _internal whitelist: https://raw.githubusercontent.com/beetbox/beets/master/beetsplug/lastgenre/genres.txt
.. _script that scrapes wikipedia: https://gist.github.com/1241307
Canonicalization
^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~
The plugin can also *canonicalize* genres, meaning that more obscure genres can
be turned into coarser-grained ones that are present in the whitelist. This
works using a `tree of nested genre names`_, represented using `YAML`_, where the
works using a `tree of nested genre names`_, represented using YAML_, where the
leaves of the tree represent the most specific genres.
The most common way to use this would be with a custom whitelist containing only
a desired subset of genres. Consider for a example this minimal whitelist::
a desired subset of genres. Consider for a example this minimal whitelist:
::
rock
heavy metal
@ -54,7 +56,9 @@ as *viking metal* would actually be tagged as *heavy metal* because neither
*viking metal* nor its parent *black metal* are in the whitelist. It always
tries to use the most specific genre that's available in the whitelist.
The relevant subtree path in the default tree looks like this::
The relevant subtree path in the default tree looks like this:
::
- rock:
- heavy metal:
@ -66,60 +70,58 @@ contains about any genre contained in the tree) with canonicalization because
nothing would ever be matched to a more generic node since all the specific
subgenres are in the whitelist to begin with.
.. _YAML: https://yaml.org/
.. _tree of nested genre names: https://raw.githubusercontent.com/beetbox/beets/master/beetsplug/lastgenre/genres-tree.yaml
.. _yaml: https://yaml.org/
Genre Source
^^^^^^^^^^^^
~~~~~~~~~~~~
When looking up genres for albums or individual tracks, you can choose whether
to use Last.fm tags on the album, the artist, or the track. For example, you
might want all the albums for a certain artist to carry the same genre.
The default is "album". When set to "track", the plugin will fetch *both*
might want all the albums for a certain artist to carry the same genre. The
default is "album". When set to "track", the plugin will fetch *both*
album-level and track-level genres for your music when importing albums.
Multiple Genres
^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~
By default, the plugin chooses the most popular tag on Last.fm as a genre. If
you prefer to use a *list* of popular genre tags, you can increase the number
of the ``count`` config option.
you prefer to use a *list* of popular genre tags, you can increase the number of
the ``count`` config option.
Lists of up to *count* genres will then be used instead of single genres. The
genres are separated by commas by default, but you can change this with the
``separator`` config option.
`Last.fm`_ provides a popularity factor, a.k.a. *weight*, for each tag ranging
from 100 for the most popular tag down to 0 for the least popular.
The plugin uses this weight to discard unpopular tags. The default is to
ignore tags with a weight less then 10. You can change this by setting
the ``min_weight`` config option.
Last.fm_ provides a popularity factor, a.k.a. *weight*, for each tag ranging
from 100 for the most popular tag down to 0 for the least popular. The plugin
uses this weight to discard unpopular tags. The default is to ignore tags with a
weight less then 10. You can change this by setting the ``min_weight`` config
option.
Specific vs. Popular Genres
^^^^^^^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~~~~~~~
By default, the plugin sorts genres by popularity. However, you can use the
``prefer_specific`` option to override this behavior and instead sort genres
by specificity, as determined by your whitelist and canonicalization tree.
``prefer_specific`` option to override this behavior and instead sort genres by
specificity, as determined by your whitelist and canonicalization tree.
For instance, say you have both ``folk`` and ``americana`` in your whitelist
and canonicalization tree and ``americana`` is a leaf within ``folk``. If
Last.fm returns both of those tags, lastgenre is going to use the most
popular, which is often the most generic (in this case ``folk``). By setting
``prefer_specific`` to true, lastgenre would use ``americana`` instead.
For instance, say you have both ``folk`` and ``americana`` in your whitelist and
canonicalization tree and ``americana`` is a leaf within ``folk``. If Last.fm
returns both of those tags, lastgenre is going to use the most popular, which is
often the most generic (in this case ``folk``). By setting ``prefer_specific``
to true, lastgenre would use ``americana`` instead.
Handling pre-populated tags
^^^^^^^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``force``, ``keep_existing`` and ``whitelist`` options control how
pre-existing genres are handled.
As you would assume, setting ``force: no`` **won't touch pre-existing genre
tags** and will only **fetch new genres for empty tags**. When ``force`` is
``yes`` the setting of the ``whitelist`` option (as documented in `Usage`_)
``yes`` the setting of the ``whitelist`` option (as documented in Usage_)
applies to any existing or newly fetched genres.
The follwing configurations are possible:
@ -154,73 +156,61 @@ make sure any existing genres remain, set ``whitelist: no``).
keep_existing: yes
.. attention::
If ``force`` is disabled the ``keep_existing`` option is simply ignored (since ``force:
no`` means `not touching` existing tags anyway).
If ``force`` is disabled the ``keep_existing`` option is simply ignored
(since ``force: no`` means ``not touching`` existing tags anyway).
Configuration
-------------
To configure the plugin, make a ``lastgenre:`` section in your
configuration file. The available options are:
To configure the plugin, make a ``lastgenre:`` section in your configuration
file. The available options are:
- **auto**: Fetch genres automatically during import.
Default: ``yes``.
- **canonical**: Use a canonicalization tree. Setting this to ``yes`` will use
a built-in tree. You can also set it to a path, like the ``whitelist``
config value, to use your own tree.
Default: ``no`` (disabled).
- **count**: Number of genres to fetch.
Default: 1
- **fallback**: A string to use as a fallback genre when no genre is found `or`
the original genre is not desired to be kept (``keep_existing: no``). You can
use the empty string ``''`` to reset the genre.
Default: None.
- **auto**: Fetch genres automatically during import. Default: ``yes``.
- **canonical**: Use a canonicalization tree. Setting this to ``yes`` will use a
built-in tree. You can also set it to a path, like the ``whitelist`` config
value, to use your own tree. Default: ``no`` (disabled).
- **count**: Number of genres to fetch. Default: 1
- **fallback**: A string to use as a fallback genre when no genre is found
``or`` the original genre is not desired to be kept (``keep_existing: no``).
You can use the empty string ``''`` to reset the genre. Default: None.
- **force**: By default, lastgenre will fetch new genres for empty tags only,
enable this option to always try to fetch new last.fm genres. Enable the
``keep_existing`` option to combine existing and new genres. (see `Handling
pre-populated tags`_).
Default: ``no``.
- **keep_existing**: This option alters the ``force`` behavior.
If both ``force`` and ``keep_existing`` are enabled, existing genres are
combined with new ones. Depending on the ``whitelist`` setting, existing and
new genres are filtered accordingly. To ensure only fresh last.fm genres,
disable this option. (see `Handling pre-populated tags`_)
Default: ``no``.
pre-populated tags`_). Default: ``no``.
- **keep_existing**: This option alters the ``force`` behavior. If both
``force`` and ``keep_existing`` are enabled, existing genres are combined with
new ones. Depending on the ``whitelist`` setting, existing and new genres are
filtered accordingly. To ensure only fresh last.fm genres, disable this
option. (see `Handling pre-populated tags`_) Default: ``no``.
- **min_weight**: Minimum popularity factor below which genres are discarded.
Default: 10.
- **prefer_specific**: Sort genres by the most to least specific, rather than
most to least popular. Note that this option requires a ``canonical`` tree,
and if not configured it will automatically enable and use the built-in tree.
Default: ``no``.
- **source**: Which entity to look up in Last.fm. Can be
either ``artist``, ``album`` or ``track``.
Default: ``album``.
- **separator**: A separator for multiple genres.
Default: ``', '``.
- **whitelist**: The filename of a custom genre list, ``yes`` to use
the internal whitelist, or ``no`` to consider all genres valid.
Default: ``yes``.
- **title_case**: Convert the new tags to TitleCase before saving.
Default: ``yes``.
- **source**: Which entity to look up in Last.fm. Can be either ``artist``,
``album`` or ``track``. Default: ``album``.
- **separator**: A separator for multiple genres. Default: ``', '``.
- **whitelist**: The filename of a custom genre list, ``yes`` to use the
internal whitelist, or ``no`` to consider all genres valid. Default: ``yes``.
- **title_case**: Convert the new tags to TitleCase before saving. Default:
``yes``.
- **extended_debug**: Add additional debug logging messages that show what
last.fm tags were fetched for tracks, albums and artists. This is done before
any canonicalization and whitelist filtering is applied. It's useful for
tuning the plugin's settings and understanding how it works, but it can be
quite verbose.
Default: ``no``.
quite verbose. Default: ``no``.
Running Manually
----------------
In addition to running automatically on import, the plugin can also be run manually
from the command line. Use the command ``beet lastgenre [QUERY]`` to fetch
genres for albums or items matching a certain query.
In addition to running automatically on import, the plugin can also be run
manually from the command line. Use the command ``beet lastgenre [QUERY]`` to
fetch genres for albums or items matching a certain query.
By default, ``beet lastgenre`` matches albums. To match
individual tracks or singletons, use the ``-A`` switch:
``beet lastgenre -A [QUERY]``.
By default, ``beet lastgenre`` matches albums. To match individual tracks or
singletons, use the ``-A`` switch: ``beet lastgenre -A [QUERY]``.
To disable automatic genre fetching on import, set the ``auto`` config option
to false.
To disable automatic genre fetching on import, set the ``auto`` config option to
false.

View file

@ -1,12 +1,12 @@
LastImport Plugin
=================
The ``lastimport`` plugin downloads play-count data from your `Last.fm`_
library into beets' database. You can later create :doc:`smart playlists
</plugins/smartplaylist>` by querying ``play_count`` and do other fun stuff
with this field.
The ``lastimport`` plugin downloads play-count data from your Last.fm_ library
into beets' database. You can later create :doc:`smart playlists
</plugins/smartplaylist>` by querying ``play_count`` and do other fun stuff with
this field.
.. _Last.fm: https://last.fm
.. _last.fm: https://last.fm
Installation
------------
@ -18,7 +18,9 @@ To use the ``lastimport`` plugin, first enable it in your configuration (see
pip install "beets[lastimport]"
Next, add your Last.fm username to your beets configuration file::
Next, add your Last.fm username to your beets configuration file:
::
lastfm:
user: beetsfanatic
@ -27,11 +29,13 @@ Importing Play Counts
---------------------
Simply run ``beet lastimport`` and wait for the plugin to request tracks from
Last.fm and match them to your beets library. (You will be notified of tracks
in your Last.fm profile that do not match any songs in your library.)
Last.fm and match them to your beets library. (You will be notified of tracks in
your Last.fm profile that do not match any songs in your library.)
Then, your matched tracks will be populated with the ``play_count`` field,
which you can use in any query or template. For example::
Then, your matched tracks will be populated with the ``play_count`` field, which
you can use in any query or template. For example:
::
$ beet ls -f '$title: $play_count' play_count:5..
Eple (Melody A.M.): 60
@ -45,14 +49,15 @@ Configuration
Aside from the required ``lastfm.user`` field, this plugin has some specific
options under the ``lastimport:`` section:
* **per_page**: The number of tracks to request from the API at once.
Default: 500.
* **retry_limit**: How many times should we re-send requests to Last.fm on
failure?
Default: 3.
- **per_page**: The number of tracks to request from the API at once. Default:
500.
- **retry_limit**: How many times should we re-send requests to Last.fm on
failure? Default: 3.
By default, the plugin will use beets's own Last.fm API key. You can also
override it with your own API key::
override it with your own API key:
::
lastfm:
api_key: your_api_key

View file

@ -1,58 +1,63 @@
Limit Query Plugin
==================
``limit`` is a plugin to limit a query to the first or last set of
results. We also provide a query prefix ``'<n'`` to inline the same
behavior in the ``list`` command. They are analogous to piping results:
``limit`` is a plugin to limit a query to the first or last set of results. We
also provide a query prefix ``'<n'`` to inline the same behavior in the ``list``
command. They are analogous to piping results:
$ beet [list|ls] [QUERY] | [head|tail] -n n
There are two provided interfaces:
1. ``beet lslimit [--head n | --tail n] [QUERY]`` returns the head or
tail of a query
1. ``beet lslimit [--head n | --tail n] [QUERY]`` returns the head or tail of a
query
2. ``beet [list|ls] [QUERY] '<n'`` returns the head of a query
There are two differences in behavior:
There are two differences in behavior:
1. The query prefix does not support tail.
2. The query prefix could appear anywhere in the query but will only
have the same behavior as the ``lslimit`` command and piping to ``head``
when it appears last.
2. The query prefix could appear anywhere in the query but will only have the
same behavior as the ``lslimit`` command and piping to ``head`` when it appears
last.
Performance for the query previx is much worse due to the current
singleton-based implementation.
Performance for the query previx is much worse due to the current
singleton-based implementation.
So why does the query prefix exist? Because it composes with any other
query-based API or plugin (see :doc:`/reference/query`). For example,
you can use the query prefix in ``smartplaylist``
(see :doc:`/plugins/smartplaylist`) to limit the number of tracks in a smart
playlist for applications like most played and recently added.
So why does the query prefix exist? Because it composes with any other
query-based API or plugin (see :doc:`/reference/query`). For example, you can
use the query prefix in ``smartplaylist`` (see :doc:`/plugins/smartplaylist`) to
limit the number of tracks in a smart playlist for applications like most played
and recently added.
Configuration
-------------
Enable the ``limit`` plugin in your configuration (see
:ref:`using-plugins`).
Enable the ``limit`` plugin in your configuration (see :ref:`using-plugins`).
Examples
--------
First 10 tracks
.. code-block:: sh
$ beet ls | head -n 10
$ beet lslimit --head 10
$ beet ls '<10'
Last 10 tracks
.. code-block:: sh
$ beet ls | tail -n 10
$ beet lslimit --tail 10
100 mostly recently released tracks
.. code-block:: sh
$ beet lslimit --head 100 year- month- day-
$ beet ls year- month- day- '<100'
$ beet lslimit --tail 100 year+ month+ day+

View file

@ -3,30 +3,35 @@
ListenBrainz Plugin
===================
The ListenBrainz plugin for beets allows you to interact with the ListenBrainz service.
The ListenBrainz plugin for beets allows you to interact with the ListenBrainz
service.
Installation
------------
To enable the ListenBrainz plugin, add the following to your beets configuration file (`config.yaml`_):
To enable the ListenBrainz plugin, add the following to your beets configuration
file (config.yaml_):
.. code-block:: yaml
plugins:
- listenbrainz
plugins:
- listenbrainz
You can then configure the plugin by providing your Listenbrainz token (see intructions `here`_) and username::
You can then configure the plugin by providing your Listenbrainz token (see
intructions here_) and username:
::
listenbrainz:
token: TOKEN
username: LISTENBRAINZ_USERNAME
Usage
-----
Once the plugin is enabled, you can import the listening history using the `lbimport` command in beets.
Once the plugin is enabled, you can import the listening history using the
``lbimport`` command in beets.
.. _config.yaml: ../reference/config.rst
.. _here: https://listenbrainz.readthedocs.io/en/latest/users/api/index.html#get-the-user-token
.. _config.yaml: ../reference/config.rst

View file

@ -1,21 +1,21 @@
Load Extension Plugin
=====================
Beets uses an SQLite database to store and query library information, which
has support for extensions to extend its functionality. The ``loadext`` plugin
lets you enable these SQLite extensions within beets.
Beets uses an SQLite database to store and query library information, which has
support for extensions to extend its functionality. The ``loadext`` plugin lets
you enable these SQLite extensions within beets.
One of the primary uses of this within beets is with the `"ICU" extension`_,
which adds support for case insensitive querying of non-ASCII characters.
.. _"ICU" extension: https://www.sqlite.org/src/dir?ci=7461d2e120f21493&name=ext/icu
.. _"icu" extension: https://www.sqlite.org/src/dir?ci=7461d2e120f21493&name=ext/icu
Configuration
-------------
To configure the plugin, make a ``loadext`` section in your configuration
file. The section must consist of a list of paths to extensions to load, which
looks like this:
To configure the plugin, make a ``loadext`` section in your configuration file.
The section must consist of a list of paths to extensions to load, which looks
like this:
.. code-block:: yaml
@ -25,21 +25,22 @@ looks like this:
If a relative path is specified, it is resolved relative to the beets
configuration directory.
If no file extension is specified, the default dynamic library extension for
the current platform will be used.
If no file extension is specified, the default dynamic library extension for the
current platform will be used.
Building the ICU extension
--------------------------
This section is for **advanced** users only, and is not an in-depth guide on
building the extension.
To compile the ICU extension, you will need a few dependencies:
- gcc
- icu-devtools
- libicu
- libicu-dev
- libsqlite3-dev
- gcc
- icu-devtools
- libicu
- libicu-dev
- libsqlite3-dev
Here's roughly how to download, build and install the extension (although the
specifics may vary from system to system):
@ -49,5 +50,5 @@ specifics may vary from system to system):
$ wget https://sqlite.org/2019/sqlite-src-3280000.zip
$ unzip sqlite-src-3280000.zip
$ cd sqlite-src-3280000/ext/icu
$ gcc -shared -fPIC icu.c `icu-config --ldflags` -o libicu.so
$ gcc -shared -fPIC icu.c $(icu-config --ldflags) -o libicu.so
$ cp libicu.so ~/.config/beets

View file

@ -2,13 +2,14 @@ Lyrics Plugin
=============
The ``lyrics`` plugin fetches and stores song lyrics from databases on the Web.
Namely, the current version of the plugin uses `Genius.com`_, `Tekstowo.pl`_,
`LRCLIB`_ and, optionally, the Google Custom Search API.
Namely, the current version of the plugin uses Genius.com_, Tekstowo.pl_,
LRCLIB_ and, optionally, the Google Custom Search API.
.. _Genius.com: https://genius.com/
.. _Tekstowo.pl: https://www.tekstowo.pl/
.. _LRCLIB: https://lrclib.net/
.. _genius.com: https://genius.com/
.. _lrclib: https://lrclib.net/
.. _tekstowo.pl: https://www.tekstowo.pl/
Install
-------
@ -62,20 +63,20 @@ The available options are:
``translate_to`` are translated. Use a list of language codes to restrict
them.
- **to_language**: Language code to translate lyrics to.
- **dist_thresh**: The maximum distance between the artist and title
combination of the music file and lyrics candidate to consider them a match.
Lower values will make the plugin more strict, higher values will make it
more lenient. This does not apply to the ``lrclib`` backend as it matches
durations.
- **dist_thresh**: The maximum distance between the artist and title combination
of the music file and lyrics candidate to consider them a match. Lower values
will make the plugin more strict, higher values will make it more lenient.
This does not apply to the ``lrclib`` backend as it matches durations.
- **fallback**: By default, the file will be left unchanged when no lyrics are
found. Use the empty string ``''`` to reset the lyrics in such a case.
- **force**: By default, beets won't fetch lyrics if the files already have
ones. To instead always fetch lyrics, set the ``force`` option to ``yes``.
- **google_API_key**: Your Google API key (to enable the Google Custom Search
backend).
- **google_engine_ID**: The custom search engine to use.
Default: The `beets custom search engine`_, which gathers an updated list of
sources known to be scrapeable.
- **google_engine_ID**: The custom search engine to use. Default: The `beets
custom search engine`_, which gathers an updated list of sources known to be
scrapeable.
- **print**: Print lyrics to the console.
- **sources**: List of sources to search for lyrics. An asterisk ``*`` expands
to all available sources. The ``google`` source will be automatically
@ -109,61 +110,60 @@ Rendering Lyrics into Other Formats
-----------------------------------
The ``-r directory, --write-rest directory`` option renders all lyrics as
`reStructuredText`_ (ReST) documents in ``directory``. That directory, in turn,
can be parsed by tools like `Sphinx`_ to generate HTML, ePUB, or PDF documents.
reStructuredText_ (ReST) documents in ``directory``. That directory, in turn,
can be parsed by tools like Sphinx_ to generate HTML, ePUB, or PDF documents.
Minimal ``conf.py`` and ``index.rst`` files are created the first time the
command is run. They are not overwritten on subsequent runs, so you can safely
modify these files to customize the output.
Sphinx supports various `builders`_, see a few suggestions:
Sphinx supports various builders_, see a few suggestions:
.. admonition:: Build an HTML version
::
::
sphinx-build -b html <dir> <dir>/html
sphinx-build -b html <dir> <dir>/html
.. admonition:: Build an ePUB3 formatted file, usable on ebook readers
::
::
sphinx-build -b epub3 <dir> <dir>/epub
sphinx-build -b epub3 <dir> <dir>/epub
.. admonition:: Build a PDF file, which incidentally also builds a LaTeX file
::
::
sphinx-build -b latex <dir> <dir>/latex && make -C <dir>/latex all-pdf
sphinx-build -b latex <dir> <dir>/latex && make -C <dir>/latex all-pdf
.. _Sphinx: https://www.sphinx-doc.org/
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
.. _builders: https://www.sphinx-doc.org/en/stable/builders.html
Activate Google Custom Search
------------------------------
.. _restructuredtext: http://docutils.sourceforge.net/rst.html
You need to `register for a Google API key`_. Set the ``google_API_key``
.. _sphinx: https://www.sphinx-doc.org/
Activate Google Custom Search
-----------------------------
You need to `register for a Google API key
<https://console.developers.google.com/>`__. Set the ``google_API_key``
configuration option to your key.
Then add ``google`` to the list of sources in your configuration (or use
default list, which includes it as long as you have an API key).
If you use default ``google_engine_ID``, we recommend limiting the sources to
``google`` as the other sources are already included in the Google results.
Then add ``google`` to the list of sources in your configuration (or use default
list, which includes it as long as you have an API key). If you use default
``google_engine_ID``, we recommend limiting the sources to ``google`` as the
other sources are already included in the Google results.
Optionally, you can `define a custom search engine`_. Get your search engine's
token and use it for your ``google_engine_ID`` configuration option. By
default, beets use a list of sources known to be scrapeable.
token and use it for your ``google_engine_ID`` configuration option. By default,
beets use a list of sources known to be scrapeable.
Note that the Google custom search API is limited to 100 queries per day.
After that, the lyrics plugin will fall back on other declared data sources.
Note that the Google custom search API is limited to 100 queries per day. After
that, the lyrics plugin will fall back on other declared data sources.
.. _register for a Google API key: https://console.developers.google.com/
.. _define a custom search engine: https://www.google.com/cse/all
.. _lyrics-translation:
Activate On-the-Fly Translation
@ -177,20 +177,22 @@ follow these steps:
3. Add the API key to your configuration as ``translate.api_key``.
4. Configure your target language using the ``translate.to_language`` option.
For example, with the following configuration
.. code-block:: yaml
lyrics:
translate:
api_key: YOUR_TRANSLATOR_API_KEY
to_language: de
lyrics:
translate:
api_key: YOUR_TRANSLATOR_API_KEY
to_language: de
You should expect lyrics like this::
You should expect lyrics like this:
Original verse / Ursprünglicher Vers
Some other verse / Ein anderer Vers
::
.. _create a Translator resource: https://learn.microsoft.com/en-us/azure/ai-services/translator/create-translator-resource
.. _obtain its API key: https://learn.microsoft.com/en-us/python/api/overview/azure/ai-translation-text-readme?view=azure-python&preserve-view=true#get-an-api-key
Original verse / Ursprünglicher Vers
Some other verse / Ein anderer Vers
.. _create a translator resource: https://learn.microsoft.com/en-us/azure/ai-services/translator/create-translator-resource
.. _obtain its api key: https://learn.microsoft.com/en-us/python/api/overview/azure/ai-translation-text-readme?view=azure-python&preserve-view=true#get-an-api-key

View file

@ -6,10 +6,11 @@ maintain your `music collection`_ list there.
.. _music collection: https://musicbrainz.org/doc/Collections
To begin, just enable the ``mbcollection`` plugin in your
configuration (see :ref:`using-plugins`).
Then, add your MusicBrainz username and password to your
:doc:`configuration file </reference/config>` under a ``musicbrainz`` section::
To begin, just enable the ``mbcollection`` plugin in your configuration (see
:ref:`using-plugins`). Then, add your MusicBrainz username and password to your
:doc:`configuration file </reference/config>` under a ``musicbrainz`` section:
::
musicbrainz:
user: you
@ -22,21 +23,18 @@ profile first.
The command has one command-line option:
* To remove albums from the collection which are no longer present in
the beets database, use the ``-r`` (``--remove``) flag.
- To remove albums from the collection which are no longer present in the beets
database, use the ``-r`` (``--remove``) flag.
Configuration
-------------
To configure the plugin, make a ``mbcollection:`` section in your
configuration file. There is one option available:
To configure the plugin, make a ``mbcollection:`` section in your configuration
file. There is one option available:
- **auto**: Automatically amend your MusicBrainz collection whenever you
import a new album.
Default: ``no``.
- **collection**: The MBID of which MusicBrainz collection to update.
Default: ``None``.
- **remove**: Remove albums from collections which are no longer
present in the beets database.
Default: ``no``.
- **auto**: Automatically amend your MusicBrainz collection whenever you import
a new album. Default: ``no``.
- **collection**: The MBID of which MusicBrainz collection to update. Default:
``None``.
- **remove**: Remove albums from collections which are no longer present in the
beets database. Default: ``no``.

View file

@ -8,28 +8,32 @@ that is parseable by MusicBrainz's `track parser`_. The prompt choices are:
- Print the tracks to stdout in a format suitable for MusicBrainz's `track
parser`_.
- Open the program Picard_ with the unmatched folder as an input, allowing you
to start submitting the unmatched release to MusicBrainz with many input
fields already filled in, thanks to Picard reading the preexisting tags of the
files.
- Open the program `Picard`_ with the unmatched folder as an input, allowing
you to start submitting the unmatched release to MusicBrainz with many input
fields already filled in, thanks to Picard reading the preexisting tags of
the files.
For the last option, `Picard`_ is assumed to be installed and available on the
For the last option, Picard_ is assumed to be installed and available on the
machine including a ``picard`` executable. Picard developers list `download
options`_. `other GNU/Linux distributions`_ may distribute Picard via their
package manager as well.
.. _track parser: https://wiki.musicbrainz.org/History:How_To_Parse_Track_Listings
.. _Picard: https://picard.musicbrainz.org/
.. _download options: https://picard.musicbrainz.org/downloads/
.. _other GNU/Linux distributions: https://repology.org/project/picard-tagger/versions
.. _other gnu/linux distributions: https://repology.org/project/picard-tagger/versions
.. _picard: https://picard.musicbrainz.org/
.. _track parser: https://wiki.musicbrainz.org/History:How_To_Parse_Track_Listings
Usage
-----
Enable the ``mbsubmit`` plugin in your configuration (see :ref:`using-plugins`)
and select one of the options mentioned above. Here the option ``Print tracks``
choice is demonstrated::
choice is demonstrated:
::
No matching release found for 3 tracks.
For help, see: https://beets.readthedocs.org/en/latest/faq.html#nomatch
@ -44,7 +48,10 @@ choice is demonstrated::
[U]se as-is, as Tracks, Group albums, Skip, Enter search, enter Id, aBort,
Print tracks?
You can also run ``beet mbsubmit QUERY`` to print the track information for any album::
You can also run ``beet mbsubmit QUERY`` to print the track information for any
album:
::
$ beet mbsubmit album:"An Obscure Album"
01. An Obscure Track - An Obscure Artist (3:37)
@ -53,8 +60,8 @@ You can also run ``beet mbsubmit QUERY`` to print the track information for any
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.
and paste it into the parser that can be found by clicking on the "Track Parser"
button on MusicBrainz "Tracklist" tab.
Configuration
-------------
@ -62,22 +69,22 @@ 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>`.
- **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``.
- **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``.
- **picard_path**: The path to the ``picard`` executable. Could be an absolute
path, and if not, ``$PATH`` is consulted. The default value is simply
``picard``. Windows users will have to find and specify the absolute path to
their ``picard.exe``. That would probably be:
``C:\Program Files\MusicBrainz Picard\picard.exe``.
their ``picard.exe``. That would probably be: ``C:\Program Files\MusicBrainz
Picard\picard.exe``.
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`.
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`.

View file

@ -1,8 +1,8 @@
MBSync Plugin
=============
This plugin provides the ``mbsync`` command, which lets you synchronize
metadata for albums and tracks that have external data source IDs.
This plugin provides the ``mbsync`` command, which lets you synchronize metadata
for albums and tracks that have external data source IDs.
This is useful for syncing your library with online data or when changing
configuration options that affect tag writing. If your music library already
@ -10,7 +10,6 @@ contains correct tags, you can speed up the initial import by importing files
"as-is" and then using ``mbsync`` to write tags according to your beets
configuration.
Usage
-----
@ -18,20 +17,20 @@ Enable the ``mbsync`` plugin in your configuration (see :ref:`using-plugins`)
and then run ``beet mbsync QUERY`` to fetch updated metadata for a part of your
collection (or omit the query to run over your whole library).
This plugin treats albums and singletons (non-album tracks) separately. It
first processes all matching singletons and then proceeds on to full albums.
The same query is used to search for both kinds of entities.
This plugin treats albums and singletons (non-album tracks) separately. It first
processes all matching singletons and then proceeds on to full albums. The same
query is used to search for both kinds of entities.
The command has a few command-line options:
* To preview the changes that would be made without applying them, use the
- To preview the changes that would be made without applying them, use the
``-p`` (``--pretend``) flag.
* By default, files will be moved (renamed) according to their metadata if
they are inside your beets library directory. To disable this, use the
``-M`` (``--nomove``) command-line option.
* If you have the ``import.write`` configuration option enabled, then this
plugin will write new metadata to files' tags. To disable this, use the
``-W`` (``--nowrite``) option.
* To customize the output of unrecognized items, use the ``-f``
(``--format``) option. The default output is ``format_item`` or
``format_album`` for items and albums, respectively.
- By default, files will be moved (renamed) according to their metadata if they
are inside your beets library directory. To disable this, use the ``-M``
(``--nomove``) command-line option.
- If you have the ``import.write`` configuration option enabled, then this
plugin will write new metadata to files' tags. To disable this, use the ``-W``
(``--nowrite``) option.
- To customize the output of unrecognized items, use the ``-f`` (``--format``)
option. The default output is ``format_item`` or ``format_album`` for items
and albums, respectively.

View file

@ -4,23 +4,21 @@ MetaSync Plugin
This plugin provides the ``metasync`` command, which lets you fetch certain
metadata from other sources: for example, your favorite audio player.
Currently, the plugin supports synchronizing with the `Amarok`_ music player,
and with `iTunes`_.
It can fetch the rating, score, first-played date, last-played date, play
count, and track uid from Amarok.
Currently, the plugin supports synchronizing with the Amarok_ music player, and
with iTunes_. It can fetch the rating, score, first-played date, last-played
date, play count, and track uid from Amarok.
.. _Amarok: https://amarok.kde.org/
.. _iTunes: https://www.apple.com/itunes/
.. _amarok: https://amarok.kde.org/
.. _itunes: https://www.apple.com/itunes/
Installation
------------
Enable the ``metasync`` plugin in your configuration (see
:ref:`using-plugins`).
Enable the ``metasync`` plugin in your configuration (see :ref:`using-plugins`).
To synchronize with Amarok, you'll need the `dbus-python`_ library. In such
case, install ``beets`` with ``metasync`` extra
To synchronize with Amarok, you'll need the dbus-python_ library. In such case,
install ``beets`` with ``metasync`` extra
.. code-block:: bash
@ -28,23 +26,24 @@ case, install ``beets`` with ``metasync`` extra
.. _dbus-python: https://dbus.freedesktop.org/releases/dbus-python/
Configuration
-------------
To configure the plugin, make a ``metasync:`` section in your configuration
file. The available options are:
- **source**: A list of comma-separated sources to fetch metadata from.
Set this to "amarok" or "itunes" to enable synchronization with that player.
Default: empty
- **source**: A list of comma-separated sources to fetch metadata from. Set this
to "amarok" or "itunes" to enable synchronization with that player. Default:
empty
The follow subsections describe additional configure required for some players.
itunes
''''''
~~~~~~
The path to your iTunes library **xml** file has to be configured, e.g.::
The path to your iTunes library **xml** file has to be configured, e.g.:
::
metasync:
source: itunes
@ -61,7 +60,7 @@ sources.
The command has a few command-line options:
* To preview the changes that would be made without applying them, use the
- To preview the changes that would be made without applying them, use the
``-p`` (``--pretend``) flag.
* To specify temporary sources to fetch metadata from, use the ``-s``
- To specify temporary sources to fetch metadata from, use the ``-s``
(``--source``) flag with a comma-separated list of a sources.

View file

@ -8,22 +8,24 @@ call to album data source.
Usage
-----
Add the ``missing`` plugin to your configuration (see :ref:`using-plugins`).
The ``beet missing`` command fetches album information from the origin data
source and lists names of the **tracks** that are missing from your library.
Add the ``missing`` plugin to your configuration (see :ref:`using-plugins`). The
``beet missing`` command fetches album information from the origin data source
and lists names of the **tracks** that are missing from your library.
It can also list the names of missing **albums** for each artist, although this
is limited to albums from the MusicBrainz data source only.
You can customize the output format, show missing counts instead of track
titles, or display the total number of missing entities across your entire
library::
library:
-f FORMAT, --format=FORMAT
print with custom FORMAT
-c, --count count missing tracks per album
-t, --total count totals across the entire library
-a, --album show missing albums for artist instead of tracks for album
::
-f FORMAT, --format=FORMAT
print with custom FORMAT
-c, --count count missing tracks per album
-t, --total count totals across the entire library
-a, --album show missing albums for artist instead of tracks for album
…or by editing the corresponding configuration options.
@ -34,21 +36,21 @@ library::
Configuration
-------------
To configure the plugin, make a ``missing:`` section in your
configuration file. The available options are:
To configure the plugin, make a ``missing:`` section in your configuration file.
The available options are:
- **count**: Print a count of missing tracks per album, with ``format``
defaulting to ``$albumartist - $album: $missing``.
Default: ``no``.
- **format**: A specific format with which to print every
track. This uses the same template syntax as beets'
:doc:`path formats </reference/pathformat>`. The usage is inspired by, and
therefore similar to, the :ref:`list <list-cmd>` command.
Default: :ref:`format_item`.
- **total**: Print a single count of missing tracks in all albums.
Default: ``no``.
defaulting to ``$albumartist - $album: $missing``. Default: ``no``.
- **format**: A specific format with which to print every track. This uses the
same template syntax as beets' :doc:`path formats </reference/pathformat>`.
The usage is inspired by, and therefore similar to, the :ref:`list <list-cmd>`
command. Default: :ref:`format_item`.
- **total**: Print a single count of missing tracks in all albums. Default:
``no``.
Here's an example ::
Here's an example
::
missing:
format: $albumartist - $album - $title
@ -58,39 +60,53 @@ Here's an example ::
Template Fields
---------------
With this plugin enabled, the ``$missing`` template field expands to the
number of tracks missing from each album.
With this plugin enabled, the ``$missing`` template field expands to the number
of tracks missing from each album.
Examples
--------
List all missing tracks in your collection::
List all missing tracks in your collection:
beet missing
::
List all missing albums in your collection::
beet missing
beet missing -a
List all missing albums in your collection:
List all missing tracks from 2008::
::
beet missing year:2008
beet missing -a
Print out a unicode histogram of the missing track years using `spark`_::
List all missing tracks from 2008:
beet missing -f '$year' | spark
▆▁▆█▄▇▇▄▇▇▁█▇▆▇▂▄█▁██▂█▁▁██▁█▂▇▆▂▇█▇▇█▆▆▇█▇█▇▆██▂▇
::
Print out a listing of all albums with missing tracks, and respective counts::
beet missing year:2008
beet missing -c
Print out a unicode histogram of the missing track years using spark_:
Print out a count of the total number of missing tracks::
::
beet missing -t
beet missing -f '$year' | spark
▆▁▆█▄▇▇▄▇▇▁█▇▆▇▂▄█▁██▂█▁▁██▁█▂▇▆▂▇█▇▇█▆▆▇█▇█▇▆██▂▇
Call this plugin from other beet commands::
Print out a listing of all albums with missing tracks, and respective counts:
beet ls -a -f '$albumartist - $album: $missing'
::
beet missing -c
Print out a count of the total number of missing tracks:
::
beet missing -t
Call this plugin from other beet commands:
::
beet ls -a -f '$albumartist - $album: $missing'
.. _spark: https://github.com/holman/spark

View file

@ -1,25 +1,24 @@
MPDStats Plugin
================
===============
``mpdstats`` is a plugin for beets that collects statistics about your listening
habits from `MPD`_. It collects the following information about tracks:
habits from MPD_. It collects the following information about tracks:
* ``play_count``: The number of times you *fully* listened to this track.
* ``skip_count``: The number of times you *skipped* this track.
* ``last_played``: UNIX timestamp when you last played this track.
* ``rating``: A rating based on ``play_count`` and ``skip_count``.
- ``play_count``: The number of times you *fully* listened to this track.
- ``skip_count``: The number of times you *skipped* this track.
- ``last_played``: UNIX timestamp when you last played this track.
- ``rating``: A rating based on ``play_count`` and ``skip_count``.
To gather these statistics it runs as an MPD client and watches the current state
of MPD. This means that ``mpdstats`` needs to be running continuously for it to
work.
To gather these statistics it runs as an MPD client and watches the current
state of MPD. This means that ``mpdstats`` needs to be running continuously for
it to work.
.. _MPD: https://www.musicpd.org/
.. _mpd: https://www.musicpd.org/
Installing Dependencies
-----------------------
This plugin requires the python-mpd2 library in order to talk to the MPD
server.
This plugin requires the python-mpd2 library in order to talk to the MPD server.
To use the ``mpdstats`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install ``beets`` with ``mpdstats`` extra
@ -29,79 +28,77 @@ To use the ``mpdstats`` plugin, first enable it in your configuration (see
Usage
-----
Use the ``mpdstats`` command to fire it up::
Use the ``mpdstats`` command to fire it up:
::
$ beet mpdstats
Configuration
-------------
To configure the plugin, make an ``mpd:`` section in your
configuration file. The available options are:
To configure the plugin, make an ``mpd:`` section in your configuration file.
The available options are:
- **host**: The MPD server hostname.
Default: The ``$MPD_HOST`` environment variable if set,
falling back to ``localhost`` otherwise.
- **port**: The MPD server port.
Default: The ``$MPD_PORT`` environment variable if set,
falling back to 6600 otherwise.
- **password**: The MPD server password.
Default: None.
- **host**: The MPD server hostname. Default: The ``$MPD_HOST`` environment
variable if set, falling back to ``localhost`` otherwise.
- **port**: The MPD server port. Default: The ``$MPD_PORT`` environment variable
if set, falling back to 6600 otherwise.
- **password**: The MPD server password. Default: None.
- **music_directory**: If your MPD library is at a different location from the
beets library (e.g., because one is mounted on a NFS share), specify the path
here.
- **strip_path**: If your MPD library contains local path, specify the part to remove
here. Combining this with **music_directory** you can mangle MPD path to match the
beets library one.
Default: The beets library directory.
- **rating**: Enable rating updates.
Default: ``yes``.
- **rating_mix**: Tune the way rating is calculated (see below).
Default: 0.75.
- **strip_path**: If your MPD library contains local path, specify the part to
remove here. Combining this with **music_directory** you can mangle MPD path
to match the beets library one. Default: The beets library directory.
- **rating**: Enable rating updates. Default: ``yes``.
- **rating_mix**: Tune the way rating is calculated (see below). Default: 0.75.
- **played_ratio_threshold**: If a song was played for less than this percentage
of its duration it will be considered a skip.
Default: 0.85
of its duration it will be considered a skip. Default: 0.85
A Word on Ratings
-----------------
Ratings are calculated based on the *play_count*, *skip_count* and the last
*action* (play or skip). It consists in one part of a *stable_rating* and in
another part on a *rolling_rating*. The *stable_rating* is calculated like
this::
*action* (play or skip). It consists in one part of a *stable_rating* and in
another part on a *rolling_rating*. The *stable_rating* is calculated like this:
::
stable_rating = (play_count + 1.0) / (play_count + skip_count + 2.0)
So if the *play_count* equals the *skip_count*, the *stable_rating* is always
0.5. More *play_counts* adjust the rating up to 1.0. More *skip_counts*
adjust it down to 0.0. One of the disadvantages of this rating system, is
that it doesn't really cover *recent developments*. e.g. a song that you
loved last year and played over 50 times will keep a high rating even if you
skipped it the last 10 times. That's were the *rolling_rating* comes in.
0.5. More *play_counts* adjust the rating up to 1.0. More *skip_counts* adjust
it down to 0.0. One of the disadvantages of this rating system, is that it
doesn't really cover *recent developments*. e.g. a song that you loved last year
and played over 50 times will keep a high rating even if you skipped it the last
10 times. That's were the *rolling_rating* comes in.
If a song has been fully played, the *rolling_rating* is calculated like
this::
If a song has been fully played, the *rolling_rating* is calculated like this:
::
rolling_rating = old_rating + (1.0 - old_rating) / 2.0
If a song has been skipped, like this::
If a song has been skipped, like this:
::
rolling_rating = old_rating - old_rating / 2.0
So *rolling_rating* adapts pretty fast to *recent developments*. But it's too
fast. Taking the example from above, your old favorite with 50 plays will get
a negative rating (<0.5) the first time you skip it. Also not good.
So *rolling_rating* adapts pretty fast to *recent developments*. But it's too
fast. Taking the example from above, your old favorite with 50 plays will get a
negative rating (<0.5) the first time you skip it. Also not good.
To take the best of both worlds, we mix the ratings together with the
``rating_mix`` factor. A ``rating_mix`` of 0.0 means all
*rolling* and 1.0 means all *stable*. We found 0.75 to be a good compromise,
but fell free to play with that.
``rating_mix`` factor. A ``rating_mix`` of 0.0 means all *rolling* and 1.0 means
all *stable*. We found 0.75 to be a good compromise, but fell free to play with
that.
Warning
-------
This has only been tested with MPD versions >= 0.16. It may not work
on older versions. If that is the case, please report an `issue`_.
This has only been tested with MPD versions >= 0.16. It may not work on older
versions. If that is the case, please report an issue_.
.. _issue: https://github.com/beetbox/beets/issues

Some files were not shown because too many files have changed in this diff Show more