music-tag


Namemusic-tag JSON
Version 0.4.3 PyPI version JSON
download
home_pagehttps://github.com/KristoforMaynard/music-tag
SummarySimple interface to edit audio file metadata
upload_time2021-06-05 17:20:23
maintainer
docs_urlNone
authorKristofor Maynard
requires_python
licenseMIT
keywords music metadata id3
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # music-tag

music-tag is a library for editing audio metadata with an interface
that does not depend on the underlying file format. In other words, editing
mp3 files shouldn not be any different than flac, m4a, ... This library is
just a layer on top of [mutagen](https://mutagen.readthedocs.io/en/latest/),
which does all the heavy lifting.

## Formats

The following file formats are actively tested.

- ``aac``
- ``aiff``
- ``dsf``
- ``flac``
- ``m4a``
- ``mp3``
- ``ogg``
- ``opus``
- ``wav``
- ``wv``

## Keys

Metadata is available using a dictionary-like interface with the following keys.
Keys are not case sensitive and can contain arbitrary whitespace, '-', and '_'
characters. In other words, ``Album Artist``, ``album-artist``, and
``album_artist`` are all synonyms for ``albumartist``. Also, ``disk`` is synonymous with ``disc``.

- ``album``
- ``albumartist``
- ``artist``
- ``artwork``
- ``comment``
- ``compilation``
- ``composer``
- ``discnumber``
- ``genre``
- ``lyrics``
- ``totaldiscs``
- ``totaltracks``
- ``tracknumber``
- ``tracktitle``
- ``year``
- ``isrc``
- ``#bitrate`` (read only)
- ``#codec`` (read only)
- ``#length`` (read only)
- ``#channels`` (read only)
- ``#bitspersample`` (read only)
- ``#samplerate`` (read only)

## Examples

### Reading tags

``` python
import music_tag

f = music_tag.load_file("music-tag/sample/440Hz.m4a")

# dict access returns a MetadataItem
title_item = f['title']

# MetadataItems keep track of multi-valued keys
title_item.values  # -> ['440Hz']

# A single value can be extracted
title_item.first  # -> '440Hz'
title_item.value  # -> '440Hz'

# MetadataItems can also be cast to a string
str(title_item)  # -> '440Hz'
```

### Setting tags

``` python
# tags can be set as if the file were a dictionary
f['title'] = '440Hz'

# additional values can be appended to the tags
f.append_tag('title', 'subtitle')
title_item.values  # -> ['440Hz', 'subtitle']
title_item.first  # -> '440Hz'
title_item.value  # -> '440Hz, subtitle'
str(title_item)  # -> '440Hz, subtitle'
```

### Removing tags

``` python
del f['title']
f.remove_tag('title')
```

### Album artwork

Album artwork is wrapped in an object that keeps track of some of the
extra metadata associated with images. Note that some album art functionality
requires the Pillow (modern day PIL) library.

``` python
# get artwork
art = f['artwork']

# Note: `art` is a MetadataItem. Use ``art.value`` if there is
#       only one image embeded in the file. This will raise a
#       ValueError if there is more than one image. You can also
#       use ``art.first``, or iterate through ``art.values``.

art.first.mime  # -> 'image/jpeg'
art.first.width  # -> 1280
art.first.height  # -> 1280
art.first.depth  # -> 24
art.first.data  # -> b'... raw image data ...'

# set artwork
with open('music_tag/test/sample/imgA.jpg', 'rb') as img_in:
    f['artwork'] = img_in.read()
with open('music_tag/test/sample/imgB.jpg', 'rb') as img_in:
    f.append_tag('artwork', img_in.read())

# Make a thumbnail (requires Pillow)
art.first.thumbnail([64, 64])  # -> pillow image
art.first.raw_thumbnail([64, 64])  # -> b'... raw thumbnail data ...'
```

### Saving tags

``` python
# finally, you can bounce the edits to disk
f.save()
```

### Skipping Type Normalization

By default, tags are validated and normalized. For instance, track numbers
and years are return as integers. Some tag formats store everything as strings
to enable things like leading zeros in tracknumbers (i.e., track '01'). I think
this is ugly, but you can use the file object's ``raw`` property if you like
this kind of thing.

``` python
f.raw['tracknumber'] = '01'
f.raw['tracknumber'].value  # -> '01'
```

## Resolvers

Some tags may not exist in a file, but there could be enough information to
discern the correct value. For instance, the ``album artist`` tag is probably
equal to the ``artist`` tag, or ``"Various Artists"`` if the ``compilation``
flag is set. Here are some examples,

``` python
f['album artist'] = 'Brian'
f.resolve('album artist')  # <- 'Brian'
f['artist'] = 'Brian'
del f['album artist']
f['compilation'] = False
f.resolve('album artist')  # <- 'Brian'
f['compilation'] = True
f.resolve('album artist')  # <- 'Various Artists'

del f['compilation']
f['album artist'] = 'Various Artists'
f.resolve('compilation')  # <- True
f['album artist'] = 'Brian'
f.resolve('compilation')  # <- False
```

## Command Line Tool

The music_tag package can be used as a CLI to get / set tags. Here are some
examples,

### Printing Tags

``` bash
# Print tags from all audio files in sample directory
python -m music_tag --print ./sample

# Print specific tags from all audio files in sample directory      
python -m music_tag --print --tags="Title : Album" ./sample

# Write tags from all audio files in sample directory to a csv file
python -m music_tag --to-csv tags.csv ./sample

# Write specific tags from all audio files in sample directory to a csv file
python -m music_tag --tags="Title : Album" --to-csv tags.csv ./sample
```

### Setting Tags
``` bash
# Set a couple tags for multiple files      
python -m music_tag --set "genre:Pop" --set "comment:cli test" \
    ./sample/440Hz.aac ./sample/440Hz.flac

# Write tags from csv file to audio files (assuming file paths in
# the csv file are relative to the sample directory
python -m music_tag --from-csv tags.csv
```
            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/KristoforMaynard/music-tag",
    "name": "music-tag",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "music,metadata,id3",
    "author": "Kristofor Maynard",
    "author_email": "kristofor.maynard@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/fc/f4/ebcdd2fc9bfaf569b795250090e4f4088dc65a5a3e32c53baa9bfc3fc296/music-tag-0.4.3.tar.gz",
    "platform": "",
    "description": "# music-tag\n\nmusic-tag is a library for editing audio metadata with an interface\nthat does not depend on the underlying file format. In other words, editing\nmp3 files shouldn not be any different than flac, m4a, ... This library is\njust a layer on top of [mutagen](https://mutagen.readthedocs.io/en/latest/),\nwhich does all the heavy lifting.\n\n## Formats\n\nThe following file formats are actively tested.\n\n- ``aac``\n- ``aiff``\n- ``dsf``\n- ``flac``\n- ``m4a``\n- ``mp3``\n- ``ogg``\n- ``opus``\n- ``wav``\n- ``wv``\n\n## Keys\n\nMetadata is available using a dictionary-like interface with the following keys.\nKeys are not case sensitive and can contain arbitrary whitespace, '-', and '_'\ncharacters. In other words, ``Album Artist``, ``album-artist``, and\n``album_artist`` are all synonyms for ``albumartist``. Also, ``disk`` is synonymous with ``disc``.\n\n- ``album``\n- ``albumartist``\n- ``artist``\n- ``artwork``\n- ``comment``\n- ``compilation``\n- ``composer``\n- ``discnumber``\n- ``genre``\n- ``lyrics``\n- ``totaldiscs``\n- ``totaltracks``\n- ``tracknumber``\n- ``tracktitle``\n- ``year``\n- ``isrc``\n- ``#bitrate`` (read only)\n- ``#codec`` (read only)\n- ``#length`` (read only)\n- ``#channels`` (read only)\n- ``#bitspersample`` (read only)\n- ``#samplerate`` (read only)\n\n## Examples\n\n### Reading tags\n\n``` python\nimport music_tag\n\nf = music_tag.load_file(\"music-tag/sample/440Hz.m4a\")\n\n# dict access returns a MetadataItem\ntitle_item = f['title']\n\n# MetadataItems keep track of multi-valued keys\ntitle_item.values  # -> ['440Hz']\n\n# A single value can be extracted\ntitle_item.first  # -> '440Hz'\ntitle_item.value  # -> '440Hz'\n\n# MetadataItems can also be cast to a string\nstr(title_item)  # -> '440Hz'\n```\n\n### Setting tags\n\n``` python\n# tags can be set as if the file were a dictionary\nf['title'] = '440Hz'\n\n# additional values can be appended to the tags\nf.append_tag('title', 'subtitle')\ntitle_item.values  # -> ['440Hz', 'subtitle']\ntitle_item.first  # -> '440Hz'\ntitle_item.value  # -> '440Hz, subtitle'\nstr(title_item)  # -> '440Hz, subtitle'\n```\n\n### Removing tags\n\n``` python\ndel f['title']\nf.remove_tag('title')\n```\n\n### Album artwork\n\nAlbum artwork is wrapped in an object that keeps track of some of the\nextra metadata associated with images. Note that some album art functionality\nrequires the Pillow (modern day PIL) library.\n\n``` python\n# get artwork\nart = f['artwork']\n\n# Note: `art` is a MetadataItem. Use ``art.value`` if there is\n#       only one image embeded in the file. This will raise a\n#       ValueError if there is more than one image. You can also\n#       use ``art.first``, or iterate through ``art.values``.\n\nart.first.mime  # -> 'image/jpeg'\nart.first.width  # -> 1280\nart.first.height  # -> 1280\nart.first.depth  # -> 24\nart.first.data  # -> b'... raw image data ...'\n\n# set artwork\nwith open('music_tag/test/sample/imgA.jpg', 'rb') as img_in:\n    f['artwork'] = img_in.read()\nwith open('music_tag/test/sample/imgB.jpg', 'rb') as img_in:\n    f.append_tag('artwork', img_in.read())\n\n# Make a thumbnail (requires Pillow)\nart.first.thumbnail([64, 64])  # -> pillow image\nart.first.raw_thumbnail([64, 64])  # -> b'... raw thumbnail data ...'\n```\n\n### Saving tags\n\n``` python\n# finally, you can bounce the edits to disk\nf.save()\n```\n\n### Skipping Type Normalization\n\nBy default, tags are validated and normalized. For instance, track numbers\nand years are return as integers. Some tag formats store everything as strings\nto enable things like leading zeros in tracknumbers (i.e., track '01'). I think\nthis is ugly, but you can use the file object's ``raw`` property if you like\nthis kind of thing.\n\n``` python\nf.raw['tracknumber'] = '01'\nf.raw['tracknumber'].value  # -> '01'\n```\n\n## Resolvers\n\nSome tags may not exist in a file, but there could be enough information to\ndiscern the correct value. For instance, the ``album artist`` tag is probably\nequal to the ``artist`` tag, or ``\"Various Artists\"`` if the ``compilation``\nflag is set. Here are some examples,\n\n``` python\nf['album artist'] = 'Brian'\nf.resolve('album artist')  # <- 'Brian'\nf['artist'] = 'Brian'\ndel f['album artist']\nf['compilation'] = False\nf.resolve('album artist')  # <- 'Brian'\nf['compilation'] = True\nf.resolve('album artist')  # <- 'Various Artists'\n\ndel f['compilation']\nf['album artist'] = 'Various Artists'\nf.resolve('compilation')  # <- True\nf['album artist'] = 'Brian'\nf.resolve('compilation')  # <- False\n```\n\n## Command Line Tool\n\nThe music_tag package can be used as a CLI to get / set tags. Here are some\nexamples,\n\n### Printing Tags\n\n``` bash\n# Print tags from all audio files in sample directory\npython -m music_tag --print ./sample\n\n# Print specific tags from all audio files in sample directory      \npython -m music_tag --print --tags=\"Title : Album\" ./sample\n\n# Write tags from all audio files in sample directory to a csv file\npython -m music_tag --to-csv tags.csv ./sample\n\n# Write specific tags from all audio files in sample directory to a csv file\npython -m music_tag --tags=\"Title : Album\" --to-csv tags.csv ./sample\n```\n\n### Setting Tags\n``` bash\n# Set a couple tags for multiple files      \npython -m music_tag --set \"genre:Pop\" --set \"comment:cli test\" \\\n    ./sample/440Hz.aac ./sample/440Hz.flac\n\n# Write tags from csv file to audio files (assuming file paths in\n# the csv file are relative to the sample directory\npython -m music_tag --from-csv tags.csv\n```",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Simple interface to edit audio file metadata",
    "version": "0.4.3",
    "project_urls": {
        "Download": "https://github.com/KristoforMaynard/music-tag/archive/0.4.3.zip",
        "Homepage": "https://github.com/KristoforMaynard/music-tag"
    },
    "split_keywords": [
        "music",
        "metadata",
        "id3"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "fcf4ebcdd2fc9bfaf569b795250090e4f4088dc65a5a3e32c53baa9bfc3fc296",
                "md5": "ace5be9fe210478a0f89ff62fa62d179",
                "sha256": "0aab6e6eeda8df0f5316ec2d2190bd74561b7e03562ab091ce8d5687cdbcfff6"
            },
            "downloads": -1,
            "filename": "music-tag-0.4.3.tar.gz",
            "has_sig": false,
            "md5_digest": "ace5be9fe210478a0f89ff62fa62d179",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 23153,
            "upload_time": "2021-06-05T17:20:23",
            "upload_time_iso_8601": "2021-06-05T17:20:23.552628Z",
            "url": "https://files.pythonhosted.org/packages/fc/f4/ebcdd2fc9bfaf569b795250090e4f4088dc65a5a3e32c53baa9bfc3fc296/music-tag-0.4.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2021-06-05 17:20:23",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "KristoforMaynard",
    "github_project": "music-tag",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "music-tag"
}
        
Elapsed time: 0.10479s