The new function only uses tags as input. In other words we now need to set length, uri and mtime ourselves. Users of scan APIs have been updated.
335 lines
12 KiB
Python
335 lines
12 KiB
Python
from __future__ import absolute_import, unicode_literals
|
|
|
|
import datetime
|
|
import os
|
|
import unittest
|
|
|
|
import gobject
|
|
gobject.threads_init()
|
|
|
|
from mopidy import exceptions
|
|
from mopidy.audio import scan
|
|
from mopidy.models import Album, Artist, Track
|
|
from mopidy.utils import path as path_lib
|
|
|
|
from tests import path_to_data_dir
|
|
|
|
|
|
# TODO: keep ids without name?
|
|
class TagsToTrackTest(unittest.TestCase):
|
|
def setUp(self): # noqa
|
|
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-albumartistid': ['albumartistid'],
|
|
'bitrate': [1000],
|
|
}
|
|
|
|
artist = Artist(name='artist', musicbrainz_id='artistid')
|
|
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 = scan.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.copy(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.copy(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.copy(name=None))
|
|
|
|
def test_multiple_track_name(self):
|
|
self.tags['title'] = ['name1', 'name2']
|
|
self.check(self.track.copy(name='name1; name2'))
|
|
|
|
def test_missing_track_musicbrainz_id(self):
|
|
del self.tags['musicbrainz-trackid']
|
|
self.check(self.track.copy(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.copy(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.copy(genre=None))
|
|
|
|
def test_multiple_track_genre(self):
|
|
self.tags['genre'] = ['genre1', 'genre2']
|
|
self.check(self.track.copy(genre='genre1; genre2'))
|
|
|
|
def test_missing_track_date(self):
|
|
del self.tags['date']
|
|
self.check(self.track.copy(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.copy(comment=None))
|
|
|
|
def test_multiple_track_comment(self):
|
|
self.tags['comment'] = ['comment1', 'comment2']
|
|
self.check(self.track.copy(comment='comment1; comment2'))
|
|
|
|
def test_missing_track_artist_name(self):
|
|
del self.tags['artist']
|
|
self.check(self.track.copy(artists=[]))
|
|
|
|
def test_multiple_track_artist_name(self):
|
|
self.tags['artist'] = ['name1', 'name2']
|
|
artists = [Artist(name='name1'), Artist(name='name2')]
|
|
self.check(self.track.copy(artists=artists))
|
|
|
|
def test_missing_track_artist_musicbrainz_id(self):
|
|
del self.tags['musicbrainz-artistid']
|
|
artist = list(self.track.artists)[0].copy(musicbrainz_id=None)
|
|
self.check(self.track.copy(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.copy(composers=[]))
|
|
|
|
def test_multiple_track_composer_name(self):
|
|
self.tags['composer'] = ['composer1', 'composer2']
|
|
composers = [Artist(name='composer1'), Artist(name='composer2')]
|
|
self.check(self.track.copy(composers=composers))
|
|
|
|
def test_missing_track_performer_name(self):
|
|
del self.tags['performer']
|
|
self.check(self.track.copy(performers=[]))
|
|
|
|
def test_multiple_track_performe_name(self):
|
|
self.tags['performer'] = ['performer1', 'performer2']
|
|
performers = [Artist(name='performer1'), Artist(name='performer2')]
|
|
self.check(self.track.copy(performers=performers))
|
|
|
|
def test_missing_album_name(self):
|
|
del self.tags['album']
|
|
album = self.track.album.copy(name=None)
|
|
self.check(self.track.copy(album=album))
|
|
|
|
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.copy(musicbrainz_id=None,
|
|
images=[])
|
|
self.check(self.track.copy(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.copy(num_tracks=None)
|
|
self.check(self.track.copy(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.copy(num_discs=None)
|
|
self.check(self.track.copy(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.copy(artists=[])
|
|
self.check(self.track.copy(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.copy(artists=artists)
|
|
self.check(self.track.copy(album=album))
|
|
|
|
def test_missing_album_artist_musicbrainz_id(self):
|
|
del self.tags['musicbrainz-albumartistid']
|
|
albumartist = list(self.track.album.artists)[0]
|
|
albumartist = albumartist.copy(musicbrainz_id=None)
|
|
album = self.track.album.copy(artists=[albumartist])
|
|
self.check(self.track.copy(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.copy(name='organization'))
|
|
|
|
def test_multiple_organization_track_name(self):
|
|
del self.tags['title']
|
|
self.tags['organization'] = ['organization1', 'organization2']
|
|
self.check(self.track.copy(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.copy(comment='location'))
|
|
|
|
def test_multiple_location_track_comment(self):
|
|
del self.tags['comment']
|
|
self.tags['location'] = ['location1', 'location2']
|
|
self.check(self.track.copy(comment='location1; location2'))
|
|
|
|
def test_stream_copyright_track_comment(self):
|
|
del self.tags['comment']
|
|
self.tags['copyright'] = ['copyright']
|
|
self.check(self.track.copy(comment='copyright'))
|
|
|
|
def test_multiple_copyright_track_comment(self):
|
|
del self.tags['comment']
|
|
self.tags['copyright'] = ['copyright1', 'copyright2']
|
|
self.check(self.track.copy(comment='copyright1; copyright2'))
|
|
|
|
|
|
class ScannerTest(unittest.TestCase):
|
|
def setUp(self): # noqa
|
|
self.errors = {}
|
|
self.tags = {}
|
|
self.durations = {}
|
|
|
|
def find(self, path):
|
|
media_dir = path_to_data_dir(path)
|
|
result, errors = path_lib.find_mtimes(media_dir)
|
|
for path in result:
|
|
yield os.path.join(media_dir, path)
|
|
|
|
def scan(self, paths):
|
|
scanner = scan.Scanner()
|
|
for path in paths:
|
|
uri = path_lib.path_to_uri(path)
|
|
key = uri[len('file://'):]
|
|
try:
|
|
tags, duration = scanner.scan(uri)
|
|
self.tags[key] = tags
|
|
self.durations[key] = duration
|
|
except exceptions.ScannerError as error:
|
|
self.errors[key] = error
|
|
|
|
def check_tag(self, name, key, value):
|
|
name = path_to_data_dir(name)
|
|
self.assertEqual(self.tags[name][key], value)
|
|
|
|
def check_duration(self, name, value):
|
|
name = path_to_data_dir(name)
|
|
self.assertEqual(self.durations[name], value)
|
|
|
|
def test_tags_is_set(self):
|
|
self.scan(self.find('scanner/simple'))
|
|
self.assert_(self.tags)
|
|
|
|
def test_errors_is_not_set(self):
|
|
self.scan(self.find('scanner/simple'))
|
|
self.assert_(not self.errors)
|
|
|
|
def test_duration_is_set(self):
|
|
self.scan(self.find('scanner/simple'))
|
|
self.check_duration('scanner/simple/song1.mp3', 4680)
|
|
self.check_duration('scanner/simple/song1.ogg', 4680)
|
|
|
|
def test_artist_is_set(self):
|
|
self.scan(self.find('scanner/simple'))
|
|
self.check_tag('scanner/simple/song1.mp3', 'artist', ['name'])
|
|
self.check_tag('scanner/simple/song1.ogg', 'artist', ['name'])
|
|
|
|
def test_album_is_set(self):
|
|
self.scan(self.find('scanner/simple'))
|
|
self.check_tag('scanner/simple/song1.mp3', 'album', ['albumname'])
|
|
self.check_tag('scanner/simple/song1.ogg', 'album', ['albumname'])
|
|
|
|
def test_track_is_set(self):
|
|
self.scan(self.find('scanner/simple'))
|
|
self.check_tag('scanner/simple/song1.mp3', 'title', ['trackname'])
|
|
self.check_tag('scanner/simple/song1.ogg', 'title', ['trackname'])
|
|
|
|
def test_nonexistant_dir_does_not_fail(self):
|
|
self.scan(self.find('scanner/does-not-exist'))
|
|
self.assert_(not self.errors)
|
|
|
|
def test_other_media_is_ignored(self):
|
|
self.scan(self.find('scanner/image'))
|
|
self.assert_(self.errors)
|
|
|
|
def test_log_file_that_gst_thinks_is_mpeg_1_is_ignored(self):
|
|
self.scan([path_to_data_dir('scanner/example.log')])
|
|
self.assert_(self.errors)
|
|
|
|
def test_empty_wav_file_is_ignored(self):
|
|
self.scan([path_to_data_dir('scanner/empty.wav')])
|
|
self.assert_(self.errors)
|
|
|
|
@unittest.SkipTest
|
|
def test_song_without_time_is_handeled(self):
|
|
pass
|