beets-filetote


Namebeets-filetote JSON
Version 0.4.9 PyPI version JSON
download
home_pagehttps://github.com/gtronset/beets-filetote
SummaryA beets plugin to copy/moves non-music extra files, attachments, and artifacts during the import process.
upload_time2024-04-20 22:20:56
maintainerNone
docs_urlNone
authorGavin Tronset
requires_python<4.0,>=3.6
licenseMIT
keywords beets files artifacts extra
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # _Filetote_ plugin for beets

[![MIT license][license image]][license link]
[![CI][ci image]][ci link]
[![GitHub release][github image]][github link]
[![PyPI][pypi_version]][pypi_link]
[![PyPI - Python Version][pypi_python_versions]][pypi_link]

A plugin that moves non-music extra files, attachments, and artifacts during imports and
CLI file manipulation actions (`move`, `modify`, reimport, etc.) for [beets], a music
library manager (and much more!).

This plugin is supported/runs in beets [`v1.6.0`]. The unrealease "latest" version of
beets is not (yet) officially supported.

[beets]: https://beets.io/

## Installing

### Stable

The stable version of the plugin is available from PyPI and can be installed using
`pip3`:

```sh
pip3 install beets-filetote
```

> **Important Note:** Python versions <3.7 will need to also install the [dataclasses]
> module.

[dataclasses]: https://pypi.org/project/dataclasses/

## Configuration

You will need to enable the plugin in beets' `config.yaml`:

```yaml
plugins: filetote
```

It can copy files by file extension:

```yaml
filetote:
  extensions: .cue .log
```

Or copy all non-music files:

```yaml
filetote:
  extensions: .*
```

Or copy files by filename:

```yaml
filetote:
  filenames: song.log
```

Or match based on a "pattern" ([glob pattern]):

```yaml
filetote:
  patterns:
    artworkdir:
      - "[aA]rtwork/"
```

It can look for and target "pairs" (files having the same name as a matching or "paired"
media item/track):

```yaml
filetote:
  pairing:
    enabled: true
```

You can specify pairing to happen to certain extensions, and even target/include only
paired files:

```yaml
filetote:
  pairing:
    enabled: true
    pairing_only: true
    extensions: ".lrc"
```

It can also exclude files by name:

```yaml
filetote:
  exclude: song_lyrics.nfo
```

And print what got left:

```yaml
filetote:
  print_ignored: true
```

`exclude`-d files take precedence over other matching, meaning exclude will override
other matches by either `extensions` or `filenames`.

[glob pattern]: https://docs.python.org/3/library/glob.html#module-glob

### File Handling & Renaming

In order to collect extra files and artifacts, Filetote needs to be told which types of
files it should care about. This can be done using the following:

- Extensions (`ext:`): Specify individual extensions like `.cue` or `.log`, or catch all
  non-music files with `.*`.
- Filenames (`filename:`): Match specific filenames like `cover.jpg` or organize artwork
  with `[aA]rtwork/*`.
- Patterns (`pattern:`): Use flexible glob patterns for more control, like matching all
  logs in a subfolder: `CD1/*.log`.
- Pairing: Move files with the same name as imported music items, like `.lrc` lyrics or
  album logs.

#### Filetote Renaming Basics

Unless otherwise specified, the default name for artifacts and extra files is:
`$albumpath/$old_filename`. This means that by default, the file is essentially
moved/copied into destination directory of the music item it gets grabbed with. This
also means that the album folder is flattened and any subdirectory is removed by
default. To preserve subdirectories, see `$subpath` usage [here](#subpath-renaming-example).

Configuration for renaming works in much the same way as beets [Path Formats], including
the standard metadata values provided by beets. Filetote provides the below new path
queries, which each takes a single corresponding value. These can be defined in either
the top-level `paths` section of Beet's config or in the `paths` section of Filetote's
config. Both of the following are equivalent:

```yaml
paths:
  ext:.log: $albumpath/$artist - $album
```

```yaml
filetote:
  paths:
    ext:.log: $albumpath/$artist - $album
```

[Path Formats]: http://beets.readthedocs.org/en/stable/reference/pathformat.html

##### New path queries

These are the new path queries added by Filetote, from _most_ to _least_ specific:

- `filename:`
- `paired_ext:`
- `pattern:`
- `ext:`

This means that the `filename:` path query will take precedence over `paired_ext:`,
`pattern:`, and `ext:` if a given file qualifies for them. This also means that
the value in `paired_ext:` will take precedence over `pattern:` and `ext:`, and
`pattern:` is higher priority than `ext:`.

##### Renaming considerations

Renaming has the following considerations:

The fields available include [the standard metadata values] of the imported item
(`$albumartist`, `$album`, `$title`, etc.), along with Filetote-specific values of:

- `$albumpath`: the entire path of the new destination of the item/track (a useful
  shorthand for when the extra/artifact file will be moved allongside  the item/track).
    - **Note**: Beets doesn't have a strict "album" path concept. All references are
      relative to Items (the actual media files). This is especially relevant for
      multi-disc files/albums, but usually isn't a problem. Check the section on
      multi-discs [here](#advanced-renaming-for-multi-disc-albums) for more details.
- `$subpath`: Represents any subdirectories under the base album path where an
  extra/artifact file resides. For use when it is desirable to preserve the directory
  hierarchy in the albums. This respects the original capitalization of directory names.
  Defaults to an empty string when no subdirectories exist.
    - **Example:** If an extra file is located in a subdirectory named "Extras" under
    the album path, `$subpath` would be set to "Extras/" (with the same casing).
- `$old_filename`: the filename of the extra/artifact file before its renamed.
- `$medianame_old`: the filename of the item/track triggering it, _before_ it's renamed.
- `$medianame_new`: the filename of the item/track triggering it, _after_ it's renamed.

The full set of [built in functions] are also supported, with the exception of
`%aunique` - which will return an empty string.

Note that the fields mentioned above are not usable within other plugins like `inline`.
But `inline` and other plugins should be fine otherwise.

> **Important Note:** if the rename is set and there are multiple files that qualify,
> only the first will be added to the library (new folder); other files that
> subsequently match will not be saved/renamed. To work around this, `$old_filename`
> can be used to help with adding uniqueness to the name.

[the standard metadata values]: https://beets.readthedocs.io/en/stable/reference/pathformat.html#available-values
[built in functions]: http://beets.readthedocs.org/en/stable/reference/pathformat.html#functions

##### Subpath Renaming Example

The following configuration or template string will be applied to `.log` files by using
the `$subpath` and will rename log file to:
`~/Music/Artist/2014 - Album/Extras/Artist - Album.log`

This assumes that the original file is in the subdirectory (subpath) of `Extras/`. Any
other `.log` files in other subdirectories or in the root of the album will be moved
accordingly. If a more targeted approach is needed, this can be combined with the
`pattern:` query.

**Note:** `$subpath` automatically adds in path separators including the end one if there
are subdirectories.

```yaml
paths:
  ext:.log: $albumpath/$subpath$artist - $album
```

#### Extension (`ext:`)

Filename can match on the extension of the file, in a space-delimited list (i.e., a
string sequence). Use `.*` to match all file extensions.

##### Extension Example Configuration

This example will match any file which has an extension of either `.lrc` or `.log`,
across all subfolders.

```yaml
filetote:
  ext: .lrc .log
```

##### Extension Renaming Example

The following configuration or template string will be applied to `.log` files by using
the `ext:` query and will rename log file to:
`~/Music/Artist/2014 - Album/Artist - Album.log`

```yaml
paths:
  ext:.log: $albumpath/$artist - $album
```

#### Filename (`filename:`)

Filetote can match on the actual name (including extension) of the file, in a
space-delimited list (string sequence). `filename:` will match across any subdirectories,
meaning targeting a filename in a specific subdirectory will not work (this functionality
_can_ be achieved using a `pattern`, however).

##### Filename Example Configuration

This example will match if the filename of the given artifact or extra file matches the name
exactly as specified, either `cover.jpg` or `artifact.nfo`.

```yaml
filetote:
  filenames: cover.jpg artifact.nfo
```

##### Filename Renaming Example

The following configuration will rename the specific `artifact.nfo` file to:
`~/Music/Artist/2014 - Album/Artist - Album.nfo`

```yaml
filetote:
  paths:
    filename:artifact.nfo: $albumpath/$artist - $album
  filenames: cover.jpg artifact.nfo
```

#### Pattern (`pattern:`)

Filetote can match on a given _pattern_ as specified using [glob patterns]. This allows
for more specific matching, like grabbing only PNG artwork files. Paths in the pattern
are relative to the root of the importing album. Hence, if there are subdirectories in
the album's folder (for multidisc setups, for instance, e.g., `albumpath/CD1`), the
album's path would be the base/root for the pattern (ex: `CD1/*.jpg`). Patterns will
work with or without the proceeding slash (`/`). Note: Windows users will need to
use the appropriate slash (`\`).

Patterns specifying folders with a trailing slash will (ex: `albumpath/`) will match
every file in that subdirectory irrespective of name or extension (it is equivalent to
`albumpath/*.*`).

Patterns are defined by a _name_ so that any customization for renaming can apply to the
pattern when specifying the path (ex: `pattern:artworkdir`; see the section on renaming
below).

[glob patterns]: https://docs.python.org/3/library/glob.html#module-glob

##### Pattern Example Configuration

This example will match if the filename of the given artifact or extra file matches the name
exactly as specified, either `cover.jpg` or `artifact.nfo`.

This example will match all files within the given subdirectory of either `artwork/` or
`Artwork/`. Since it's not otherwise specified, `[aA]rtwork/` will grab all non-media
files in that subdirectory irrespective of name or extension.

```yaml
filetote:
  patterns:
    artworkdir:
      - "[aA]rtwork/"
```

##### Pattern Renaming Example

The following pattern configuration will rename the file `artwork/cover.jpeg` to:
`~/Music/Artist/2014 - Album/artwork/cover.jpeg`

```yaml
filetote:
  paths:
    pattern:artworkdir: $albumpath/artwork/$old_filename
  patterns:
    artworkdir:
      - "[aA]rtwork/"
```

#### Pairing

Filetote can specially target related files like lyrics or logs with the same name as
music files ("paired" files). This keeps related files together, making your library
even more organized. When enabled, it will match and move those files having the same
name as a matching music file. Pairing can be configured to target only certain
extensions, such as `.lrc`.

**Note:** Pairing takes precedence over other Filetote rules like filename or patterns.

##### Pairing Example Configuration

This example configuration will grab paired `.lrc` files, along with any artwork files:

```yaml
filetote:
  pairing:
    enabled: true
    extensions: ".lrc"
  patterns:
    artworkdir:
          - "[aA]rtwork/"
```

Filetote can also be configured to _only_ target paired files, which will ignore other
Filetote configurations such as filename or patterns as described above. The following
configuration would _only_ target `.lrc` files:

```yaml
filetote:
  pairing:
    enabled: true
    pairing_only: true
    extensions: ".lrc"
```

##### Pairing Renaming

To mainting the concept of "pairs" after importing, it is strongly encouraged to set
the `path` for the paired files to use the media files new name. This will ensure thet
the file remains paired even after moving. E.g.:

```yaml
paths:
  paired_ext:.lrc: $albumpath/$medianame_new
```

### Import Operations

This plugin supports the same operations as beets:

- `copy`
- `move`
- `link` (symlink)
- `harklink`
- `reflink`

These options are mutually exclusive, and there are nuances to how beets (and thus this
plugin) behave when there multiple set. See the [beets import documentation] and [#36]
for more details.

Reimporting has an additional nuance when copying of linking files that are already in
the library, in which files will be moved rather than duplicated. This behavior in
Filetote is identical to that of beets. See the [beets reimport documentation] for more
details.

[beets import documentation]: https://beets.readthedocs.io/en/stable/reference/config.html#importer-options
[#36]: https://github.com/gtronset/beets-filetote/pull/36
[beets reimport documentation]: https://beets.readthedocs.io/en/stable/reference/cli.html#reimporting

### Other CLI Operations

Additional commands such such as `move`, `modify`, `update`, etc. will also trigger
Filetote to handle files. These commands typically work with [queries], targeting
specific files that match the supplied query. Please note that the operation executed
by beets for these commands do not use the value set in the config file under `import`,
they instead are specified as part of the CLI command.

[queries]: https://beets.readthedocs.io/en/stable/reference/query.html

### Examples of `config.yaml`

```yaml
plugins: filetote

paths:
  default: $albumartist/$year - $album/$track - $title
  singleton: Singletons/$artist - $title
  ext:.log: $albumpath/$artist - $album
  ext:.cue: $albumpath/$artist - $album
  paired_ext:.lrc: $albumpath/$medianame_new
  filename:cover.jpg: $albumpath/cover

filetote:
  extensions: .cue .log .jpg
  filename: "cover.jpg"
  pairing:
    enabled: true
    extensions: ".lrc"
  print_ignored: true
```

Or:

```yaml
plugins: filetote

paths:
  default: $albumartist/$year - $album/$track - $title
  singleton: Singletons/$artist - $title

filetote:
  extensions: .cue
  patterns:
    artworkdir:
      - "[sS]cans/"
      - "[aA]rtwork/"
  pairing:
    enabled: true
    extensions: ".lrc"
  paths:
    pattern:artworkdir: $albumpath/artwork
    paired_ext:.lrc: $albumpath/$medianame_old
    filename:cover.jpg: $albumpath/cover  
```

## Multi-Disc and Nested Import Directories

beets imports multi-disc albums as a single unit ([see beets documentation]). By
default, this results in the media importing to a single directory in the library.
Artifacts and extra files in the initial subdirectories will brought by Filetote to the
destination of the file's they're near, resulting in them landing where one would expect.
Because of this, the files will also be moved by Filetote to any specified subdirectory
in the library if the path definition creates "Disc N" subfolders
[as described in the beets documentation].

In short, artifacts and extra files in these scenarios should simply just move/copy as
expected.

[see beets documentation]: https://beets.readthedocs.io/en/stable/faq.html#import-a-multi-disc-album
[as described in the beets documentation]: https://beets.readthedocs.io/en/stable/faq.html#create-disc-n-directories-for-multi-disc-albums

### Advanced renaming for multi-disc albums

The value for `$albumpath` is actually based on the path for the Item (music file) the
lead to the artifact to be moved. Since it's common to store multi-disc albums with
subfolders, this means that by default the artifact or extra file in question will also
be in a subfolder.

For macOS and Linux, to achieve a different location (say the media is in
`Artist/Disc 01` but artifacts are intended to be in `Artist/Extras`), `..` can be used
to navigate to the parent directory of the `$albumpath` so that the entirety of the
media's path does not have to be recreated. For Windows, the entire media path would
need to be recreated as Windows sees `..` as an attempt to create a directory with the
name `..` within path instead of it being a path component representing the parent.

#### macOS & Linux

The following example will have the following results on macOS & Linux:

- Music: `~/Music/Artist/2014 - Album/Disc 1/media.mp3`
- Artifact: `~/Music/Artist/2014 - Album/Extras/example.log`

```yaml
plugins: filetote

paths:
  default: $albumartist/$year - $album/$track - $title
  comp: $albumartist/$year - $album/Disc $disc/$track - $title

filetote:
  extensions: .log
  paths:
    ext:log: $albumpath/../Extras/$old_filename
```

#### Windows

The following example will have the following results on Windows:

- Music: `~/Music/Artist/2014 - Album/Disc 1/media.mp3`
- Artifact: `~/Music/Artist/2014 - Album/Extras/example.log`

```yaml
plugins: filetote

paths:
  default: $albumartist/$year - $album/$track - $title
  comp: $albumartist/$year - $album/Disc $disc/$track - $title

filetote:
  extensions: .log
  paths:
    ext:log: $albumartist/$year - $album/Extras/$old_filename
```

## Why Filetote and Not Other Plugins?

Filetote serves the same core purpose as the [`copyfilertifacts` plugin] and the
[`extrafiles` plugin], however both have lacked in maintenance over the last few years.
There are outstanding bugs in each (though `copyfilertifacts` has seen some recent
activity resolving some). In addition, each are lacking in certain features and
abilities, such as hardlink/reflink support, "paired" file handling, and extending
renaming options. What's more, significant focus has been provided to Filetote around
Python3 conventions, linting, and typing in order to promote healthier code and easier
maintenance.

Filetote strives to encompass all functionality that _both_ `copyfilertifacts`
and `extrafiles` provide, and then some!

[`copyfilertifacts` plugin]: https://github.com/adammillerio/beets-copyartifacts
[`extrafiles` plugin]: https://github.com/Holzhaus/beets-extrafiles

### Migrating from `copyfilertifacts`

Filetote can be configured using nearly identical configuration as `copyfilertifacts`,
simply replacing the name of the plugin in its configuration settings. **There is one
change that's needed if all extensions are desired, as Filetote does not grab all
extensions by default (as `copyfilertifacts` does).** To accommodate, simply explicitly
state all extension using `.*`:

```yaml
filetote:
  extensions: .*
```

Otherwise, simply replacing the name in the config section will work. For example:

```yaml
copyartifacts:
  extensions: .cue .log
```

Would become:

```yaml
filetote:
  extensions: .cue .log
```

Path definitions can also be specified in the way that `copyfileartifacts` does,
alongside other path definitions for beets. E.g.:

```yaml
paths:
  ext:log: $albumpath/$artist - $album
```

### Migrating from `extrafiles`

Filetote can be configured using nearly identical configuration as `extrafiles`, simply
replacing the name of the plugin in its configuration settings. For example:

```yaml
extrafiles:
  patterns:
    all: "*.*"
```

Would become:

```yaml
filetote:
  patterns:
    all: "*.*"
```

Path definitions can also be specified in the way that `extrafiles` does, e.g.:

```yaml
filetote:
  patterns:
    artworkdir:
      - '[sS]cans/'
      - '[aA]rtwork/'
  paths:
    artworkdir: $albumpath/artwork
```

## Version Upgrade Instructions

Certain versoins require changes to configurations as upgrades occur. Please see below
for specific steps for each version.

### `0.4.0`

#### Default for `extensions` is now `None`

As of version `0.4.0`, Filetote no longer set the default for `extensions` to `.*`.
Instead, setting Filetote to collect all extensions needs to be explicitly defined, e.g.:

```yaml
filetote:
  extensions: .*
```

#### Pairing Config Changes

`pairing` has been converted from a boolean to an object with other like-config. Take
the following config:

```yaml
filetote:
  pairing: true
  pairing_only: false
```

These will both now be represented as individual settings within `pairing`:

```yaml
filetote:
  pairing:
    enabled: true
    pairing_only: false
    extensions: ".lrc"
```

Both remain optional and both default to `false`.

## Development

The development version can be installed with [Poetry], a Python dependency manager
that provides dependency isolation, reproducibility, and streamlined packaging to PyPI.

Testing and linting is performed with [Tox].

[Poetry]: https://python-poetry.org/
[Tox]: https://tox.wiki/

Filetote currently supports Python 3.6+, which aligns with the most recent version of
beets ([`v1.6.0`]).

**1. Install Poetry & Tox:**

```sh
python3 -m pip install poetry tox
```

**2. Clone the repository and install the plugin:**

```sh
git clone https://github.com/gtronset/beets-filetote.git
cd beets-filetote
poetry install
```

**3. Update the config.yaml to utilize the plugin:**

```yaml
pluginpath:
  - /path/to.../beets-filetote/beetsplug
```

**4. Run or test with Poetry (and Tox):**

Run beets with the following to locally develop:

```sh
poetry run beet
```

Testing can be run with Tox, ex.:

```sh
poetry run tox -e py312
```

For other linting environments, see `tox.ini`. Ex: `black`:

```sh
poetry run tox -e black
```

**Docker:**

A Docker Compose configuration is available for running the plugin in a controlled
environment. Running the `docker-compose.yml` file for details.

## Thanks

This plugin originated as a hard fork from [beets-copyartifacts (copyartifacts3)].

Thank you to the original work done by Sami Barakat and Adrian Sampson, along with the
larger [beets](http://beets.io) community.

Please report any issues you may have and feel free to contribute.

[beets-copyartifacts (copyartifacts3)]: https://github.com/adammillerio/beets-copyartifacts

## License

Copyright (c) 2022 Gavin Tronset

Licensed under the [MIT license][license link].

[license image]: https://img.shields.io/badge/License-MIT-blue.svg
[license link]: https://github.com/gtronset/beets-filetote/blob/main/LICENSE
[ci image]: https://github.com/gtronset/beets-filetote/actions/workflows/tox.yml/badge.svg
[ci link]: https://github.com/gtronset/beets-filetote/actions/workflows/tox.yml
[github image]: https://img.shields.io/github/release/gtronset/beets-filetote.svg
[github link]: https://github.com/gtronset/beets-filetote/releases
[pypi_version]: https://img.shields.io/pypi/v/beets-filetote
[pypi_link]: https://pypi.org/project/beets-filetote/
[pypi_python_versions]: https://img.shields.io/pypi/pyversions/beets-filetote

[`v1.6.0`]: https://pypi.org/project/beets/1.6.0/

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/gtronset/beets-filetote",
    "name": "beets-filetote",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.6",
    "maintainer_email": null,
    "keywords": "beets, files, artifacts, extra",
    "author": "Gavin Tronset",
    "author_email": "gtronset@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/53/f6/9e9872ece053a627c7df1e781ce4ba9a4bf3f6cf9a12e24498e1c8228125/beets_filetote-0.4.9.tar.gz",
    "platform": null,
    "description": "# _Filetote_ plugin for beets\n\n[![MIT license][license image]][license link]\n[![CI][ci image]][ci link]\n[![GitHub release][github image]][github link]\n[![PyPI][pypi_version]][pypi_link]\n[![PyPI - Python Version][pypi_python_versions]][pypi_link]\n\nA plugin that moves non-music extra files, attachments, and artifacts during imports and\nCLI file manipulation actions (`move`, `modify`, reimport, etc.) for [beets], a music\nlibrary manager (and much more!).\n\nThis plugin is supported/runs in beets [`v1.6.0`]. The unrealease \"latest\" version of\nbeets is not (yet) officially supported.\n\n[beets]: https://beets.io/\n\n## Installing\n\n### Stable\n\nThe stable version of the plugin is available from PyPI and can be installed using\n`pip3`:\n\n```sh\npip3 install beets-filetote\n```\n\n> **Important Note:** Python versions <3.7 will need to also install the [dataclasses]\n> module.\n\n[dataclasses]: https://pypi.org/project/dataclasses/\n\n## Configuration\n\nYou will need to enable the plugin in beets' `config.yaml`:\n\n```yaml\nplugins: filetote\n```\n\nIt can copy files by file extension:\n\n```yaml\nfiletote:\n  extensions: .cue .log\n```\n\nOr copy all non-music files:\n\n```yaml\nfiletote:\n  extensions: .*\n```\n\nOr copy files by filename:\n\n```yaml\nfiletote:\n  filenames: song.log\n```\n\nOr match based on a \"pattern\" ([glob pattern]):\n\n```yaml\nfiletote:\n  patterns:\n    artworkdir:\n      - \"[aA]rtwork/\"\n```\n\nIt can look for and target \"pairs\" (files having the same name as a matching or \"paired\"\nmedia item/track):\n\n```yaml\nfiletote:\n  pairing:\n    enabled: true\n```\n\nYou can specify pairing to happen to certain extensions, and even target/include only\npaired files:\n\n```yaml\nfiletote:\n  pairing:\n    enabled: true\n    pairing_only: true\n    extensions: \".lrc\"\n```\n\nIt can also exclude files by name:\n\n```yaml\nfiletote:\n  exclude: song_lyrics.nfo\n```\n\nAnd print what got left:\n\n```yaml\nfiletote:\n  print_ignored: true\n```\n\n`exclude`-d files take precedence over other matching, meaning exclude will override\nother matches by either `extensions` or `filenames`.\n\n[glob pattern]: https://docs.python.org/3/library/glob.html#module-glob\n\n### File Handling & Renaming\n\nIn order to collect extra files and artifacts, Filetote needs to be told which types of\nfiles it should care about. This can be done using the following:\n\n- Extensions (`ext:`): Specify individual extensions like `.cue` or `.log`, or catch all\n  non-music files with `.*`.\n- Filenames (`filename:`): Match specific filenames like `cover.jpg` or organize artwork\n  with `[aA]rtwork/*`.\n- Patterns (`pattern:`): Use flexible glob patterns for more control, like matching all\n  logs in a subfolder: `CD1/*.log`.\n- Pairing: Move files with the same name as imported music items, like `.lrc` lyrics or\n  album logs.\n\n#### Filetote Renaming Basics\n\nUnless otherwise specified, the default name for artifacts and extra files is:\n`$albumpath/$old_filename`. This means that by default, the file is essentially\nmoved/copied into destination directory of the music item it gets grabbed with. This\nalso means that the album folder is flattened and any subdirectory is removed by\ndefault. To preserve subdirectories, see `$subpath` usage [here](#subpath-renaming-example).\n\nConfiguration for renaming works in much the same way as beets [Path Formats], including\nthe standard metadata values provided by beets. Filetote provides the below new path\nqueries, which each takes a single corresponding value. These can be defined in either\nthe top-level `paths` section of Beet's config or in the `paths` section of Filetote's\nconfig. Both of the following are equivalent:\n\n```yaml\npaths:\n  ext:.log: $albumpath/$artist - $album\n```\n\n```yaml\nfiletote:\n  paths:\n    ext:.log: $albumpath/$artist - $album\n```\n\n[Path Formats]: http://beets.readthedocs.org/en/stable/reference/pathformat.html\n\n##### New path queries\n\nThese are the new path queries added by Filetote, from _most_ to _least_ specific:\n\n- `filename:`\n- `paired_ext:`\n- `pattern:`\n- `ext:`\n\nThis means that the `filename:` path query will take precedence over `paired_ext:`,\n`pattern:`, and `ext:` if a given file qualifies for them. This also means that\nthe value in `paired_ext:` will take precedence over `pattern:` and `ext:`, and\n`pattern:` is higher priority than `ext:`.\n\n##### Renaming considerations\n\nRenaming has the following considerations:\n\nThe fields available include [the standard metadata values] of the imported item\n(`$albumartist`, `$album`, `$title`, etc.), along with Filetote-specific values of:\n\n- `$albumpath`: the entire path of the new destination of the item/track (a useful\n  shorthand for when the extra/artifact file will be moved allongside  the item/track).\n    - **Note**: Beets doesn't have a strict \"album\" path concept. All references are\n      relative to Items (the actual media files). This is especially relevant for\n      multi-disc files/albums, but usually isn't a problem. Check the section on\n      multi-discs [here](#advanced-renaming-for-multi-disc-albums) for more details.\n- `$subpath`: Represents any subdirectories under the base album path where an\n  extra/artifact file resides. For use when it is desirable to preserve the directory\n  hierarchy in the albums. This respects the original capitalization of directory names.\n  Defaults to an empty string when no subdirectories exist.\n    - **Example:** If an extra file is located in a subdirectory named \"Extras\" under\n    the album path, `$subpath` would be set to \"Extras/\" (with the same casing).\n- `$old_filename`: the filename of the extra/artifact file before its renamed.\n- `$medianame_old`: the filename of the item/track triggering it, _before_ it's renamed.\n- `$medianame_new`: the filename of the item/track triggering it, _after_ it's renamed.\n\nThe full set of [built in functions] are also supported, with the exception of\n`%aunique` - which will return an empty string.\n\nNote that the fields mentioned above are not usable within other plugins like `inline`.\nBut `inline` and other plugins should be fine otherwise.\n\n> **Important Note:** if the rename is set and there are multiple files that qualify,\n> only the first will be added to the library (new folder); other files that\n> subsequently match will not be saved/renamed. To work around this, `$old_filename`\n> can be used to help with adding uniqueness to the name.\n\n[the standard metadata values]: https://beets.readthedocs.io/en/stable/reference/pathformat.html#available-values\n[built in functions]: http://beets.readthedocs.org/en/stable/reference/pathformat.html#functions\n\n##### Subpath Renaming Example\n\nThe following configuration or template string will be applied to `.log` files by using\nthe `$subpath` and will rename log file to:\n`~/Music/Artist/2014 - Album/Extras/Artist - Album.log`\n\nThis assumes that the original file is in the subdirectory (subpath) of `Extras/`. Any\nother `.log` files in other subdirectories or in the root of the album will be moved\naccordingly. If a more targeted approach is needed, this can be combined with the\n`pattern:` query.\n\n**Note:** `$subpath` automatically adds in path separators including the end one if there\nare subdirectories.\n\n```yaml\npaths:\n  ext:.log: $albumpath/$subpath$artist - $album\n```\n\n#### Extension (`ext:`)\n\nFilename can match on the extension of the file, in a space-delimited list (i.e., a\nstring sequence). Use `.*` to match all file extensions.\n\n##### Extension Example Configuration\n\nThis example will match any file which has an extension of either `.lrc` or `.log`,\nacross all subfolders.\n\n```yaml\nfiletote:\n  ext: .lrc .log\n```\n\n##### Extension Renaming Example\n\nThe following configuration or template string will be applied to `.log` files by using\nthe `ext:` query and will rename log file to:\n`~/Music/Artist/2014 - Album/Artist - Album.log`\n\n```yaml\npaths:\n  ext:.log: $albumpath/$artist - $album\n```\n\n#### Filename (`filename:`)\n\nFiletote can match on the actual name (including extension) of the file, in a\nspace-delimited list (string sequence). `filename:` will match across any subdirectories,\nmeaning targeting a filename in a specific subdirectory will not work (this functionality\n_can_ be achieved using a `pattern`, however).\n\n##### Filename Example Configuration\n\nThis example will match if the filename of the given artifact or extra file matches the name\nexactly as specified, either `cover.jpg` or `artifact.nfo`.\n\n```yaml\nfiletote:\n  filenames: cover.jpg artifact.nfo\n```\n\n##### Filename Renaming Example\n\nThe following configuration will rename the specific `artifact.nfo` file to:\n`~/Music/Artist/2014 - Album/Artist - Album.nfo`\n\n```yaml\nfiletote:\n  paths:\n    filename:artifact.nfo: $albumpath/$artist - $album\n  filenames: cover.jpg artifact.nfo\n```\n\n#### Pattern (`pattern:`)\n\nFiletote can match on a given _pattern_ as specified using [glob patterns]. This allows\nfor more specific matching, like grabbing only PNG artwork files. Paths in the pattern\nare relative to the root of the importing album. Hence, if there are subdirectories in\nthe album's folder (for multidisc setups, for instance, e.g., `albumpath/CD1`), the\nalbum's path would be the base/root for the pattern (ex: `CD1/*.jpg`). Patterns will\nwork with or without the proceeding slash (`/`). Note: Windows users will need to\nuse the appropriate slash (`\\`).\n\nPatterns specifying folders with a trailing slash will (ex: `albumpath/`) will match\nevery file in that subdirectory irrespective of name or extension (it is equivalent to\n`albumpath/*.*`).\n\nPatterns are defined by a _name_ so that any customization for renaming can apply to the\npattern when specifying the path (ex: `pattern:artworkdir`; see the section on renaming\nbelow).\n\n[glob patterns]: https://docs.python.org/3/library/glob.html#module-glob\n\n##### Pattern Example Configuration\n\nThis example will match if the filename of the given artifact or extra file matches the name\nexactly as specified, either `cover.jpg` or `artifact.nfo`.\n\nThis example will match all files within the given subdirectory of either `artwork/` or\n`Artwork/`. Since it's not otherwise specified, `[aA]rtwork/` will grab all non-media\nfiles in that subdirectory irrespective of name or extension.\n\n```yaml\nfiletote:\n  patterns:\n    artworkdir:\n      - \"[aA]rtwork/\"\n```\n\n##### Pattern Renaming Example\n\nThe following pattern configuration will rename the file `artwork/cover.jpeg` to:\n`~/Music/Artist/2014 - Album/artwork/cover.jpeg`\n\n```yaml\nfiletote:\n  paths:\n    pattern:artworkdir: $albumpath/artwork/$old_filename\n  patterns:\n    artworkdir:\n      - \"[aA]rtwork/\"\n```\n\n#### Pairing\n\nFiletote can specially target related files like lyrics or logs with the same name as\nmusic files (\"paired\" files). This keeps related files together, making your library\neven more organized. When enabled, it will match and move those files having the same\nname as a matching music file. Pairing can be configured to target only certain\nextensions, such as `.lrc`.\n\n**Note:** Pairing takes precedence over other Filetote rules like filename or patterns.\n\n##### Pairing Example Configuration\n\nThis example configuration will grab paired `.lrc` files, along with any artwork files:\n\n```yaml\nfiletote:\n  pairing:\n    enabled: true\n    extensions: \".lrc\"\n  patterns:\n    artworkdir:\n          - \"[aA]rtwork/\"\n```\n\nFiletote can also be configured to _only_ target paired files, which will ignore other\nFiletote configurations such as filename or patterns as described above. The following\nconfiguration would _only_ target `.lrc` files:\n\n```yaml\nfiletote:\n  pairing:\n    enabled: true\n    pairing_only: true\n    extensions: \".lrc\"\n```\n\n##### Pairing Renaming\n\nTo mainting the concept of \"pairs\" after importing, it is strongly encouraged to set\nthe `path` for the paired files to use the media files new name. This will ensure thet\nthe file remains paired even after moving. E.g.:\n\n```yaml\npaths:\n  paired_ext:.lrc: $albumpath/$medianame_new\n```\n\n### Import Operations\n\nThis plugin supports the same operations as beets:\n\n- `copy`\n- `move`\n- `link` (symlink)\n- `harklink`\n- `reflink`\n\nThese options are mutually exclusive, and there are nuances to how beets (and thus this\nplugin) behave when there multiple set. See the [beets import documentation] and [#36]\nfor more details.\n\nReimporting has an additional nuance when copying of linking files that are already in\nthe library, in which files will be moved rather than duplicated. This behavior in\nFiletote is identical to that of beets. See the [beets reimport documentation] for more\ndetails.\n\n[beets import documentation]: https://beets.readthedocs.io/en/stable/reference/config.html#importer-options\n[#36]: https://github.com/gtronset/beets-filetote/pull/36\n[beets reimport documentation]: https://beets.readthedocs.io/en/stable/reference/cli.html#reimporting\n\n### Other CLI Operations\n\nAdditional commands such such as `move`, `modify`, `update`, etc. will also trigger\nFiletote to handle files. These commands typically work with [queries], targeting\nspecific files that match the supplied query. Please note that the operation executed\nby beets for these commands do not use the value set in the config file under `import`,\nthey instead are specified as part of the CLI command.\n\n[queries]: https://beets.readthedocs.io/en/stable/reference/query.html\n\n### Examples of `config.yaml`\n\n```yaml\nplugins: filetote\n\npaths:\n  default: $albumartist/$year - $album/$track - $title\n  singleton: Singletons/$artist - $title\n  ext:.log: $albumpath/$artist - $album\n  ext:.cue: $albumpath/$artist - $album\n  paired_ext:.lrc: $albumpath/$medianame_new\n  filename:cover.jpg: $albumpath/cover\n\nfiletote:\n  extensions: .cue .log .jpg\n  filename: \"cover.jpg\"\n  pairing:\n    enabled: true\n    extensions: \".lrc\"\n  print_ignored: true\n```\n\nOr:\n\n```yaml\nplugins: filetote\n\npaths:\n  default: $albumartist/$year - $album/$track - $title\n  singleton: Singletons/$artist - $title\n\nfiletote:\n  extensions: .cue\n  patterns:\n    artworkdir:\n      - \"[sS]cans/\"\n      - \"[aA]rtwork/\"\n  pairing:\n    enabled: true\n    extensions: \".lrc\"\n  paths:\n    pattern:artworkdir: $albumpath/artwork\n    paired_ext:.lrc: $albumpath/$medianame_old\n    filename:cover.jpg: $albumpath/cover  \n```\n\n## Multi-Disc and Nested Import Directories\n\nbeets imports multi-disc albums as a single unit ([see beets documentation]). By\ndefault, this results in the media importing to a single directory in the library.\nArtifacts and extra files in the initial subdirectories will brought by Filetote to the\ndestination of the file's they're near, resulting in them landing where one would expect.\nBecause of this, the files will also be moved by Filetote to any specified subdirectory\nin the library if the path definition creates \"Disc N\" subfolders\n[as described in the beets documentation].\n\nIn short, artifacts and extra files in these scenarios should simply just move/copy as\nexpected.\n\n[see beets documentation]: https://beets.readthedocs.io/en/stable/faq.html#import-a-multi-disc-album\n[as described in the beets documentation]: https://beets.readthedocs.io/en/stable/faq.html#create-disc-n-directories-for-multi-disc-albums\n\n### Advanced renaming for multi-disc albums\n\nThe value for `$albumpath` is actually based on the path for the Item (music file) the\nlead to the artifact to be moved. Since it's common to store multi-disc albums with\nsubfolders, this means that by default the artifact or extra file in question will also\nbe in a subfolder.\n\nFor macOS and Linux, to achieve a different location (say the media is in\n`Artist/Disc 01` but artifacts are intended to be in `Artist/Extras`), `..` can be used\nto navigate to the parent directory of the `$albumpath` so that the entirety of the\nmedia's path does not have to be recreated. For Windows, the entire media path would\nneed to be recreated as Windows sees `..` as an attempt to create a directory with the\nname `..` within path instead of it being a path component representing the parent.\n\n#### macOS & Linux\n\nThe following example will have the following results on macOS & Linux:\n\n- Music: `~/Music/Artist/2014 - Album/Disc 1/media.mp3`\n- Artifact: `~/Music/Artist/2014 - Album/Extras/example.log`\n\n```yaml\nplugins: filetote\n\npaths:\n  default: $albumartist/$year - $album/$track - $title\n  comp: $albumartist/$year - $album/Disc $disc/$track - $title\n\nfiletote:\n  extensions: .log\n  paths:\n    ext:log: $albumpath/../Extras/$old_filename\n```\n\n#### Windows\n\nThe following example will have the following results on Windows:\n\n- Music: `~/Music/Artist/2014 - Album/Disc 1/media.mp3`\n- Artifact: `~/Music/Artist/2014 - Album/Extras/example.log`\n\n```yaml\nplugins: filetote\n\npaths:\n  default: $albumartist/$year - $album/$track - $title\n  comp: $albumartist/$year - $album/Disc $disc/$track - $title\n\nfiletote:\n  extensions: .log\n  paths:\n    ext:log: $albumartist/$year - $album/Extras/$old_filename\n```\n\n## Why Filetote and Not Other Plugins?\n\nFiletote serves the same core purpose as the [`copyfilertifacts` plugin] and the\n[`extrafiles` plugin], however both have lacked in maintenance over the last few years.\nThere are outstanding bugs in each (though `copyfilertifacts` has seen some recent\nactivity resolving some). In addition, each are lacking in certain features and\nabilities, such as hardlink/reflink support, \"paired\" file handling, and extending\nrenaming options. What's more, significant focus has been provided to Filetote around\nPython3 conventions, linting, and typing in order to promote healthier code and easier\nmaintenance.\n\nFiletote strives to encompass all functionality that _both_ `copyfilertifacts`\nand `extrafiles` provide, and then some!\n\n[`copyfilertifacts` plugin]: https://github.com/adammillerio/beets-copyartifacts\n[`extrafiles` plugin]: https://github.com/Holzhaus/beets-extrafiles\n\n### Migrating from `copyfilertifacts`\n\nFiletote can be configured using nearly identical configuration as `copyfilertifacts`,\nsimply replacing the name of the plugin in its configuration settings. **There is one\nchange that's needed if all extensions are desired, as Filetote does not grab all\nextensions by default (as `copyfilertifacts` does).** To accommodate, simply explicitly\nstate all extension using `.*`:\n\n```yaml\nfiletote:\n  extensions: .*\n```\n\nOtherwise, simply replacing the name in the config section will work. For example:\n\n```yaml\ncopyartifacts:\n  extensions: .cue .log\n```\n\nWould become:\n\n```yaml\nfiletote:\n  extensions: .cue .log\n```\n\nPath definitions can also be specified in the way that `copyfileartifacts` does,\nalongside other path definitions for beets. E.g.:\n\n```yaml\npaths:\n  ext:log: $albumpath/$artist - $album\n```\n\n### Migrating from `extrafiles`\n\nFiletote can be configured using nearly identical configuration as `extrafiles`, simply\nreplacing the name of the plugin in its configuration settings. For example:\n\n```yaml\nextrafiles:\n  patterns:\n    all: \"*.*\"\n```\n\nWould become:\n\n```yaml\nfiletote:\n  patterns:\n    all: \"*.*\"\n```\n\nPath definitions can also be specified in the way that `extrafiles` does, e.g.:\n\n```yaml\nfiletote:\n  patterns:\n    artworkdir:\n      - '[sS]cans/'\n      - '[aA]rtwork/'\n  paths:\n    artworkdir: $albumpath/artwork\n```\n\n## Version Upgrade Instructions\n\nCertain versoins require changes to configurations as upgrades occur. Please see below\nfor specific steps for each version.\n\n### `0.4.0`\n\n#### Default for `extensions` is now `None`\n\nAs of version `0.4.0`, Filetote no longer set the default for `extensions` to `.*`.\nInstead, setting Filetote to collect all extensions needs to be explicitly defined, e.g.:\n\n```yaml\nfiletote:\n  extensions: .*\n```\n\n#### Pairing Config Changes\n\n`pairing` has been converted from a boolean to an object with other like-config. Take\nthe following config:\n\n```yaml\nfiletote:\n  pairing: true\n  pairing_only: false\n```\n\nThese will both now be represented as individual settings within `pairing`:\n\n```yaml\nfiletote:\n  pairing:\n    enabled: true\n    pairing_only: false\n    extensions: \".lrc\"\n```\n\nBoth remain optional and both default to `false`.\n\n## Development\n\nThe development version can be installed with [Poetry], a Python dependency manager\nthat provides dependency isolation, reproducibility, and streamlined packaging to PyPI.\n\nTesting and linting is performed with [Tox].\n\n[Poetry]: https://python-poetry.org/\n[Tox]: https://tox.wiki/\n\nFiletote currently supports Python 3.6+, which aligns with the most recent version of\nbeets ([`v1.6.0`]).\n\n**1. Install Poetry & Tox:**\n\n```sh\npython3 -m pip install poetry tox\n```\n\n**2. Clone the repository and install the plugin:**\n\n```sh\ngit clone https://github.com/gtronset/beets-filetote.git\ncd beets-filetote\npoetry install\n```\n\n**3. Update the config.yaml to utilize the plugin:**\n\n```yaml\npluginpath:\n  - /path/to.../beets-filetote/beetsplug\n```\n\n**4. Run or test with Poetry (and Tox):**\n\nRun beets with the following to locally develop:\n\n```sh\npoetry run beet\n```\n\nTesting can be run with Tox, ex.:\n\n```sh\npoetry run tox -e py312\n```\n\nFor other linting environments, see `tox.ini`. Ex: `black`:\n\n```sh\npoetry run tox -e black\n```\n\n**Docker:**\n\nA Docker Compose configuration is available for running the plugin in a controlled\nenvironment. Running the `docker-compose.yml` file for details.\n\n## Thanks\n\nThis plugin originated as a hard fork from [beets-copyartifacts (copyartifacts3)].\n\nThank you to the original work done by Sami Barakat and Adrian Sampson, along with the\nlarger [beets](http://beets.io) community.\n\nPlease report any issues you may have and feel free to contribute.\n\n[beets-copyartifacts (copyartifacts3)]: https://github.com/adammillerio/beets-copyartifacts\n\n## License\n\nCopyright (c) 2022 Gavin Tronset\n\nLicensed under the [MIT license][license link].\n\n[license image]: https://img.shields.io/badge/License-MIT-blue.svg\n[license link]: https://github.com/gtronset/beets-filetote/blob/main/LICENSE\n[ci image]: https://github.com/gtronset/beets-filetote/actions/workflows/tox.yml/badge.svg\n[ci link]: https://github.com/gtronset/beets-filetote/actions/workflows/tox.yml\n[github image]: https://img.shields.io/github/release/gtronset/beets-filetote.svg\n[github link]: https://github.com/gtronset/beets-filetote/releases\n[pypi_version]: https://img.shields.io/pypi/v/beets-filetote\n[pypi_link]: https://pypi.org/project/beets-filetote/\n[pypi_python_versions]: https://img.shields.io/pypi/pyversions/beets-filetote\n\n[`v1.6.0`]: https://pypi.org/project/beets/1.6.0/\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A beets plugin to copy/moves non-music extra files, attachments, and artifacts during the import process.",
    "version": "0.4.9",
    "project_urls": {
        "Documentation": "https://github.com/gtronset/beets-filetote",
        "Homepage": "https://github.com/gtronset/beets-filetote",
        "Release notes": "https://github.com/gtronset/beets-filetote/releases",
        "Repository": "https://github.com/gtronset/beets-filetote",
        "Source": "https://github.com/gtronset/beets-filetote"
    },
    "split_keywords": [
        "beets",
        " files",
        " artifacts",
        " extra"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8cf6c42207078a7572a83d4f69f21366eb87c0670a065e1a707212e4294a213b",
                "md5": "83e0bc5547750a8416e6fa532adbdef5",
                "sha256": "9d39e9343bb00044a793f6622946a10bf4c8d3ffe343f549afe7e0ff3d7452ea"
            },
            "downloads": -1,
            "filename": "beets_filetote-0.4.9-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "83e0bc5547750a8416e6fa532adbdef5",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.6",
            "size": 20845,
            "upload_time": "2024-04-20T22:20:54",
            "upload_time_iso_8601": "2024-04-20T22:20:54.308965Z",
            "url": "https://files.pythonhosted.org/packages/8c/f6/c42207078a7572a83d4f69f21366eb87c0670a065e1a707212e4294a213b/beets_filetote-0.4.9-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "53f69e9872ece053a627c7df1e781ce4ba9a4bf3f6cf9a12e24498e1c8228125",
                "md5": "0ed0292f5837e0db7a20176332ece347",
                "sha256": "a08f3cd5c4cc823d0f954f123624f1321a6658d3d61cd7dce5aa69371ef2e504"
            },
            "downloads": -1,
            "filename": "beets_filetote-0.4.9.tar.gz",
            "has_sig": false,
            "md5_digest": "0ed0292f5837e0db7a20176332ece347",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.6",
            "size": 26431,
            "upload_time": "2024-04-20T22:20:56",
            "upload_time_iso_8601": "2024-04-20T22:20:56.018334Z",
            "url": "https://files.pythonhosted.org/packages/53/f6/9e9872ece053a627c7df1e781ce4ba9a4bf3f6cf9a12e24498e1c8228125/beets_filetote-0.4.9.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-20 22:20:56",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "gtronset",
    "github_project": "beets-filetote",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "beets-filetote"
}
        
Elapsed time: 4.79126s