def create_item(self, **values): """Return an `Item` instance with sensible default values. The item receives its attributes from `**values` paratmeter. The `title`, `artist`, `album`, `track`, `format` and `path` attributes have defaults if they are not given as parameters. The `title` attribute is formated with a running item count to prevent duplicates. The default for the `path` attribute respects the `format` value. The item is attached to the database from `self.lib`. """ item_count = self._get_item_count() values_ = { 'title': u't\u00eftle {0}', 'artist': u'the \u00e4rtist', 'album': u'the \u00e4lbum', 'track': item_count, 'format': 'MP3', } values_.update(values) values_['title'] = values_['title'].format(item_count) values_['db'] = self.lib item = Item(**values_) if 'path' not in values: item['path'] = 'audio.' + item['format'].lower() # mtime needs to be set last since other assignments reset it. item.mtime = 12345 return item
def test_missing_request(self): json_file = os.path.join(_common.RSRC, b'spotify', b'missing_request.json') with open(json_file, 'rb') as f: response_body = f.read() responses.add(responses.GET, 'https://api.spotify.com/v1/search', body=response_body, status=200, content_type='application/json') item = Item( mb_trackid=u'01234', album=u'lkajsdflakjsd', albumartist=u'ujydfsuihse', title=u'duifhjslkef', length=10 ) item.add(self.lib) self.assertEqual([], self.spotify.query_spotify(self.lib, u"")) params = _params(responses.calls[0].request.url) self.assertEqual( params['q'], [u'duifhjslkef album:lkajsdflakjsd artist:ujydfsuihse'], ) self.assertEqual(params['type'], [u'track'])
def test_missing_request(self): response_body = str( '{' '"tracks" : {' '"href" : "https://api.spotify.com/v1/search?query=duifhjslkef' '+album%3Alkajsdflakjsd+artist%3A&offset=0&limit=20&type=track",' '"items" : [ ],' '"limit" : 20,' '"next" : null,' '"offset" : 0,' '"previous" : null,' '"total" : 0' '}' '}' ) responses.add(responses.GET, 'https://api.spotify.com/v1/search?q=duifhjslkef+album' '%3Alkajsdflakjsd+artist%3A&type=track', body=response_body, status=200, content_type='application/json') item = Item( mb_trackid='01234', album='lkajsdflakjsd', albumartist='ujydfsuihse', title='duifhjslkef', length=10 ) item.add(self.lib) self.assertEquals([], self.spotify.query_spotify(self.lib, ""))
def test_missing_request(self): response_body = bytes( '{' '"tracks" : {' '"href" : "https://api.spotify.com/v1/search?query=duifhjslkef' '+album%3Alkajsdflakjsd+artist%3A&offset=0&limit=20&type=track",' '"items" : [ ],' '"limit" : 20,' '"next" : null,' '"offset" : 0,' '"previous" : null,' '"total" : 0' '}' '}' ) responses.add(responses.GET, 'https://api.spotify.com/v1/search', body=response_body, status=200, content_type='application/json') item = Item( mb_trackid=u'01234', album=u'lkajsdflakjsd', albumartist=u'ujydfsuihse', title=u'duifhjslkef', length=10 ) item.add(self.lib) self.assertEqual([], self.spotify.query_spotify(self.lib, u"")) params = _params(responses.calls[0].request.url) self.assertEqual( params['q'], [u'duifhjslkef album:lkajsdflakjsd artist:ujydfsuihse'], ) self.assertEqual(params['type'], [u'track'])
def test_store_data(self, echonest_track, echonest_profile, item_write): profile = Mock( artist_name='artist', title='title', id='echonestid', audio_summary={ 'duration': 10, 'energy': 0.5, 'liveness': 0.5, 'loudness': 0.5, 'speechiness': 0.5, 'danceability': 0.5, 'tempo': 120, 'key': 2, 'mode': 0 }, ) echonest_profile.return_value = [profile] echonest_track.return_value = Mock(song_id='echonestid') item = Item( mb_trackid='01234', artist='artist', title='title', length=10, ) item.add(self.lib) self.assertNotIn('danceability', item) self.assertNotIn('initialkey', item) self.run_command('echonest') item.load() self.assertEqual(item['danceability'], '0.5') self.assertEqual(item['initial_key'], 'C#m')
def test_track_request(self): json_file = os.path.join(_common.RSRC, b'spotify', b'track_request.json') with open(json_file, 'rb') as f: response_body = f.read() responses.add(responses.GET, 'https://api.spotify.com/v1/search', body=response_body, status=200, content_type='application/json') item = Item( mb_trackid=u'01234', album=u'Despicable Me 2', albumartist=u'Pharrell Williams', title=u'Happy', length=10 ) item.add(self.lib) results = self.spotify.query_spotify(self.lib, u"Happy") self.assertEqual(1, len(results)) self.assertEqual(u"6NPVjNh8Jhru9xOmyQigds", results[0]['id']) self.spotify.output_results(results) params = _params(responses.calls[0].request.url) self.assertEqual( params['q'], [u'Happy album:Despicable Me 2 artist:Pharrell Williams'], ) self.assertEqual(params['type'], [u'track'])
def test_do_not_overwrite(self): item = Item(path='/file', initial_key='F') item.add(self.lib) self.command_output.return_value = 'dbm' self.run_command('keyfinder') item.load() self.assertEqual(item['initial_key'], 'F')
def test_do_not_overwrite(self): item = Item(path="/file", initial_key="F") item.add(self.lib) self.command_output.return_value = "dbm" self.run_command("keyfinder") item.load() self.assertEqual(item["initial_key"], "F")
def test_update_rating(self): item = Item(title=u'title', path='', id=1) item.add(self.lib) log = Mock() mpdstats = MPDStats(self.lib, log) self.assertFalse(mpdstats.update_rating(item, True)) self.assertFalse(mpdstats.update_rating(None, True))
def test_add_key(self): item = Item(path="/file") item.add(self.lib) self.command_output.return_value = "dbm" self.run_command("keyfinder") item.load() self.assertEqual(item["initial_key"], "C#m") self.command_output.assert_called_with(["KeyFinder", "-f", item.path])
def test_get_item(self): item_path = '/foo/bar.flac' item = Item(title=u'title', path=item_path, id=1) item.add(self.lib) log = Mock() mpdstats = MPDStats(self.lib, log) self.assertEqual(str(mpdstats.get_item(item_path)), str(item)) self.assertIsNone(mpdstats.get_item('/some/non-existing/path')) self.assertIn(u'item not found:', log.info.call_args[0][0])
def test_force_overwrite(self): self.config['keyfinder']['overwrite'] = True item = Item(path='/file', initial_key='F') item.add(self.lib) self.command_output.return_value = 'C#m' self.run_command('keyfinder') item.load() self.assertEqual(item['initial_key'], 'C#m')
def test_force_overwrite(self): self.config["keyfinder"]["overwrite"] = True item = Item(path="/file", initial_key="F") item.add(self.lib) self.command_output.return_value = "C#m" self.run_command("keyfinder") item.load() self.assertEqual(item["initial_key"], "C#m")
def test_add_key(self): item = Item(path='/file') item.add(self.lib) self.command_output.return_value = 'dbm' self.run_command('keyfinder') item.load() self.assertEqual(item['initial_key'], 'C#m') self.command_output.assert_called_with( ['KeyFinder', '-f', item.path])
def test_write_extended_tag_from_item(self): plugin = BeetsPlugin() plugin.add_media_field('customtag', field_extension) mediafile = self._mediafile_fixture('empty') self.assertIsNone(mediafile.customtag) item = Item(path=mediafile.path, customtag=u'Gb') item.write() mediafile = MediaFile(mediafile.path) self.assertEqual(mediafile.customtag, u'Gb') delattr(MediaFile, 'customtag') Item._media_fields.remove('customtag')
def test_write_extended_tag_from_item(self): plugin = BeetsPlugin() plugin.add_media_field('initialkey', field_extension) mediafile = self._mediafile_fixture('empty') self.assertEqual(mediafile.initialkey, '') item = Item(path=mediafile.path, initialkey='Gb') item.write() mediafile = MediaFile(mediafile.path) self.assertEqual(mediafile.initialkey, 'Gb') delattr(MediaFile, 'initialkey') Item.media_fields.remove('initialkey')
def test_run_mpdstats(self, mpd_mock): item = Item(title=u'title', path=self.item_path, id=1) item.add(self.lib) log = Mock() try: MPDStats(self.lib, log).run() except KeyboardInterrupt: pass log.debug.assert_has_calls( [call(u'unhandled status "{0}"', ANY)]) log.info.assert_has_calls( [call(u'pause'), call(u'playing {0}', ANY), call(u'stop')])
def addItemFixture(self, basename='ok.ogg'): src = os.path.join(self.fixture_dir, basename) dst = os.path.join(self.libdir, basename) shutil.copy(src, dst) item = Item.from_path(dst) item.add(self.lib) return item
def test_get_single_item_by_path(self): data_path = os.path.join(_common.RSRC, b'full.mp3') self.lib.add(Item.from_path(data_path)) response = self.client.get('/item/path/' + data_path.decode('utf-8')) res_json = json.loads(response.data.decode('utf-8')) self.assertEqual(response.status_code, 200) self.assertEqual(res_json['title'], u'full')
def setupFixtureLibrary(self): self.import_dir = os.path.join(self.temp_dir, 'import') for file in os.listdir(self.fixture_dir): src = os.path.join(self.fixture_dir, file) dst = os.path.join(self.libdir, file) shutil.copy(src, dst) item = Item.from_path(dst) item.add(self.lib) check.set_checksum(item)
def setUp(self): self.setup_beets() self.load_plugins('edit') # Create some mediafiles, and store them for comparison. self._create_import_dir(3) self.items_orig = [Item.from_path(f.path) for f in self.media_files] self.matcher = AutotagStub().install() self.matcher.matching = AutotagStub.GOOD self.config['import']['timid'] = True
def add_item(self, **values_): """Add an item to the library and return it. The item receives sensible default values for the title, artist, and album fields. These default values contain unicode characters to test for encoding issues. The track title also includes a counter to make sure we do not create items with the same attributes. """ values = { 'title': u't\u00eftle {0}'.format(self._get_item_count()), 'artist': u'the \u00e4rtist', 'album': u'the \u00e4lbum', } values.update(values_) item = Item(**values) if hasattr(self, 'lib'): item.add(self.lib) return item
def add_item_fixtures(self, ext='mp3', count=1): items = [] paths = glob(os.path.join(_common.RSRC, '*.' + ext)) for path in paths[0:count]: item = Item.from_path(str(path)) item.add(self.lib) item.move(copy=True) item.store() items.append(item) return items
def pre_process_folder(folder): p = Path(folder) assert p.isdir(), "Got non directory input, breaking" paths = _collect_files_from_folder(p) items = [Item.from_path(str(f)) for f in paths] tempdir = tempfile.mkdtemp(prefix="temp_") for item in items: filename = os.path.basename(item.path) item.move_file(os.path.join(tempdir, filename), copy=True) yield AlbumTask(items)
def test_album_art(self): self.config['zero']['fields'] = ['images'] path = self.create_mediafile_fixture(images=['jpg']) item = Item.from_path(path) self.load_plugins('zero') item.write() mf = MediaFile(syspath(path)) self.assertEqual(0, len(mf.images))
def test_read_flexible_attribute_from_file(self): plugin = BeetsPlugin() plugin.add_media_field('initialkey', field_extension) mediafile = self._mediafile_fixture('empty') mediafile.update({'initialkey': 'F#'}) item = Item.from_path(mediafile.path) self.assertEqual(item['initialkey'], 'F#') delattr(MediaFile, 'initialkey') Item.media_fields.remove('initialkey')
def emitter(): fields = list(mediafile.MediaFile.readable_fields()) fields.remove('images') mf = mediafile.MediaFile(syspath(path)) tags = {} for field in fields: tags[field] = getattr(mf, field) tags['art'] = mf.art is not None # create a temporary Item to take advantage of __format__ item = Item.from_path(syspath(path)) return tags, item
def test_update_library(self, track_for_mbid, album_for_mbid): album_for_mbid.return_value = \ generate_album_info('album id', ['track id']) track_for_mbid.return_value = \ generate_track_info(u'singleton track id', {'title': u'singleton info'}) album_item = Item( album=u'old title', mb_albumid=u'album id', mb_trackid=u'track id', path='' ) album = self.lib.add_album([album_item]) item = Item( title=u'old title', mb_trackid=u'singleton track id', path='', ) self.lib.add(item) self.run_command('mbsync') item.load() self.assertEqual(item.title, u'singleton info') album_item.load() self.assertEqual(album_item.title, u'track info') album.load() self.assertEqual(album.album, u'album info')
def test_album_art(self): path = self.create_mediafile_fixture(images=['jpg']) item = Item.from_path(path) mediafile = MediaFile(syspath(item.path)) self.assertNotEqual(0, len(mediafile.images)) config['zero'] = {'fields': [u'images']} self.load_plugins('zero') item.write() mediafile = MediaFile(syspath(item.path)) self.assertEqual(0, len(mediafile.images))
def test_read_flexible_attribute_from_file(self): plugin = BeetsPlugin() plugin.add_media_field('customtag', field_extension) mediafile = self._mediafile_fixture('empty') mediafile.update({'customtag': u'F#'}) mediafile.save() item = Item.from_path(mediafile.path) self.assertEqual(item['customtag'], u'F#') delattr(MediaFile, 'customtag') Item._media_fields.remove('customtag')
def _item(track_info, album_info, album_id): """Build and return `item` from `track_info` and `album info` objects. `item` is missing what fields cannot be obtained from MusicBrainz alone (encoder, rg_track_gain, rg_track_peak, rg_album_gain, rg_album_peak, original_year, original_month, original_day, length, bitrate, format, samplerate, bitdepth, channels, mtime.) """ t = track_info a = album_info return Item( **{ 'album_id': album_id, 'album': a.album, 'albumartist': a.artist, 'albumartist_credit': a.artist_credit, 'albumartist_sort': a.artist_sort, 'albumdisambig': a.albumdisambig, 'albumstatus': a.albumstatus, 'albumtype': a.albumtype, 'artist': t.artist, 'artist_credit': t.artist_credit, 'artist_sort': t.artist_sort, 'asin': a.asin, 'catalognum': a.catalognum, 'comp': a.va, 'country': a.country, 'day': a.day, 'disc': t.medium, 'disctitle': t.disctitle, 'disctotal': a.mediums, 'label': a.label, 'language': a.language, 'length': t.length, 'mb_albumid': a.album_id, 'mb_artistid': t.artist_id, 'mb_releasegroupid': a.releasegroup_id, 'mb_trackid': t.track_id, 'media': t.media, 'month': a.month, 'script': a.script, 'title': t.title, 'track': t.index, 'tracktotal': len(a.tracks), 'year': a.year, })
def process_item(self, item: Item): self._say("Fixing item: {}".format(item), log_only=True) current_genre = item.get("genre") tag_groups = [] qtypes = (self.config["types"].keys()) metadata = { 'artist': item.get("artist"), 'artistid': item.get("mb_artistid:"), 'album': item.get("album"), 'albumid': item.get("mb_releasegroupid"), 'year': item.get("year") } for dp in self.dataproviders: # self._say("{}: {}".format("=" * 60, dp.name)) for qtype in qtypes: tags = self.get_tags_from_provider(dp, qtype, metadata) # self._say("tags[{}]: {}".format(qtype, tags), log_only=False) if tags: tag_groups.append({ 'provider': dp.name, 'qtype': qtype, 'tags': tags }) # self._say("Tags: {}".format(tag_groups), log_only=False) tags = self.create_unified_tag_list(tag_groups) # self._say("Unified Tags: {}".format(tags), log_only=False) tags = self.get_scored_tags(tags) # self._say("Scored Tags: {}".format(tags), log_only=False) tags = sorted(tags.items(), key=operator.itemgetter(1), reverse=True) self._say("Ordered Tags: {}".format(tags), log_only=False) _max = self.config["max_tags"].as_number() _glue = self.config["tag_glue"].as_str() top_tags = [v[0] for v in tags][:_max] # self._say("Top Tags: {}".format(top_tags), log_only=False) changed = False if top_tags: new_genre = _glue.join(top_tags) if new_genre != current_genre: self._say("Setting new genre: '{}' -> '{}'".format( current_genre, new_genre), log_only=False) item["genre"] = new_genre changed = True return changed
def test_add_key(self, command_output): item = Item(path='/file') item.add(self.lib) command_output.return_value = 'dbm' self.run_command('keyfinder') item.load() self.assertEqual(item['initial_key'], 'C#m') command_output.assert_called_with( ['KeyFinder', '-f', util.syspath(item.path)])
def test_normal_case(self, command_output): item = Item(path='/file', mb_workid=u'e27bda6e-531e-36d3-9cd7-b8ebc18e8c53') item.add(self.lib) command_output.return_value = u'32c8943f-1b27-3a23-8660-4567f4847c94' self.run_command('parentwork') item.load() self.assertEqual(item['mb_parentworkid'], u'32c8943f-1b27-3a23-8660-4567f4847c94')
def _item(track_info, album_info, album_id): """Build and return `item` from `track_info` and `album info` objects. `item` is missing what fields cannot be obtained from MusicBrainz alone (encoder, rg_track_gain, rg_track_peak, rg_album_gain, rg_album_peak, original_year, original_month, original_day, length, bitrate, format, samplerate, bitdepth, channels, mtime.) """ t = track_info a = album_info return Item( album_id=album_id, album=a.album, albumartist=a.artist, albumartist_credit=a.artist_credit, albumartist_sort=a.artist_sort, albumdisambig=a.albumdisambig, albumstatus=a.albumstatus, albumtype=a.albumtype, artist=t.artist, artist_credit=t.artist_credit, artist_sort=t.artist_sort, asin=a.asin, catalognum=a.catalognum, comp=a.va, country=a.country, day=a.day, disc=t.medium, disctitle=t.disctitle, disctotal=a.mediums, label=a.label, language=a.language, length=t.length, mb_albumid=a.album_id, mb_artistid=t.artist_id, mb_releasegroupid=a.releasegroup_id, mb_trackid=t.track_id, media=a.media, month=a.month, script=a.script, title=t.title, track=t.index, tracktotal=len(a.tracks), year=a.year, )
def add_item_fixtures(self, ext='mp3', count=1): """Add a number of items with files to the database. """ # TODO base this on `add_item()` items = [] path = os.path.join(_common.RSRC, util.bytestring_path('full.' + ext)) for i in range(count): item = Item.from_path(path) item.album = u'\u00e4lbum {0}'.format(i) # Check unicode paths item.title = u't\u00eftle {0}'.format(i) # mtime needs to be set last since other assignments reset it. item.mtime = 12345 item.add(self.lib) item.move(operation=MoveOperation.COPY) item.store() items.append(item) return items
def add_album_fixture(self, track_count=1, ext='mp3', filename='full'): """Add an album with files to the database. """ items = [] path = os.path.join(_common.RSRC, util.bytestring_path(filename + '.' + ext)) for i in range(track_count): item = Item.from_path(path) item.album = u'\u00e4lbum' # Check unicode paths item.title = u't\u00eftle {0}'.format(i) # mtime needs to be set last since other assignments reset it. item.mtime = 12345 item.add(self.lib) item.move(operation=MoveOperation.COPY) item.store() items.append(item) return self.lib.add_album(items)
def _album_item(album_info): """Build and return `item` from `album info` objects. `item` is missing what fields cannot be obtained from MusicBrainz alone (encoder, rg_track_gain, rg_track_peak, rg_album_gain, rg_album_peak, original_year, original_month, original_day, length, bitrate, format, samplerate, bitdepth, channels, mtime.) """ a = album_info return Item(**{ 'album_id': a.get("id"), 'album': a.get("release-group", {}).get("title"), 'albumartist': a.get("release-group", {}).get("artist-credit", [])[0].get("artist", {}).get("name") if len(a.get("release-group", {}).get("artist-credit", [])) > 0 else None, 'albumartist_credit': a.get("release-group", {}).get("artist-credit-phrase"), 'albumartist_sort': a.get("release-group", {}).get("artist-credit", [])[0].get("artist", {}).get("sort-name") if len(a.get("release-group", {}).get("artist-credit", [])) > 0 else None, 'albumdisambig': a.get("release-group", {}).get("artist-credit", [])[0].get("artist", {}).get("disambiguation") if len(a.get("release-group", {}).get("artist-credit", [])) > 0 else None, 'albumstatus': a.get("status"), 'albumtype': a.get("release-group", {}).get("primary-type"), 'albumsubtype': a.get("release-group", {}).get("secondary-type-list", [])[0] if len(a.get("release-group", {}).get("secondary-type-list", [])) > 0 else None, 'artist': a.get("artist-credit", [])[0].get("artist", {}).get("name") if len(a.get("artist-credit", [])) > 0 else None, 'artist_credit': a.get("artist-credit-phrase"), 'artist_sort': a.get("artist-credit", [])[0].get("artist", {}).get("sort-name") if len(a.get("artist-credit", [])) > 0 else None, 'asin': a.get("asin"), 'catalognum': a.get("label-info-list", [])[0].get("catalog-number") if len(a.get("label-info-list", [])) > 0 else None, 'comp': a.get("artist-credit", [])[0].get("artist", {}).get("name") if len(a.get("artist-credit", [])) > 0 else None, 'country': a.get("country"), 'day': a.get("date", "")[8:10] if len(a.get("date", "")) == 10 else None, 'disc': None, 'disctitle': None, 'disctotal': None, 'label': a.get("label-info-list", [])[0].get("label", {}).get("name") if len(a.get("label-info-list", [])) > 0 else None, 'language': a.get("text-representation", {}).get("language"), 'length': None, 'mb_albumid': a.get("id"), 'mb_artistid': a.get("artist-credit", [])[0].get("artist", {}).get("id") if len(a.get("artist-credit", [])) > 0 else None, 'mb_releasegroupid': a.get("release-group", {}).get("id"), 'mb_trackid': None, 'media': a.get("packaging"), 'month': a.get("date", "")[5:7] if len(a.get("date", "")) >= 7 else None, 'script': a.get("text-representation", {}).get("script"), 'title': None, 'track': None, 'tracktotal': None, 'year': a.get("date", "")[0:4] if len(a.get("date", "")) >= 4 else None })
def create_item(self, **values): """Return an `Item` instance with sensible default values. The item receives its attributes from `**values` paratmeter. The `title`, `artist`, `album`, `track`, `format` and `path` attributes have defaults if they are not given as parameters. The `title` attribute is formatted with a running item count to prevent duplicates. """ item_count = self._get_item_count() _values = self.default_item_values _values['title'] = _values['title'].format(item_count) _values['track'] = item_count _values.update(values) item = Item(**_values) return item
def test_normal_case_real(self): item = Item(path='/file', mb_workid=u'e27bda6e-531e-36d3-9cd7-b8ebc18e8c53', parentwork_workid_current=u'e27bda6e-531e-36d3-9cd7-\ b8ebc18e8c53') item.add(self.lib) self.run_command('parentwork') item.load() self.assertEqual(item['mb_parentworkid'], u'32c8943f-1b27-3a23-8660-4567f4847c94')
def test_no_force(self): self.config['parentwork']['force'] = True item = Item(path='/file', mb_workid=u'e27bda6e-531e-36d3-9cd7-\ b8ebc18e8c53', mb_parentworkid=u'XXX') item.add(self.lib) self.run_command('parentwork') item.load() self.assertEqual(item['mb_parentworkid'], u'XXX')
def test_force(self): self.config['parentwork']['force'] = True item = Item(path='/file', mb_workid=u'e27bda6e-531e-36d3-9cd7-b8ebc18e8c53', mb_parentworkid=u'XXX') item.add(self.lib) self.run_command('parentwork') item.load() self.assertEqual(item['mb_parentworkid'], u'32c8943f-1b27-3a23-8660-4567f4847c94')
def add_album(self, **kwargs): values = { 'title': 'track 1', 'artist': 'artist 1', 'album': 'album 1', 'format': 'mp3', } values.update(kwargs) ext = values.pop('format').lower() item = Item.from_path(os.path.join(self.fixture_dir, 'min.' + ext)) item.add(self.lib) item.update(values) item.move(copy=True) item.write() album = self.lib.add_album([item]) album.albumartist = item.artist album.store() return album
def test_no_force(self): self.config['parentwork']['force'] = False item = Item(path='/file', mb_workid='1', mb_parentworkid=u'XXX', parentwork_workid_current='1', parentwork='parentwork') item.add(self.lib) self.run_command('parentwork') item.load() self.assertEqual(item['mb_parentworkid'], u'XXX')
def _merge_albums(self, objs): """Merge Album objs by copying missing items from albums in the tail to the head album. Return same number of albums, with the head album modified.""" ids = [i.mb_trackid for i in objs[0].items()] for o in objs[1:]: for i in o.items(): if i.mb_trackid not in ids: missing = Item.from_path(i.path) missing.album_id = objs[0].id missing.add(i._db) self._log.debug( u'item {0} missing from album {1}:' u' merging from {2} into {3}', missing, objs[0], displayable_path(o.path), displayable_path(missing.destination())) missing.move(copy=True) return objs
def test_delete_replaygain_tag(self): path = self.create_mediafile_fixture() item = Item.from_path(path) item.rg_track_peak = 0.0 item.write() mediafile = MediaFile(item.path) self.assertIsNotNone(mediafile.rg_track_peak) self.assertIsNotNone(mediafile.rg_track_gain) config['zero'] = { 'fields': ['rg_track_peak', 'rg_track_gain'], } self.load_plugins('zero') item.write() mediafile = MediaFile(item.path) self.assertIsNone(mediafile.rg_track_peak) self.assertIsNone(mediafile.rg_track_gain)
def test_patch_item_id(self): # Note: PATCH is currently only implemented for track items, not albums web.app.config['READONLY'] = False # Create a temporary item item_id = self.lib.add( Item(title='test_patch_item_id', test_patch_f1=1, test_patch_f2="Old")) # Check we can find the temporary item we just created response = self.client.get('/item/' + str(item_id)) res_json = json.loads(response.data.decode('utf-8')) self.assertEqual(response.status_code, 200) self.assertEqual(res_json['id'], item_id) self.assertEqual( [res_json['test_patch_f1'], res_json['test_patch_f2']], ['1', 'Old']) # Patch item by id # patch_json = json.JSONEncoder().encode({"test_patch_f2": "New"}]}) response = self.client.patch('/item/' + str(item_id), json={"test_patch_f2": "New"}) res_json = json.loads(response.data.decode('utf-8')) self.assertEqual(response.status_code, 200) self.assertEqual(res_json['id'], item_id) self.assertEqual( [res_json['test_patch_f1'], res_json['test_patch_f2']], ['1', 'New']) # Check the update has really worked response = self.client.get('/item/' + str(item_id)) res_json = json.loads(response.data.decode('utf-8')) self.assertEqual(response.status_code, 200) self.assertEqual(res_json['id'], item_id) self.assertEqual( [res_json['test_patch_f1'], res_json['test_patch_f2']], ['1', 'New']) # Remove the item self.lib.get_item(item_id).remove()
def test_hate(self): genre_p = [] artist_p = [] album_p = [] white_p = [] task = ImportTask() task.cur_artist = u'Test Artist' task.cur_album = u'Test Album' task.items = [Item({'genre': 'Test Genre'})] self.assertFalse( IHatePlugin.do_i_hate_this(task, genre_p, artist_p, album_p, white_p)) genre_p = 'some_genre test\sgenre'.split() self.assertTrue( IHatePlugin.do_i_hate_this(task, genre_p, artist_p, album_p, white_p)) genre_p = [] artist_p = 'bad_artist test\sartist' self.assertTrue( IHatePlugin.do_i_hate_this(task, genre_p, artist_p, album_p, white_p)) artist_p = [] album_p = 'tribute christmas test'.split() self.assertTrue( IHatePlugin.do_i_hate_this(task, genre_p, artist_p, album_p, white_p)) album_p = [] white_p = 'goodband test\sartist another_band'.split() genre_p = 'some_genre test\sgenre'.split() self.assertFalse( IHatePlugin.do_i_hate_this(task, genre_p, artist_p, album_p, white_p)) genre_p = [] artist_p = 'bad_artist test\sartist' self.assertFalse( IHatePlugin.do_i_hate_this(task, genre_p, artist_p, album_p, white_p)) artist_p = [] album_p = 'tribute christmas test'.split() self.assertFalse( IHatePlugin.do_i_hate_this(task, genre_p, artist_p, album_p, white_p))
def emitter(included_keys): if included_keys == '*': fields = tag_fields() else: fields = included_keys if 'images' in fields: # We can't serialize the image data. fields.remove('images') mf = mediafile.MediaFile(syspath(path)) tags = {} for field in fields: if field == 'art': tags[field] = mf.art is not None else: tags[field] = getattr(mf, field, None) # create a temporary Item to take advantage of __format__ item = Item.from_path(syspath(path)) return tags, item
def test_update_library(self, track_for_id, album_for_id): album_for_id.return_value = \ generate_album_info( 'album id', [('track id', {'release_track_id': u'release track id'})] ) track_for_id.return_value = \ generate_track_info(u'singleton track id', {'title': u'singleton info'}) album_item = Item(album=u'old title', mb_albumid=u'81ae60d4-5b75-38df-903a-db2cfa51c2c6', mb_trackid=u'old track id', mb_releasetrackid=u'release track id', path='') album = self.lib.add_album([album_item]) item = Item( title=u'old title', mb_trackid=u'b8c2cf90-83f9-3b5f-8ccd-31fb866fcf37', path='', ) self.lib.add(item) with capture_log() as logs: self.run_command('mbsync') self.assertIn('Sending event: albuminfo_received', logs) self.assertIn('Sending event: trackinfo_received', logs) item.load() self.assertEqual(item.title, u'singleton info') album_item.load() self.assertEqual(album_item.title, u'track info') self.assertEqual(album_item.mb_trackid, u'track id') album.load() self.assertEqual(album.album, u'album info')
def _merge_items(self, objs): """Merge Item objs by copying missing fields from items in the tail to the head item. Return same number of items, with the head item modified. """ fields = Item.all_keys() for f in fields: for o in objs[1:]: if getattr(objs[0], f, None) in (None, ''): value = getattr(o, f, None) if value: self._log.debug(u'key {0} on item {1} is null ' u'or empty: setting from item {2}', f, displayable_path(objs[0].path), displayable_path(o.path)) setattr(objs[0], f, value) objs[0].store() break return objs
def test_no_force_real(self): self.config['parentwork']['force'] = False item = Item(path='/file', mb_workid='e27bda6e-531e-36d3-9cd7-\ b8ebc18e8c53', mb_parentworkid='XXX', parentwork_workid_current='e27bda6e-531e-36d3-9cd7-\ b8ebc18e8c53', parentwork='whatever') item.add(self.lib) self.run_command('parentwork') item.load() self.assertEqual(item['mb_parentworkid'], 'XXX')
def _import_mtags(self, lib, opts, args): path, = args paths = [Path(path)] while paths: p = paths.pop(0) for child in p.iterdir(): if child.is_dir(): paths.append(child) continue loader = MTagLoader(child) al = [] for path, data in loader.items(): matching = lib.items(PathQuery('path', path)) if any(m.path == path.encode() for m in matching): continue print('add %r' % path) item = Item(path=path) mf = MediaFile(syspath(item.path)) for field in AUDIO_FIELDS: v = getattr(mf, field) item[field] = v values = {} for tag, converter in TAGS.items(): v = converter.get(data) if v is not None: values[tag] = v item[tag] = v for tag, converter in DEPENDENT_TAGS.items(): v = converter.get(data, values) if v is not None: item[tag] = v al.append(item) if al: #print(al) try: lib.add_album(al) except BaseException as e: import pdb pdb.post_mortem(e.__traceback__) return
def test_search_artist(self): item = Item(artist='Alice ft. Bob', title='song') self.assertIn(('Alice ft. Bob', ['song']), lyrics.search_pairs(item)) self.assertIn(('Alice', ['song']), lyrics.search_pairs(item)) item = Item(artist='Alice feat Bob', title='song') self.assertIn(('Alice feat Bob', ['song']), lyrics.search_pairs(item)) self.assertIn(('Alice', ['song']), lyrics.search_pairs(item)) item = Item(artist='Alice feat. Bob', title='song') self.assertIn(('Alice feat. Bob', ['song']), lyrics.search_pairs(item)) self.assertIn(('Alice', ['song']), lyrics.search_pairs(item)) item = Item(artist='Alice feats Bob', title='song') self.assertIn(('Alice feats Bob', ['song']), lyrics.search_pairs(item)) self.assertNotIn(('Alice', ['song']), lyrics.search_pairs(item)) item = Item(artist='Alice featuring Bob', title='song') self.assertIn(('Alice featuring Bob', ['song']), lyrics.search_pairs(item)) self.assertIn(('Alice', ['song']), lyrics.search_pairs(item)) item = Item(artist='Alice & Bob', title='song') self.assertIn(('Alice & Bob', ['song']), lyrics.search_pairs(item)) self.assertIn(('Alice', ['song']), lyrics.search_pairs(item)) item = Item(artist='Alice and Bob', title='song') self.assertIn(('Alice and Bob', ['song']), lyrics.search_pairs(item)) self.assertIn(('Alice', ['song']), lyrics.search_pairs(item))
def identify_album_from_multiple_paths(paths_list_or_beets_items_list=None, expected_artist=None, expected_album=None, expected_release_id=None): items = paths_list_or_beets_items_list if isinstance(paths_list_or_beets_items_list[0], six.string_types): items = [Item.from_path(x) for x in paths_list_or_beets_items_list if is_media_file(x)] logger.debug("Called with {} items, expected id {}".format(len(items), expected_release_id)) artist_name, album_name, album_recommendation_list, recommendation = \ tag_album(items, search_artist=expected_artist, search_album=expected_album, search_ids=[expected_release_id] if expected_release_id else []) if recommendation is Recommendation.none: return None, None distance, album_info, track_mapping, extra_items, extra_tracks = album_recommendation_list[0] logger.debug('Successfully matched album {} !'.format(album_info.album_id)) logger.info("Successfully tagged album {album_id}, releasegroup {rgid}".format(album_id=album_info.album_id, rgid=album_info.releasegroup_id)) return album_info, track_mapping
def test_delete_item_id(self): web.app.config['READONLY'] = False # Create a temporary item item_id = self.lib.add( Item(title='test_delete_item_id', test_delete_item_id=1)) # Check we can find the temporary item we just created response = self.client.get('/item/' + str(item_id)) res_json = json.loads(response.data.decode('utf-8')) self.assertEqual(response.status_code, 200) self.assertEqual(res_json['id'], item_id) # Delete item by id response = self.client.delete('/item/' + str(item_id)) res_json = json.loads(response.data.decode('utf-8')) self.assertEqual(response.status_code, 200) # Check the item has gone response = self.client.get('/item/' + str(item_id)) self.assertEqual(response.status_code, 404)
def test_hate(self): match_pattern = {} test_item = Item( genre='TestGenre', album=u'TestAlbum', artist=u'TestArtist') task = importer.ImportTask() task.items = [test_item] task.item = test_item task.is_album = False # Empty query should let it pass. self.assertFalse(IHatePlugin.do_i_hate_this(task, match_pattern)) # 1 query match. match_pattern = ["artist:bad_artist","artist:TestArtist"] self.assertTrue(IHatePlugin.do_i_hate_this(task, match_pattern)) # 2 query matches, either should trigger. match_pattern = ["album:test","artist:testartist"] self.assertTrue(IHatePlugin.do_i_hate_this(task, match_pattern)) # Query is blocked by AND clause. match_pattern = ["album:notthis genre:testgenre"] self.assertFalse(IHatePlugin.do_i_hate_this(task, match_pattern)) # Both queries are blocked by AND clause with unmatched condition. match_pattern = ["album:notthis genre:testgenre", "artist:testartist album:notthis"] self.assertFalse(IHatePlugin.do_i_hate_this(task, match_pattern)) # Only one query should fire. match_pattern = ["album:testalbum genre:testgenre", "artist:testartist album:notthis"] self.assertTrue(IHatePlugin.do_i_hate_this(task, match_pattern))
def create_track(self, hgid, hid, tmpfname, path): """ Creates the data corresponding to the track in impala associated with the holding uuid based on metadata gleaned from beets. If it fails, raises an exception. """ try: # In the event the item isn't a music track, we need to prevent it # from getting added to impala but keep it in moss. i = Item.from_path(tmpfname) except: return # Create a stack and format if they don't already exist self._create_default_objects() # Create the holding group if it doesn't already exist self._create_holding_group(hgid, i) # Create the holding if it doesn't already exist self._create_holding(hgid, hid, i) # Create the track self._create_track(hid, path, i)
def test_delete_item_query(self): web.app.config['READONLY'] = False # Create a temporary item self.lib.add( Item(title='test_delete_item_query', test_delete_item_query=1)) # Check we can find the temporary item we just created response = self.client.get('/item/query/test_delete_item_query') res_json = json.loads(response.data.decode('utf-8')) self.assertEqual(response.status_code, 200) self.assertEqual(len(res_json['results']), 1) # Delete item by query response = self.client.delete('/item/query/test_delete_item_query') res_json = json.loads(response.data.decode('utf-8')) self.assertEqual(response.status_code, 200) # Check the item has gone response = self.client.get('/item/query/test_delete_item_query') res_json = json.loads(response.data.decode('utf-8')) self.assertEqual(response.status_code, 200) self.assertEqual(len(res_json['results']), 0)