audio: Move tag helpers to mopidy.audio.tags
This commit is contained in:
parent
f0c7d25db6
commit
31c894030d
@ -12,7 +12,7 @@ Gst.is_initialized() or Gst.init()
|
||||
import pykka
|
||||
|
||||
from mopidy import exceptions
|
||||
from mopidy.audio import utils
|
||||
from mopidy.audio import tags as tags_lib, utils
|
||||
from mopidy.audio.constants import PlaybackState
|
||||
from mopidy.audio.listener import AudioListener
|
||||
from mopidy.internal import deprecation, process
|
||||
@ -325,7 +325,7 @@ class _Handler(object):
|
||||
gst_logger.debug('Got ASYNC_DONE bus message.')
|
||||
|
||||
def on_tag(self, taglist):
|
||||
tags = utils.convert_taglist(taglist)
|
||||
tags = tags_lib.convert_taglist(taglist)
|
||||
gst_logger.debug('Got TAG bus message: tags=%r', dict(tags))
|
||||
self._audio._tags.update(tags)
|
||||
logger.debug('Audio event: tags_changed(tags=%r)', tags.keys())
|
||||
|
||||
@ -10,7 +10,7 @@ from gi.repository import Gst, GstPbutils
|
||||
Gst.is_initialized() or Gst.init()
|
||||
|
||||
from mopidy import exceptions
|
||||
from mopidy.audio import utils
|
||||
from mopidy.audio import tags as tags_lib, utils
|
||||
from mopidy.internal import encoding
|
||||
|
||||
# GST_ELEMENT_FACTORY_LIST:
|
||||
@ -214,7 +214,7 @@ def _process(pipeline, timeout_ms):
|
||||
elif message.type == Gst.MessageType.TAG:
|
||||
taglist = message.parse_tag()
|
||||
# Note that this will only keep the last tag.
|
||||
tags.update(utils.convert_taglist(taglist))
|
||||
tags.update(tags_lib.convert_taglist(taglist))
|
||||
|
||||
now = int(time.time() * 1000)
|
||||
timeout -= now - previous
|
||||
|
||||
132
mopidy/audio/tags.py
Normal file
132
mopidy/audio/tags.py
Normal file
@ -0,0 +1,132 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import collections
|
||||
import logging
|
||||
import numbers
|
||||
|
||||
import gi
|
||||
gi.require_version('Gst', '1.0')
|
||||
from gi.repository import Gst
|
||||
Gst.is_initialized() or Gst.init()
|
||||
|
||||
from mopidy import compat
|
||||
from mopidy.models import Album, Artist, Track
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
TRACE = logging.getLevelName('TRACE')
|
||||
|
||||
|
||||
def convert_taglist(taglist):
|
||||
"""Convert a :class:`Gst.TagList` to plain Python types.
|
||||
|
||||
Knows how to convert:
|
||||
|
||||
- Dates
|
||||
- Buffers
|
||||
- Numbers
|
||||
- Strings
|
||||
- Booleans
|
||||
|
||||
Unknown types will be ignored and trace logged. Tag keys are all strings
|
||||
defined as part GStreamer under GstTagList_.
|
||||
|
||||
.. _GstTagList: https://developer.gnome.org/gstreamer/stable/\
|
||||
gstreamer-GstTagList.html
|
||||
|
||||
:param taglist: A GStreamer taglist to be converted.
|
||||
:type taglist: :class:`Gst.TagList`
|
||||
:rtype: dictionary of tag keys with a list of values.
|
||||
"""
|
||||
result = collections.defaultdict(list)
|
||||
|
||||
for n in range(taglist.n_tags()):
|
||||
tag = taglist.nth_tag_name(n)
|
||||
|
||||
for i in range(taglist.get_tag_size(tag)):
|
||||
value = taglist.get_value_index(tag, i)
|
||||
|
||||
if isinstance(value, Gst.DateTime):
|
||||
result[tag].append(value.to_iso8601_string())
|
||||
if isinstance(value, (compat.string_types, bool, numbers.Number)):
|
||||
result[tag].append(value)
|
||||
else:
|
||||
logger.log(
|
||||
TRACE, 'Ignoring unknown tag data: %r = %r', tag, value)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# TODO: split based on "stream" and "track" based conversion? i.e. handle data
|
||||
# from radios in it's own helper instead?
|
||||
def convert_tags_to_track(tags):
|
||||
"""Convert our normalized tags to a track.
|
||||
|
||||
:param tags: dictionary of tag keys with a list of values
|
||||
:type tags: :class:`dict`
|
||||
:rtype: :class:`mopidy.models.Track`
|
||||
"""
|
||||
album_kwargs = {}
|
||||
track_kwargs = {}
|
||||
|
||||
track_kwargs['composers'] = _artists(tags, Gst.TAG_COMPOSER)
|
||||
track_kwargs['performers'] = _artists(tags, Gst.TAG_PERFORMER)
|
||||
track_kwargs['artists'] = _artists(tags, Gst.TAG_ARTIST,
|
||||
'musicbrainz-artistid',
|
||||
'musicbrainz-sortname')
|
||||
album_kwargs['artists'] = _artists(
|
||||
tags, Gst.TAG_ALBUM_ARTIST, 'musicbrainz-albumartistid')
|
||||
|
||||
track_kwargs['genre'] = '; '.join(tags.get(Gst.TAG_GENRE, []))
|
||||
track_kwargs['name'] = '; '.join(tags.get(Gst.TAG_TITLE, []))
|
||||
if not track_kwargs['name']:
|
||||
track_kwargs['name'] = '; '.join(tags.get(Gst.TAG_ORGANIZATION, []))
|
||||
|
||||
track_kwargs['comment'] = '; '.join(tags.get('comment', []))
|
||||
if not track_kwargs['comment']:
|
||||
track_kwargs['comment'] = '; '.join(tags.get(Gst.TAG_LOCATION, []))
|
||||
if not track_kwargs['comment']:
|
||||
track_kwargs['comment'] = '; '.join(tags.get(Gst.TAG_COPYRIGHT, []))
|
||||
|
||||
track_kwargs['track_no'] = tags.get(Gst.TAG_TRACK_NUMBER, [None])[0]
|
||||
track_kwargs['disc_no'] = tags.get(Gst.TAG_ALBUM_VOLUME_NUMBER, [None])[0]
|
||||
track_kwargs['bitrate'] = tags.get(Gst.TAG_BITRATE, [None])[0]
|
||||
track_kwargs['musicbrainz_id'] = tags.get('musicbrainz-trackid', [None])[0]
|
||||
|
||||
album_kwargs['name'] = tags.get(Gst.TAG_ALBUM, [None])[0]
|
||||
album_kwargs['num_tracks'] = tags.get(Gst.TAG_TRACK_COUNT, [None])[0]
|
||||
album_kwargs['num_discs'] = tags.get(Gst.TAG_ALBUM_VOLUME_COUNT, [None])[0]
|
||||
album_kwargs['musicbrainz_id'] = tags.get('musicbrainz-albumid', [None])[0]
|
||||
|
||||
if tags.get(Gst.TAG_DATE) and tags.get(Gst.TAG_DATE)[0]:
|
||||
track_kwargs['date'] = tags[Gst.TAG_DATE][0].isoformat()
|
||||
|
||||
# Clear out any empty values we found
|
||||
track_kwargs = {k: v for k, v in track_kwargs.items() if v}
|
||||
album_kwargs = {k: v for k, v in album_kwargs.items() if v}
|
||||
|
||||
# Only bother with album if we have a name to show.
|
||||
if album_kwargs.get('name'):
|
||||
track_kwargs['album'] = Album(**album_kwargs)
|
||||
|
||||
return Track(**track_kwargs)
|
||||
|
||||
|
||||
def _artists(
|
||||
tags, artist_name, artist_id=None, artist_sortname=None):
|
||||
|
||||
# Name missing, don't set artist
|
||||
if not tags.get(artist_name):
|
||||
return None
|
||||
# One artist name and either id or sortname, include all available fields
|
||||
if len(tags[artist_name]) == 1 and \
|
||||
(artist_id in tags or artist_sortname in tags):
|
||||
attrs = {'name': tags[artist_name][0]}
|
||||
if artist_id in tags:
|
||||
attrs['musicbrainz_id'] = tags[artist_id][0]
|
||||
if artist_sortname in tags:
|
||||
attrs['sortname'] = tags[artist_sortname][0]
|
||||
return [Artist(**attrs)]
|
||||
|
||||
# Multiple artist, provide artists with name only to avoid ambiguity.
|
||||
return [Artist(name=name) for name in tags[artist_name]]
|
||||
@ -1,18 +1,10 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import collections
|
||||
import logging
|
||||
import numbers
|
||||
|
||||
import gi
|
||||
gi.require_version('Gst', '1.0')
|
||||
from gi.repository import Gst
|
||||
|
||||
from mopidy import compat, httpclient
|
||||
from mopidy.models import Album, Artist, Track
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
TRACE = logging.getLevelName('TRACE')
|
||||
from mopidy import httpclient
|
||||
|
||||
|
||||
def calculate_duration(num_samples, sample_rate):
|
||||
@ -68,79 +60,6 @@ def supported_uri_schemes(uri_schemes):
|
||||
return supported_schemes
|
||||
|
||||
|
||||
def _artists(tags, artist_name, artist_id=None, artist_sortname=None):
|
||||
# Name missing, don't set artist
|
||||
if not tags.get(artist_name):
|
||||
return None
|
||||
# One artist name and either id or sortname, include all available fields
|
||||
if len(tags[artist_name]) == 1 and \
|
||||
(artist_id in tags or artist_sortname in tags):
|
||||
attrs = {'name': tags[artist_name][0]}
|
||||
if artist_id in tags:
|
||||
attrs['musicbrainz_id'] = tags[artist_id][0]
|
||||
if artist_sortname in tags:
|
||||
attrs['sortname'] = tags[artist_sortname][0]
|
||||
return [Artist(**attrs)]
|
||||
|
||||
# Multiple artist, provide artists with name only to avoid ambiguity.
|
||||
return [Artist(name=name) for name in tags[artist_name]]
|
||||
|
||||
|
||||
# TODO: split based on "stream" and "track" based conversion? i.e. handle data
|
||||
# from radios in it's own helper instead?
|
||||
def convert_tags_to_track(tags):
|
||||
"""Convert our normalized tags to a track.
|
||||
|
||||
:param tags: dictionary of tag keys with a list of values
|
||||
:type tags: :class:`dict`
|
||||
:rtype: :class:`mopidy.models.Track`
|
||||
"""
|
||||
album_kwargs = {}
|
||||
track_kwargs = {}
|
||||
|
||||
track_kwargs['composers'] = _artists(tags, Gst.TAG_COMPOSER)
|
||||
track_kwargs['performers'] = _artists(tags, Gst.TAG_PERFORMER)
|
||||
track_kwargs['artists'] = _artists(tags, Gst.TAG_ARTIST,
|
||||
'musicbrainz-artistid',
|
||||
'musicbrainz-sortname')
|
||||
album_kwargs['artists'] = _artists(
|
||||
tags, Gst.TAG_ALBUM_ARTIST, 'musicbrainz-albumartistid')
|
||||
|
||||
track_kwargs['genre'] = '; '.join(tags.get(Gst.TAG_GENRE, []))
|
||||
track_kwargs['name'] = '; '.join(tags.get(Gst.TAG_TITLE, []))
|
||||
if not track_kwargs['name']:
|
||||
track_kwargs['name'] = '; '.join(tags.get(Gst.TAG_ORGANIZATION, []))
|
||||
|
||||
track_kwargs['comment'] = '; '.join(tags.get('comment', []))
|
||||
if not track_kwargs['comment']:
|
||||
track_kwargs['comment'] = '; '.join(tags.get(Gst.TAG_LOCATION, []))
|
||||
if not track_kwargs['comment']:
|
||||
track_kwargs['comment'] = '; '.join(tags.get(Gst.TAG_COPYRIGHT, []))
|
||||
|
||||
track_kwargs['track_no'] = tags.get(Gst.TAG_TRACK_NUMBER, [None])[0]
|
||||
track_kwargs['disc_no'] = tags.get(Gst.TAG_ALBUM_VOLUME_NUMBER, [None])[0]
|
||||
track_kwargs['bitrate'] = tags.get(Gst.TAG_BITRATE, [None])[0]
|
||||
track_kwargs['musicbrainz_id'] = tags.get('musicbrainz-trackid', [None])[0]
|
||||
|
||||
album_kwargs['name'] = tags.get(Gst.TAG_ALBUM, [None])[0]
|
||||
album_kwargs['num_tracks'] = tags.get(Gst.TAG_TRACK_COUNT, [None])[0]
|
||||
album_kwargs['num_discs'] = tags.get(Gst.TAG_ALBUM_VOLUME_COUNT, [None])[0]
|
||||
album_kwargs['musicbrainz_id'] = tags.get('musicbrainz-albumid', [None])[0]
|
||||
|
||||
if tags.get(Gst.TAG_DATE) and tags.get(Gst.TAG_DATE)[0]:
|
||||
track_kwargs['date'] = tags[Gst.TAG_DATE][0].isoformat()
|
||||
|
||||
# Clear out any empty values we found
|
||||
track_kwargs = {k: v for k, v in track_kwargs.items() if v}
|
||||
album_kwargs = {k: v for k, v in album_kwargs.items() if v}
|
||||
|
||||
# Only bother with album if we have a name to show.
|
||||
if album_kwargs.get('name'):
|
||||
track_kwargs['album'] = Album(**album_kwargs)
|
||||
|
||||
return Track(**track_kwargs)
|
||||
|
||||
|
||||
def setup_proxy(element, config):
|
||||
"""Configure a GStreamer element with proxy settings.
|
||||
|
||||
@ -157,46 +76,6 @@ def setup_proxy(element, config):
|
||||
element.set_property('proxy-pw', config.get('password'))
|
||||
|
||||
|
||||
def convert_taglist(taglist):
|
||||
"""Convert a :class:`Gst.TagList` to plain Python types.
|
||||
|
||||
Knows how to convert:
|
||||
|
||||
- Dates
|
||||
- Buffers
|
||||
- Numbers
|
||||
- Strings
|
||||
- Booleans
|
||||
|
||||
Unknown types will be ignored and debug logged. Tag keys are all strings
|
||||
defined as part GStreamer under GstTagList_.
|
||||
|
||||
.. _GstTagList: https://developer.gnome.org/gstreamer/stable/\
|
||||
gstreamer-GstTagList.html
|
||||
|
||||
:param taglist: A GStreamer taglist to be converted.
|
||||
:type taglist: :class:`Gst.TagList`
|
||||
:rtype: dictionary of tag keys with a list of values.
|
||||
"""
|
||||
result = collections.defaultdict(list)
|
||||
|
||||
for n in range(taglist.n_tags()):
|
||||
tag = taglist.nth_tag_name(n)
|
||||
|
||||
for i in range(taglist.get_tag_size(tag)):
|
||||
value = taglist.get_value_index(tag, i)
|
||||
|
||||
if isinstance(value, Gst.DateTime):
|
||||
result[tag].append(value.to_iso8601_string())
|
||||
if isinstance(value, (compat.string_types, bool, numbers.Number)):
|
||||
result[tag].append(value)
|
||||
else:
|
||||
logger.log(
|
||||
TRACE, 'Ignoring unknown tag data: %r = %r', tag, value)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class Signals(object):
|
||||
|
||||
"""Helper for tracking gobject signal registrations"""
|
||||
|
||||
@ -7,7 +7,7 @@ import sys
|
||||
import urllib2
|
||||
|
||||
from mopidy import backend, exceptions, models
|
||||
from mopidy.audio import scan, utils
|
||||
from mopidy.audio import scan, tags
|
||||
from mopidy.internal import path
|
||||
|
||||
|
||||
@ -83,7 +83,7 @@ class FileLibraryProvider(backend.LibraryProvider):
|
||||
|
||||
try:
|
||||
result = self._scanner.scan(uri)
|
||||
track = utils.convert_tags_to_track(result.tags).copy(
|
||||
track = tags.convert_tags_to_track(result.tags).copy(
|
||||
uri=uri, length=result.duration)
|
||||
except exceptions.ScannerError as e:
|
||||
logger.warning('Failed looking up %s: %s', uri, e)
|
||||
|
||||
@ -6,7 +6,7 @@ import os
|
||||
import time
|
||||
|
||||
from mopidy import commands, compat, exceptions
|
||||
from mopidy.audio import scan, utils
|
||||
from mopidy.audio import scan, tags
|
||||
from mopidy.internal import path
|
||||
from mopidy.local import translator
|
||||
|
||||
@ -140,18 +140,18 @@ class ScanCommand(commands.Command):
|
||||
relpath = translator.local_track_uri_to_path(uri, media_dir)
|
||||
file_uri = path.path_to_uri(os.path.join(media_dir, relpath))
|
||||
result = scanner.scan(file_uri)
|
||||
tags, duration = result.tags, result.duration
|
||||
if not result.playable:
|
||||
logger.warning('Failed %s: No audio found in file.', uri)
|
||||
elif duration < MIN_DURATION_MS:
|
||||
elif result.duration < MIN_DURATION_MS:
|
||||
logger.warning('Failed %s: Track shorter than %dms',
|
||||
uri, MIN_DURATION_MS)
|
||||
else:
|
||||
mtime = file_mtimes.get(os.path.join(media_dir, relpath))
|
||||
track = utils.convert_tags_to_track(tags).replace(
|
||||
uri=uri, length=duration, last_modified=mtime)
|
||||
track = tags.convert_tags_to_track(result.tags).replace(
|
||||
uri=uri, length=result.duration, last_modified=mtime)
|
||||
if library.add_supports_tags_and_duration:
|
||||
library.add(track, tags=tags, duration=duration)
|
||||
library.add(
|
||||
track, tags=result.tags, duration=result.duration)
|
||||
else:
|
||||
library.add(track)
|
||||
logger.debug('Added %s', track.uri)
|
||||
|
||||
@ -8,7 +8,7 @@ import time
|
||||
import pykka
|
||||
|
||||
from mopidy import audio as audio_lib, backend, exceptions, stream
|
||||
from mopidy.audio import scan, utils
|
||||
from mopidy.audio import scan, tags
|
||||
from mopidy.compat import urllib
|
||||
from mopidy.internal import http, playlists
|
||||
from mopidy.models import Track
|
||||
@ -60,7 +60,7 @@ class StreamLibraryProvider(backend.LibraryProvider):
|
||||
|
||||
try:
|
||||
result = self._scanner.scan(uri)
|
||||
track = utils.convert_tags_to_track(result.tags).replace(
|
||||
track = tags.convert_tags_to_track(result.tags).replace(
|
||||
uri=uri, length=result.duration)
|
||||
except exceptions.ScannerError as e:
|
||||
logger.warning('Problem looking up %s: %s', uri, e)
|
||||
|
||||
261
tests/audio/test_tags.py
Normal file
261
tests/audio/test_tags.py
Normal file
@ -0,0 +1,261 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import datetime
|
||||
import unittest
|
||||
|
||||
from mopidy.audio import tags
|
||||
from mopidy.models import Album, Artist, Track
|
||||
|
||||
|
||||
# TODO: keep ids without name?
|
||||
# TODO: current test is trying to test everything at once with a complete tags
|
||||
# set, instead we might want to try with a minimal one making testing easier.
|
||||
class TagsToTrackTest(unittest.TestCase):
|
||||
|
||||
def setUp(self): # noqa: N802
|
||||
self.tags = {
|
||||
'album': ['album'],
|
||||
'track-number': [1],
|
||||
'artist': ['artist'],
|
||||
'composer': ['composer'],
|
||||
'performer': ['performer'],
|
||||
'album-artist': ['albumartist'],
|
||||
'title': ['track'],
|
||||
'track-count': [2],
|
||||
'album-disc-number': [2],
|
||||
'album-disc-count': [3],
|
||||
'date': [datetime.date(2006, 1, 1,)],
|
||||
'container-format': ['ID3 tag'],
|
||||
'genre': ['genre'],
|
||||
'comment': ['comment'],
|
||||
'musicbrainz-trackid': ['trackid'],
|
||||
'musicbrainz-albumid': ['albumid'],
|
||||
'musicbrainz-artistid': ['artistid'],
|
||||
'musicbrainz-sortname': ['sortname'],
|
||||
'musicbrainz-albumartistid': ['albumartistid'],
|
||||
'bitrate': [1000],
|
||||
}
|
||||
|
||||
artist = Artist(name='artist', musicbrainz_id='artistid',
|
||||
sortname='sortname')
|
||||
composer = Artist(name='composer')
|
||||
performer = Artist(name='performer')
|
||||
albumartist = Artist(name='albumartist',
|
||||
musicbrainz_id='albumartistid')
|
||||
|
||||
album = Album(name='album', num_tracks=2, num_discs=3,
|
||||
musicbrainz_id='albumid', artists=[albumartist])
|
||||
|
||||
self.track = Track(name='track', date='2006-01-01',
|
||||
genre='genre', track_no=1, disc_no=2,
|
||||
comment='comment', musicbrainz_id='trackid',
|
||||
album=album, bitrate=1000, artists=[artist],
|
||||
composers=[composer], performers=[performer])
|
||||
|
||||
def check(self, expected):
|
||||
actual = tags.convert_tags_to_track(self.tags)
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_track(self):
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_no(self):
|
||||
del self.tags['track-number']
|
||||
self.check(self.track.replace(track_no=None))
|
||||
|
||||
def test_multiple_track_no(self):
|
||||
self.tags['track-number'].append(9)
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_disc_no(self):
|
||||
del self.tags['album-disc-number']
|
||||
self.check(self.track.replace(disc_no=None))
|
||||
|
||||
def test_multiple_track_disc_no(self):
|
||||
self.tags['album-disc-number'].append(9)
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_name(self):
|
||||
del self.tags['title']
|
||||
self.check(self.track.replace(name=None))
|
||||
|
||||
def test_multiple_track_name(self):
|
||||
self.tags['title'] = ['name1', 'name2']
|
||||
self.check(self.track.replace(name='name1; name2'))
|
||||
|
||||
def test_missing_track_musicbrainz_id(self):
|
||||
del self.tags['musicbrainz-trackid']
|
||||
self.check(self.track.replace(musicbrainz_id=None))
|
||||
|
||||
def test_multiple_track_musicbrainz_id(self):
|
||||
self.tags['musicbrainz-trackid'].append('id')
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_bitrate(self):
|
||||
del self.tags['bitrate']
|
||||
self.check(self.track.replace(bitrate=None))
|
||||
|
||||
def test_multiple_track_bitrate(self):
|
||||
self.tags['bitrate'].append(1234)
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_genre(self):
|
||||
del self.tags['genre']
|
||||
self.check(self.track.replace(genre=None))
|
||||
|
||||
def test_multiple_track_genre(self):
|
||||
self.tags['genre'] = ['genre1', 'genre2']
|
||||
self.check(self.track.replace(genre='genre1; genre2'))
|
||||
|
||||
def test_missing_track_date(self):
|
||||
del self.tags['date']
|
||||
self.check(self.track.replace(date=None))
|
||||
|
||||
def test_multiple_track_date(self):
|
||||
self.tags['date'].append(datetime.date(2030, 1, 1))
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_comment(self):
|
||||
del self.tags['comment']
|
||||
self.check(self.track.replace(comment=None))
|
||||
|
||||
def test_multiple_track_comment(self):
|
||||
self.tags['comment'] = ['comment1', 'comment2']
|
||||
self.check(self.track.replace(comment='comment1; comment2'))
|
||||
|
||||
def test_missing_track_artist_name(self):
|
||||
del self.tags['artist']
|
||||
self.check(self.track.replace(artists=[]))
|
||||
|
||||
def test_multiple_track_artist_name(self):
|
||||
self.tags['artist'] = ['name1', 'name2']
|
||||
artists = [Artist(name='name1'), Artist(name='name2')]
|
||||
self.check(self.track.replace(artists=artists))
|
||||
|
||||
def test_missing_track_artist_musicbrainz_id(self):
|
||||
del self.tags['musicbrainz-artistid']
|
||||
artist = list(self.track.artists)[0].replace(musicbrainz_id=None)
|
||||
self.check(self.track.replace(artists=[artist]))
|
||||
|
||||
def test_multiple_track_artist_musicbrainz_id(self):
|
||||
self.tags['musicbrainz-artistid'].append('id')
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_composer_name(self):
|
||||
del self.tags['composer']
|
||||
self.check(self.track.replace(composers=[]))
|
||||
|
||||
def test_multiple_track_composer_name(self):
|
||||
self.tags['composer'] = ['composer1', 'composer2']
|
||||
composers = [Artist(name='composer1'), Artist(name='composer2')]
|
||||
self.check(self.track.replace(composers=composers))
|
||||
|
||||
def test_missing_track_performer_name(self):
|
||||
del self.tags['performer']
|
||||
self.check(self.track.replace(performers=[]))
|
||||
|
||||
def test_multiple_track_performe_name(self):
|
||||
self.tags['performer'] = ['performer1', 'performer2']
|
||||
performers = [Artist(name='performer1'), Artist(name='performer2')]
|
||||
self.check(self.track.replace(performers=performers))
|
||||
|
||||
def test_missing_album_name(self):
|
||||
del self.tags['album']
|
||||
self.check(self.track.replace(album=None))
|
||||
|
||||
def test_multiple_album_name(self):
|
||||
self.tags['album'].append('album2')
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_album_musicbrainz_id(self):
|
||||
del self.tags['musicbrainz-albumid']
|
||||
album = self.track.album.replace(musicbrainz_id=None,
|
||||
images=[])
|
||||
self.check(self.track.replace(album=album))
|
||||
|
||||
def test_multiple_album_musicbrainz_id(self):
|
||||
self.tags['musicbrainz-albumid'].append('id')
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_album_num_tracks(self):
|
||||
del self.tags['track-count']
|
||||
album = self.track.album.replace(num_tracks=None)
|
||||
self.check(self.track.replace(album=album))
|
||||
|
||||
def test_multiple_album_num_tracks(self):
|
||||
self.tags['track-count'].append(9)
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_album_num_discs(self):
|
||||
del self.tags['album-disc-count']
|
||||
album = self.track.album.replace(num_discs=None)
|
||||
self.check(self.track.replace(album=album))
|
||||
|
||||
def test_multiple_album_num_discs(self):
|
||||
self.tags['album-disc-count'].append(9)
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_album_artist_name(self):
|
||||
del self.tags['album-artist']
|
||||
album = self.track.album.replace(artists=[])
|
||||
self.check(self.track.replace(album=album))
|
||||
|
||||
def test_multiple_album_artist_name(self):
|
||||
self.tags['album-artist'] = ['name1', 'name2']
|
||||
artists = [Artist(name='name1'), Artist(name='name2')]
|
||||
album = self.track.album.replace(artists=artists)
|
||||
self.check(self.track.replace(album=album))
|
||||
|
||||
def test_missing_album_artist_musicbrainz_id(self):
|
||||
del self.tags['musicbrainz-albumartistid']
|
||||
albumartist = list(self.track.album.artists)[0]
|
||||
albumartist = albumartist.replace(musicbrainz_id=None)
|
||||
album = self.track.album.replace(artists=[albumartist])
|
||||
self.check(self.track.replace(album=album))
|
||||
|
||||
def test_multiple_album_artist_musicbrainz_id(self):
|
||||
self.tags['musicbrainz-albumartistid'].append('id')
|
||||
self.check(self.track)
|
||||
|
||||
def test_stream_organization_track_name(self):
|
||||
del self.tags['title']
|
||||
self.tags['organization'] = ['organization']
|
||||
self.check(self.track.replace(name='organization'))
|
||||
|
||||
def test_multiple_organization_track_name(self):
|
||||
del self.tags['title']
|
||||
self.tags['organization'] = ['organization1', 'organization2']
|
||||
self.check(self.track.replace(name='organization1; organization2'))
|
||||
|
||||
# TODO: combine all comment types?
|
||||
def test_stream_location_track_comment(self):
|
||||
del self.tags['comment']
|
||||
self.tags['location'] = ['location']
|
||||
self.check(self.track.replace(comment='location'))
|
||||
|
||||
def test_multiple_location_track_comment(self):
|
||||
del self.tags['comment']
|
||||
self.tags['location'] = ['location1', 'location2']
|
||||
self.check(self.track.replace(comment='location1; location2'))
|
||||
|
||||
def test_stream_copyright_track_comment(self):
|
||||
del self.tags['comment']
|
||||
self.tags['copyright'] = ['copyright']
|
||||
self.check(self.track.replace(comment='copyright'))
|
||||
|
||||
def test_multiple_copyright_track_comment(self):
|
||||
del self.tags['comment']
|
||||
self.tags['copyright'] = ['copyright1', 'copyright2']
|
||||
self.check(self.track.replace(comment='copyright1; copyright2'))
|
||||
|
||||
def test_sortname(self):
|
||||
self.tags['musicbrainz-sortname'] = ['another_sortname']
|
||||
artist = Artist(name='artist', sortname='another_sortname',
|
||||
musicbrainz_id='artistid')
|
||||
self.check(self.track.replace(artists=[artist]))
|
||||
|
||||
def test_missing_sortname(self):
|
||||
del self.tags['musicbrainz-sortname']
|
||||
artist = Artist(name='artist', sortname=None,
|
||||
musicbrainz_id='artistid')
|
||||
self.check(self.track.replace(artists=[artist]))
|
||||
@ -1,8 +1,5 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import datetime
|
||||
import unittest
|
||||
|
||||
import gi
|
||||
gi.require_version('Gst', '1.0')
|
||||
from gi.repository import Gst
|
||||
@ -10,7 +7,6 @@ from gi.repository import Gst
|
||||
import pytest
|
||||
|
||||
from mopidy.audio import utils
|
||||
from mopidy.models import Album, Artist, Track
|
||||
|
||||
|
||||
class TestCreateBuffer(object):
|
||||
@ -28,257 +24,3 @@ class TestCreateBuffer(object):
|
||||
utils.create_buffer(b'', timestamp=0, duration=1000000)
|
||||
|
||||
assert 'Cannot create buffer without data' in str(excinfo.value)
|
||||
|
||||
|
||||
# TODO: keep ids without name?
|
||||
# TODO: current test is trying to test everything at once with a complete tags
|
||||
# set, instead we might want to try with a minimal one making testing easier.
|
||||
class TagsToTrackTest(unittest.TestCase):
|
||||
|
||||
def setUp(self): # noqa: N802
|
||||
self.tags = {
|
||||
'album': ['album'],
|
||||
'track-number': [1],
|
||||
'artist': ['artist'],
|
||||
'composer': ['composer'],
|
||||
'performer': ['performer'],
|
||||
'album-artist': ['albumartist'],
|
||||
'title': ['track'],
|
||||
'track-count': [2],
|
||||
'album-disc-number': [2],
|
||||
'album-disc-count': [3],
|
||||
'date': [datetime.date(2006, 1, 1,)],
|
||||
'container-format': ['ID3 tag'],
|
||||
'genre': ['genre'],
|
||||
'comment': ['comment'],
|
||||
'musicbrainz-trackid': ['trackid'],
|
||||
'musicbrainz-albumid': ['albumid'],
|
||||
'musicbrainz-artistid': ['artistid'],
|
||||
'musicbrainz-sortname': ['sortname'],
|
||||
'musicbrainz-albumartistid': ['albumartistid'],
|
||||
'bitrate': [1000],
|
||||
}
|
||||
|
||||
artist = Artist(name='artist', musicbrainz_id='artistid',
|
||||
sortname='sortname')
|
||||
composer = Artist(name='composer')
|
||||
performer = Artist(name='performer')
|
||||
albumartist = Artist(name='albumartist',
|
||||
musicbrainz_id='albumartistid')
|
||||
|
||||
album = Album(name='album', num_tracks=2, num_discs=3,
|
||||
musicbrainz_id='albumid', artists=[albumartist])
|
||||
|
||||
self.track = Track(name='track', date='2006-01-01',
|
||||
genre='genre', track_no=1, disc_no=2,
|
||||
comment='comment', musicbrainz_id='trackid',
|
||||
album=album, bitrate=1000, artists=[artist],
|
||||
composers=[composer], performers=[performer])
|
||||
|
||||
def check(self, expected):
|
||||
actual = utils.convert_tags_to_track(self.tags)
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_track(self):
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_no(self):
|
||||
del self.tags['track-number']
|
||||
self.check(self.track.replace(track_no=None))
|
||||
|
||||
def test_multiple_track_no(self):
|
||||
self.tags['track-number'].append(9)
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_disc_no(self):
|
||||
del self.tags['album-disc-number']
|
||||
self.check(self.track.replace(disc_no=None))
|
||||
|
||||
def test_multiple_track_disc_no(self):
|
||||
self.tags['album-disc-number'].append(9)
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_name(self):
|
||||
del self.tags['title']
|
||||
self.check(self.track.replace(name=None))
|
||||
|
||||
def test_multiple_track_name(self):
|
||||
self.tags['title'] = ['name1', 'name2']
|
||||
self.check(self.track.replace(name='name1; name2'))
|
||||
|
||||
def test_missing_track_musicbrainz_id(self):
|
||||
del self.tags['musicbrainz-trackid']
|
||||
self.check(self.track.replace(musicbrainz_id=None))
|
||||
|
||||
def test_multiple_track_musicbrainz_id(self):
|
||||
self.tags['musicbrainz-trackid'].append('id')
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_bitrate(self):
|
||||
del self.tags['bitrate']
|
||||
self.check(self.track.replace(bitrate=None))
|
||||
|
||||
def test_multiple_track_bitrate(self):
|
||||
self.tags['bitrate'].append(1234)
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_genre(self):
|
||||
del self.tags['genre']
|
||||
self.check(self.track.replace(genre=None))
|
||||
|
||||
def test_multiple_track_genre(self):
|
||||
self.tags['genre'] = ['genre1', 'genre2']
|
||||
self.check(self.track.replace(genre='genre1; genre2'))
|
||||
|
||||
def test_missing_track_date(self):
|
||||
del self.tags['date']
|
||||
self.check(self.track.replace(date=None))
|
||||
|
||||
def test_multiple_track_date(self):
|
||||
self.tags['date'].append(datetime.date(2030, 1, 1))
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_comment(self):
|
||||
del self.tags['comment']
|
||||
self.check(self.track.replace(comment=None))
|
||||
|
||||
def test_multiple_track_comment(self):
|
||||
self.tags['comment'] = ['comment1', 'comment2']
|
||||
self.check(self.track.replace(comment='comment1; comment2'))
|
||||
|
||||
def test_missing_track_artist_name(self):
|
||||
del self.tags['artist']
|
||||
self.check(self.track.replace(artists=[]))
|
||||
|
||||
def test_multiple_track_artist_name(self):
|
||||
self.tags['artist'] = ['name1', 'name2']
|
||||
artists = [Artist(name='name1'), Artist(name='name2')]
|
||||
self.check(self.track.replace(artists=artists))
|
||||
|
||||
def test_missing_track_artist_musicbrainz_id(self):
|
||||
del self.tags['musicbrainz-artistid']
|
||||
artist = list(self.track.artists)[0].replace(musicbrainz_id=None)
|
||||
self.check(self.track.replace(artists=[artist]))
|
||||
|
||||
def test_multiple_track_artist_musicbrainz_id(self):
|
||||
self.tags['musicbrainz-artistid'].append('id')
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_track_composer_name(self):
|
||||
del self.tags['composer']
|
||||
self.check(self.track.replace(composers=[]))
|
||||
|
||||
def test_multiple_track_composer_name(self):
|
||||
self.tags['composer'] = ['composer1', 'composer2']
|
||||
composers = [Artist(name='composer1'), Artist(name='composer2')]
|
||||
self.check(self.track.replace(composers=composers))
|
||||
|
||||
def test_missing_track_performer_name(self):
|
||||
del self.tags['performer']
|
||||
self.check(self.track.replace(performers=[]))
|
||||
|
||||
def test_multiple_track_performe_name(self):
|
||||
self.tags['performer'] = ['performer1', 'performer2']
|
||||
performers = [Artist(name='performer1'), Artist(name='performer2')]
|
||||
self.check(self.track.replace(performers=performers))
|
||||
|
||||
def test_missing_album_name(self):
|
||||
del self.tags['album']
|
||||
self.check(self.track.replace(album=None))
|
||||
|
||||
def test_multiple_album_name(self):
|
||||
self.tags['album'].append('album2')
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_album_musicbrainz_id(self):
|
||||
del self.tags['musicbrainz-albumid']
|
||||
album = self.track.album.replace(musicbrainz_id=None,
|
||||
images=[])
|
||||
self.check(self.track.replace(album=album))
|
||||
|
||||
def test_multiple_album_musicbrainz_id(self):
|
||||
self.tags['musicbrainz-albumid'].append('id')
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_album_num_tracks(self):
|
||||
del self.tags['track-count']
|
||||
album = self.track.album.replace(num_tracks=None)
|
||||
self.check(self.track.replace(album=album))
|
||||
|
||||
def test_multiple_album_num_tracks(self):
|
||||
self.tags['track-count'].append(9)
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_album_num_discs(self):
|
||||
del self.tags['album-disc-count']
|
||||
album = self.track.album.replace(num_discs=None)
|
||||
self.check(self.track.replace(album=album))
|
||||
|
||||
def test_multiple_album_num_discs(self):
|
||||
self.tags['album-disc-count'].append(9)
|
||||
self.check(self.track)
|
||||
|
||||
def test_missing_album_artist_name(self):
|
||||
del self.tags['album-artist']
|
||||
album = self.track.album.replace(artists=[])
|
||||
self.check(self.track.replace(album=album))
|
||||
|
||||
def test_multiple_album_artist_name(self):
|
||||
self.tags['album-artist'] = ['name1', 'name2']
|
||||
artists = [Artist(name='name1'), Artist(name='name2')]
|
||||
album = self.track.album.replace(artists=artists)
|
||||
self.check(self.track.replace(album=album))
|
||||
|
||||
def test_missing_album_artist_musicbrainz_id(self):
|
||||
del self.tags['musicbrainz-albumartistid']
|
||||
albumartist = list(self.track.album.artists)[0]
|
||||
albumartist = albumartist.replace(musicbrainz_id=None)
|
||||
album = self.track.album.replace(artists=[albumartist])
|
||||
self.check(self.track.replace(album=album))
|
||||
|
||||
def test_multiple_album_artist_musicbrainz_id(self):
|
||||
self.tags['musicbrainz-albumartistid'].append('id')
|
||||
self.check(self.track)
|
||||
|
||||
def test_stream_organization_track_name(self):
|
||||
del self.tags['title']
|
||||
self.tags['organization'] = ['organization']
|
||||
self.check(self.track.replace(name='organization'))
|
||||
|
||||
def test_multiple_organization_track_name(self):
|
||||
del self.tags['title']
|
||||
self.tags['organization'] = ['organization1', 'organization2']
|
||||
self.check(self.track.replace(name='organization1; organization2'))
|
||||
|
||||
# TODO: combine all comment types?
|
||||
def test_stream_location_track_comment(self):
|
||||
del self.tags['comment']
|
||||
self.tags['location'] = ['location']
|
||||
self.check(self.track.replace(comment='location'))
|
||||
|
||||
def test_multiple_location_track_comment(self):
|
||||
del self.tags['comment']
|
||||
self.tags['location'] = ['location1', 'location2']
|
||||
self.check(self.track.replace(comment='location1; location2'))
|
||||
|
||||
def test_stream_copyright_track_comment(self):
|
||||
del self.tags['comment']
|
||||
self.tags['copyright'] = ['copyright']
|
||||
self.check(self.track.replace(comment='copyright'))
|
||||
|
||||
def test_multiple_copyright_track_comment(self):
|
||||
del self.tags['comment']
|
||||
self.tags['copyright'] = ['copyright1', 'copyright2']
|
||||
self.check(self.track.replace(comment='copyright1; copyright2'))
|
||||
|
||||
def test_sortname(self):
|
||||
self.tags['musicbrainz-sortname'] = ['another_sortname']
|
||||
artist = Artist(name='artist', sortname='another_sortname',
|
||||
musicbrainz_id='artistid')
|
||||
self.check(self.track.replace(artists=[artist]))
|
||||
|
||||
def test_missing_sortname(self):
|
||||
del self.tags['musicbrainz-sortname']
|
||||
artist = Artist(name='artist', sortname=None,
|
||||
musicbrainz_id='artistid')
|
||||
self.check(self.track.replace(artists=[artist]))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user