Skip to content

Commit

Permalink
Add skipping flags
Browse files Browse the repository at this point in the history
  • Loading branch information
infojunkie committed Jan 12, 2024
1 parent 9e77305 commit 94e941e
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 35 deletions.
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,37 @@ A rudimentary audio tagger based on Discogs metadata.
# Installation
- Install [`poetry`](https://python-poetry.org/docs/#installation)
- `poetry install && poetry build && pip install .`
- `discogs-tag <discogs-release-id> [--dir /path/to/audio/files] [--dry]`

# Usage
```shell
NAME
discogs-tag - Tag the audio files with the given Discogs release.

SYNOPSIS
discogs-tag RELEASE <flags>

DESCRIPTION
Tag the audio files with the given Discogs release.

POSITIONAL ARGUMENTS
RELEASE

FLAGS
--dir=DIR
Default: './'
--dry=DRY
Default: False
-i, --ignore=IGNORE
Default: False
--skip_artist=SKIP_ARTIST
Default: False
--skip_title=SKIP_TITLE
Default: False
--skip_composer=SKIP_COMPOSER
Default: False
--skip_position=SKIP_POSITION
Default: False

NOTES
You can also use flags syntax for POSITIONAL ARGUMENTS
```
77 changes: 47 additions & 30 deletions src/discogs_tag/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,18 @@
import re
from discogs_tag import __NAME__, __VERSION__

def tag(release, dir = './', dry = False, ignore = False):
"""Tag the audio files in dir with the given Discogs release."""
def tag(
release,
dir='./',
dry=False,
ignore=False,
skip_artist=False,
skip_title=False,
skip_composer=False,
skip_position=False
):
"""Tag the audio files with the given Discogs release."""
options = locals()
request = urllib.request.Request(f'https://api.discogs.com/releases/{release}', headers = {
'User-Agent': f'{__NAME__} {__VERSION__}'
})
Expand All @@ -20,49 +30,56 @@ def tag(release, dir = './', dry = False, ignore = False):
glob.glob(os.path.join(glob.escape(dir), '**', '*.flac'), recursive=True) +
glob.glob(os.path.join(glob.escape(dir), '**', '*.mp3'), recursive=True)
)
apply_metadata(data, files, dry, ignore)
apply_metadata(data, files, options)

def apply_metadata(data, files, dry, ignore):
def apply_metadata(data, files, options):
tracks = list(filter(lambda t: t['type_'] == 'track', data['tracklist']))
if (len(files) != len(tracks)):
if (not ignore):
raise Exception(f'Expecting {len(tracks)} files but found {len(files)}. Aborting.')
else:
if len(files) != len(tracks):
if options['ignore']:
print(f'Expecting {len(tracks)} files but found {len(files)}. Ignoring.', file=sys.stderr)
else:
raise Exception(f'Expecting {len(tracks)} files but found {len(files)}. Aborting.')

for n, track in enumerate(tracks):
try:
audio = mutagen.File(files[n], easy=True)
merge_metadata(track, audio)
if (dry):
merge_metadata(track, audio, options)
if options['dry']:
pprint(audio)
else:
audio.save()
except Exception as e:
if (not ignore):
raise e
else:
if options['ignore']:
print(e, file=sys.stderr)
else:
raise e

if (not dry):
if not options['dry']:
print(f'Processed {len(files)} audio files.')

def merge_metadata(track, audio):
audio['title'] = track['title']
artists = []
if 'artists' in track:
artists += [artist_name(artist) for artist in track['artists']]
if 'extraartists' in track:
artists += [artist_name(artist) for artist in filter(lambda a: a['role'].casefold() != 'Written-By'.casefold(), track['extraartists'])]
if (artists):
audio['artist'] = ', '.join(artists)
positions = track['position'].split('-')
audio['tracknumber'] = positions[-1]
if (len(positions) > 1):
audio['discnumber'] = positions[0]
composers = [artist_name(composer) for composer in filter(lambda a: a['role'].casefold() == 'Written-By'.casefold(), track['extraartists'])] if 'extraartists' in track else None
if (composers):
audio['composer'] = ', '.join(composers)
def merge_metadata(track, audio, options):
if not options['skip_title']:
audio['title'] = track['title']

if not options['skip_artist']:
artists = []
if 'artists' in track:
artists += [artist_name(artist) for artist in track['artists']]
if 'extraartists' in track:
artists += [artist_name(artist) for artist in filter(lambda a: a['role'].casefold() != 'Written-By'.casefold(), track['extraartists'])]
if artists:
audio['artist'] = ', '.join(artists)

if not options['skip_composer']:
composers = [artist_name(composer) for composer in filter(lambda a: a['role'].casefold() == 'Written-By'.casefold(), track['extraartists'])] if 'extraartists' in track else None
if composers:
audio['composer'] = ', '.join(composers)

if not options['skip_position']:
positions = track['position'].split('-')
audio['tracknumber'] = positions[-1]
if len(positions) > 1:
audio['discnumber'] = positions[0]

def artist_name(artist):
name = None
Expand Down
13 changes: 9 additions & 4 deletions tests/test_discogs_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ def test_merge_metadata():
'role': 'Written-By',
'name': 'Composer'
}]
}, audio)
}, audio, {
'skip_artist': False,
'skip_composer': False,
'skip_title': False,
'skip_position': False,
})
assert audio['title'] == 'Title'
assert audio['artist'] == 'Artist 1, Artist 2, Artist 3, Guitarist'
assert audio['discnumber'] == '1'
Expand All @@ -34,6 +39,6 @@ def test_apply_metadata():
data = json.load(release)

# Test that files must match API results.
with pytest.raises(Exception) as e1:
apply_metadata(data, [], False, False)
assert "Expecting 28 files" in str(e1.value)
with pytest.raises(Exception) as error:
apply_metadata(data, [], { 'dry': False, 'ignore': False })
assert "Expecting 28 files" in str(error.value)

0 comments on commit 94e941e

Please sign in to comment.