mirror of
https://github.com/beetbox/beets.git
synced 2026-01-04 15:03:22 +01:00
Merge branch 'master' into multivalued-flexible-fields
This commit is contained in:
commit
c0675fefb8
138 changed files with 9164 additions and 8807 deletions
|
|
@ -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
|
||||
|
|
|
|||
16
.github/problem-matchers/sphinx-build.json
vendored
Normal file
16
.github/problem-matchers/sphinx-build.json
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "sphinx-build",
|
||||
"severity": "error",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(/[^:]+):((\\d+):)?(\\sWARNING:)?\\s*(.+)$",
|
||||
"file": 1,
|
||||
"line": 3,
|
||||
"message": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
17
.github/problem-matchers/sphinx-lint.json
vendored
Normal file
17
.github/problem-matchers/sphinx-lint.json
vendored
Normal 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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
15
.github/sphinx-problem-matcher.json
vendored
15
.github/sphinx-problem-matcher.json
vendored
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "sphinx",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^([^:]+):(\\d+): (WARNING: )?(.+)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"message": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
12
.github/workflows/changelog_reminder.yaml
vendored
12
.github/workflows/changelog_reminder.yaml
vendored
|
|
@ -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 }}'
|
||||
|
|
|
|||
20
.github/workflows/ci.yaml
vendored
20
.github/workflows/ci.yaml
vendored
|
|
@ -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) }}
|
||||
|
|
|
|||
28
.github/workflows/lint.yml
vendored
28
.github/workflows/lint.yml
vendored
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>`_.
|
||||
|
||||
|
|
|
|||
464
CONTRIBUTING.rst
464
CONTRIBUTING.rst
|
|
@ -1,111 +1,106 @@
|
|||
############
|
||||
Contributing
|
||||
############
|
||||
============
|
||||
|
||||
.. contents::
|
||||
:depth: 3
|
||||
|
||||
Thank you!
|
||||
==========
|
||||
----------
|
||||
|
||||
First off, thank you for considering contributing to beets! It’s people
|
||||
like you that make beets continue to succeed.
|
||||
First off, thank you for considering contributing to beets! It’s 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 you’re a programmer or not.
|
||||
We love to get contributions from our community—you! There are many ways to
|
||||
contribute, whether you’re 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`_. It’s
|
||||
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 that’s mostly because we don’t have any great ideas for what a
|
||||
good GUI should look like. If you have those great ideas, please get
|
||||
in touch.
|
||||
- Benchmarks. We’d 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? We’d 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_. It’s 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
|
||||
that’s mostly because we don’t have any great ideas for what a good GUI should
|
||||
look like. If you have those great ideas, please get in touch.
|
||||
- Benchmarks. We’d 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? We’d 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 you’re just a beginner!), you have a ton of
|
||||
opportunities to get your feet wet with beets.
|
||||
- For developing plugins, or hacking away at beets, there’s some good
|
||||
information in the `“For Developers” section of the
|
||||
docs <https://beets.readthedocs.io/en/stable/dev/>`__.
|
||||
- As a programmer (even if you’re just a beginner!), you have a ton of
|
||||
opportunities to get your feet wet with beets.
|
||||
- For developing plugins, or hacking away at beets, there’s 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
|
||||
you’d 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 you’d 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 you’ve fixed a bug, write a test to ensure that you’ve
|
||||
actually fixed it. If there’s a new feature or plugin, please
|
||||
contribute tests that show that your code does what it says.
|
||||
5. Add documentation. If you’ve 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 you’ve fixed a bug, write a test to ensure that you’ve actually
|
||||
fixed it. If there’s a new feature or plugin, please contribute tests that
|
||||
show that your code does what it says.
|
||||
5. Add documentation. If you’ve 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! We’ll 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 doesn’t
|
||||
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 doesn’t 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 you’ll 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 you’ll 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 you’re 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 you’re 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/
|
||||
|
|
|
|||
149
README.rst
149
README.rst
|
|
@ -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/
|
||||
|
|
|
|||
227
README_kr.rst
227
README_kr.rst
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
251
beets/plugins.py
251
beets/plugins.py
|
|
@ -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
0
beets/py.typed
Normal 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):
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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}'")
|
||||
|
|
|
|||
|
|
@ -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__"
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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 geek’s 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">▶</button>
|
||||
<button class="play">▶</button>
|
||||
<button class="pause" style="letter-spacing: 1px;">❙❙</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) { %> – <% } %>
|
||||
<% if (album) { %><%= album %><% } %>
|
||||
<% if ((artist || album) && title) { %> – <% } %>
|
||||
<%= title %>
|
||||
<span class="playing">▶</span>
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
2
docs/_templates/autosummary/base.rst
vendored
2
docs/_templates/autosummary/base.rst
vendored
|
|
@ -1,3 +1,3 @@
|
|||
{{ fullname | escape | underline}}
|
||||
.. currentmodule:: {{ module }}
|
||||
.. auto{{ objtype }}:: {{ objname }}
|
||||
.. auto{{ objtype }}:: {{ objname }}
|
||||
|
|
|
|||
7
docs/_templates/autosummary/class.rst
vendored
7
docs/_templates/autosummary/class.rst
vendored
|
|
@ -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') }}
|
||||
|
||||
|
|
|
|||
2
docs/_templates/autosummary/module.rst
vendored
2
docs/_templates/autosummary/module.rst
vendored
|
|
@ -8,4 +8,4 @@
|
|||
|
||||
{%- endfor %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
Plugins
|
||||
-------
|
||||
=======
|
||||
|
||||
.. currentmodule:: beets.plugins
|
||||
|
||||
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated/
|
||||
|
||||
|
|
|
|||
6090
docs/changelog.rst
6090
docs/changelog.rst
File diff suppressed because it is too large
Load diff
|
|
@ -1,3 +1,4 @@
|
|||
.. code_of_conduct:
|
||||
..
|
||||
code_of_conduct:
|
||||
|
||||
.. include:: ../CODE_OF_CONDUCT.rst
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
.. contributing:
|
||||
..
|
||||
contributing:
|
||||
|
||||
.. include:: ../CONTRIBUTING.rst
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
420
docs/faq.rst
420
docs/faq.rst
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
------
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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``
|
||||
|
|
|
|||
|
|
@ -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. 65–75 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. 65–75 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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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. 65–75 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. 65–75 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
|
||||
|
|
|
|||
|
|
@ -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[^/]+$
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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`).
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
--------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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: |
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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``
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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+
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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``.
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in a new issue