Example #1
0
 def write(self):
     """Writes the item's metadata to the associated file.
     """
     f = MediaFile(_syspath(self.path))
     for key in ITEM_KEYS_WRITABLE:
         setattr(f, key, getattr(self, key))
     f.save()
Example #2
0
    def create_importer(self, item_count=1, album_count=1):
        """Returns import session with fixtures.

        Copies the specified number of files to a subdirectory of
        ``self.temp_dir`` and creates a ``TestImportSession`` for this
        path.
        """
        import_dir = os.path.join(self.temp_dir, 'import')
        if not os.path.isdir(import_dir):
            os.mkdir(import_dir)

        for i in range(album_count):
            album = u'album {0}'.format(i)
            album_dir = os.path.join(import_dir, album)
            os.mkdir(album_dir)
            for j in range(item_count):
                title = 'track {0}'.format(j)
                src = os.path.join(_common.RSRC, 'full.mp3')
                dest = os.path.join(album_dir, '{0}.mp3'.format(title))
                shutil.copy(src, dest)
                mediafile = MediaFile(dest)
                mediafile.update({'title': title, 'album': album})
                mediafile.save()

        config['import']['quiet'] = True
        config['import']['autotag'] = False
        config['import']['resume'] = False

        return TestImportSession(self.lib, logfile=None, query=None,
                                 paths=[import_dir])
Example #3
0
def embedLyrics(downloaded_track_list):
    logger.info('Adding lyrics')
    
    # TODO: If adding lyrics for flac & lossy, only fetch the lyrics once
    # and apply it to both files
    for downloaded_track in downloaded_track_list:
        
        try:
            f = MediaFile(downloaded_track)
        except:
            logger.error('Could not read %s. Not checking lyrics', downloaded_track.decode(headphones.SYS_ENCODING, 'replace'))
            continue
            
        if f.albumartist and f.title:
            metalyrics = lyrics.getLyrics(f.albumartist, f.title)
        elif f.artist and f.title:
            metalyrics = lyrics.getLyrics(f.artist, f.title)
        else:
            logger.info('No artist/track metadata found for track: %s. Not fetching lyrics', downloaded_track.decode(headphones.SYS_ENCODING, 'replace'))
            metalyrics = None
            
        if lyrics:
            logger.debug('Adding lyrics to: %s', downloaded_track.decode(headphones.SYS_ENCODING, 'replace'))
            f.lyrics = metalyrics
            try:
                f.save()
            except:
                logger.error('Cannot save lyrics to: %s. Skipping', downloaded_track.decode(headphones.SYS_ENCODING, 'replace'))
                continue
Example #4
0
    def write(self, path=None):
        """Write the item's metadata to a media file.

        All fields in `_media_fields` are written to disk according to
        the values on this object.

        Can raise either a `ReadError` or a `WriteError`.
        """
        if path is None:
            path = self.path
        else:
            path = normpath(path)

        tags = dict(self)
        plugins.send('write', item=self, path=path, tags=tags)

        try:
            mediafile = MediaFile(syspath(path),
                                  id3v23=beets.config['id3v23'].get(bool))
        except (OSError, IOError, UnreadableFileError) as exc:
            raise ReadError(self.path, exc)

        mediafile.update(tags)
        try:
            mediafile.save()
        except (OSError, IOError, MutagenError) as exc:
            raise WriteError(self.path, exc)

        # The file has a new mtime.
        if path == self.path:
            self.mtime = self.current_mtime()
        plugins.send('after_write', item=self, path=path)
Example #5
0
    def create_mediafile_fixture(self, ext='mp3', images=[]):
        """Copies a fixture mediafile with the extension to a temporary
        location and returns the path.

        It keeps track of the created locations and will delete the with
        `remove_mediafile_fixtures()`

        `images` is a subset of 'png', 'jpg', and 'tiff'. For each
        specified extension a cover art image is added to the media
        file.
        """
        src = os.path.join(_common.RSRC, 'full.' + ext)
        handle, path = mkstemp()
        os.close(handle)
        shutil.copyfile(src, path)

        if images:
            mediafile = MediaFile(path)
            imgs = []
            for img_ext in images:
                img_path = os.path.join(_common.RSRC,
                                        'image-2x3.{0}'.format(img_ext))
                with open(img_path, 'rb') as f:
                    imgs.append(Image(f.read()))
            mediafile.images = imgs
            mediafile.save()

        if not hasattr(self, '_mediafile_fixtures'):
            self._mediafile_fixtures = []
        self._mediafile_fixtures.append(path)

        return path
Example #6
0
 def test_modified_metadata_detected(self):
     mf = MediaFile(self.i.path)
     mf.title = 'differentTitle'
     mf.save()
     self._update()
     item = self.lib.items().next()
     self.assertEqual(item.title, 'differentTitle')
Example #7
0
 def test_modified_metadata_moved(self):
     mf = MediaFile(self.i.path)
     mf.title = u'differentTitle'
     mf.save()
     self._update(move=True)
     item = self.lib.items().get()
     self.assertTrue(b'differentTitle' in item.path)
Example #8
0
 def test_modified_metadata_not_moved(self):
     mf = MediaFile(self.i.path)
     mf.title = 'differentTitle'
     mf.save()
     self._update(move=False)
     item = self.lib.items().next()
     self.assertTrue('differentTitle' not in item.path)
Example #9
0
 def test_modified_album_metadata_moved(self):
     mf = MediaFile(self.i.path)
     mf.album = 'differentAlbum'
     mf.save()
     self._update(move=True)
     item = self.lib.items().next()
     self.assertTrue('differentAlbum' in item.path)
Example #10
0
    def write(self, path=None):
        """Write the item's metadata to a media file.

        Updates the mediafile with properties from itself.

        Can raise either a `ReadError` or a `WriteError`.
        """
        if path is None:
            path = self.path
        else:
            path = normpath(path)
        try:
            mediafile = MediaFile(path)
        except (OSError, IOError) as exc:
            raise ReadError(self.path, exc)

        plugins.send('write', item=self, path=path)

        try:
            mediafile.update(self, id3v23=beets.config['id3v23'].get(bool))
        except (OSError, IOError, MutagenError) as exc:
            raise WriteError(self.path, exc)

        # The file has a new mtime.
        if path == self.path:
            self.mtime = self.current_mtime()
        plugins.send('after_write', item=self, path=path)
Example #11
0
    def write(self, path=None):
        """Write the item's metadata to a media file.

        ``path`` defaults to the item's path property.

        Can raise either a `ReadError` or a `WriteError`.
        """
        if path is None:
            path = self.path
        else:
            path = normpath(path)
        try:
            f = MediaFile(syspath(path))
        except (OSError, IOError) as exc:
            raise ReadError(self.path, exc)

        plugins.send('write', item=self, path=path)

        for key in ITEM_KEYS_WRITABLE:
            setattr(f, key, self[key])
        try:
            f.save(id3v23=beets.config['id3v23'].get(bool))
        except (OSError, IOError, MutagenError) as exc:
            raise WriteError(self.path, exc)

        # The file has a new mtime.
        self.mtime = self.current_mtime()
        plugins.send('after_write', item=self)
Example #12
0
 def test_modified_album_metadata_art_moved(self):
     artpath = self.album.artpath
     mf = MediaFile(self.i.path)
     mf.album = 'differentAlbum'
     mf.save()
     self._update(move=True)
     album = self.lib.albums()[0]
     self.assertNotEqual(artpath, album.artpath)
Example #13
0
 def test_selective_modified_metadata_moved(self):
     mf = MediaFile(syspath(self.i.path))
     mf.title = u'differentTitle'
     mf.genre = u'differentGenre'
     mf.save()
     self._update(move=True, fields=['title'])
     item = self.lib.items().get()
     self.assertTrue(b'differentTitle' in item.path)
     self.assertNotEqual(item.genre, u'differentGenre')
Example #14
0
 def __copy_file(self, dest_path, metadata):
     # Copy files
     resource_path = os.path.join(RSRC, b'full.mp3')
     shutil.copy(resource_path, dest_path)
     medium = MediaFile(dest_path)
     # Set metadata
     for attr in metadata:
         setattr(medium, attr, metadata[attr])
     medium.save()
Example #15
0
    def test_asis_updates_metadata(self):
        self.setup_importer.run()
        medium = MediaFile(self.lib.items().get().path)
        medium.title = 'New Title'
        medium.save()

        self.importer.add_choice(importer.action.ASIS)
        self.importer.run()
        self.assertEqual(self.lib.items().get().title, 'New Title')
Example #16
0
 def test_selective_modified_album_metadata_not_moved(self):
     mf = MediaFile(syspath(self.i.path))
     mf.album = u'differentAlbum'
     mf.genre = u'differentGenre'
     mf.save()
     self._update(move=True, fields=['genre'])
     item = self.lib.items().get()
     self.assertTrue(b'differentAlbum' not in item.path)
     self.assertEqual(item.genre, u'differentGenre')
Example #17
0
    def write(self):
        """Writes the item's metadata to the associated file.
        """
        f = MediaFile(syspath(self.path))
        for key in ITEM_KEYS_WRITABLE:
            setattr(f, key, getattr(self, key))
        f.save()

        # The file has a new mtime.
        self.mtime = self.current_mtime()
Example #18
0
    def test_mtime_match_skips_update(self):
        mf = MediaFile(self.i.path)
        mf.title = 'differentTitle'
        mf.save()

        # Make in-memory mtime match on-disk mtime.
        self.i.mtime = os.path.getmtime(self.i.path)
        self.lib.store(self.i)

        self._update(reset_mtime=False)
        item = self.lib.items().next()
        self.assertEqual(item.title, 'full')
Example #19
0
    def test_delete_art(self):
        mediafile = self._mediafile_fixture('empty')
        mediafile.art = self.jpg_data
        mediafile.save()

        mediafile = MediaFile(mediafile.path)
        self.assertIsNotNone(mediafile.art)

        del mediafile.art
        mediafile.save()

        mediafile = MediaFile(mediafile.path)
        self.assertIsNone(mediafile.art)
Example #20
0
    def test_asis_updated_moves_file(self):
        self.setup_importer.run()
        medium = MediaFile(self.lib.items().get().path)
        medium.title = "New Title"
        medium.save()

        old_path = os.path.join("Applied Artist", "Applied Album", "Applied Title 1.mp3")
        self.assert_file_in_lib(old_path)

        self.importer.add_choice(importer.action.ASIS)
        self.importer.run()
        self.assert_file_in_lib("Applied Artist", "Applied Album", "New Title.mp3")
        self.assert_file_not_in_lib(old_path)
Example #21
0
    def create_importer(self, item_count=1, album_count=1):
        """Create files to import and return corresponding session.

        Copies the specified number of files to a subdirectory of
        `self.temp_dir` and creates a `TestImportSession` for this path.
        """
        import_dir = os.path.join(self.temp_dir, b'import')
        if not os.path.isdir(import_dir):
            os.mkdir(import_dir)

        album_no = 0
        while album_count:
            album = util.bytestring_path(u'album {0}'.format(album_no))
            album_dir = os.path.join(import_dir, album)
            if os.path.exists(album_dir):
                album_no += 1
                continue
            os.mkdir(album_dir)
            album_count -= 1

            track_no = 0
            album_item_count = item_count
            while album_item_count:
                title = u'track {0}'.format(track_no)
                src = os.path.join(_common.RSRC, b'full.mp3')
                title_file = util.bytestring_path('{0}.mp3'.format(title))
                dest = os.path.join(album_dir, title_file)
                if os.path.exists(dest):
                    track_no += 1
                    continue
                album_item_count -= 1
                shutil.copy(src, dest)
                mediafile = MediaFile(dest)
                mediafile.update({
                    'artist': 'artist',
                    'albumartist': 'album artist',
                    'title': title,
                    'album': album,
                    'mb_albumid': None,
                    'mb_trackid': None,
                })
                mediafile.save()

        config['import']['quiet'] = True
        config['import']['autotag'] = False
        config['import']['resume'] = False

        return TestImportSession(self.lib, loghandler=None, query=None,
                                 paths=[import_dir])
Example #22
0
    def __init__(self):
        super(ZeroPlugin, self).__init__()

        # Listeners.
        self.register_listener('write', self.write_event)
        self.register_listener('import_task_choice',
                               self.import_task_choice_event)

        self.config.add({
            'fields': [],
            'update_database': False,
        })

        self.patterns = {}
        self.warned = False

        for field in self.config['fields'].as_str_seq():
            if field in ('id', 'path', 'album_id'):
                self._log.warn(u'field \'{0}\' ignored, zeroing '
                               u'it would be dangerous', field)
                continue
            if field not in MediaFile.fields():
                self._log.error(u'invalid field: {0}', field)
                continue

            try:
                self.patterns[field] = self.config[field].as_str_seq()
            except confit.NotFoundError:
                # Matches everything
                self.patterns[field] = True
Example #23
0
    def __init__(self):
        super(ZeroPlugin, self).__init__()

        # Listeners.
        self.register_listener("write", self.write_event)
        self.register_listener("import_task_choice", self.import_task_choice_event)

        self.config.add({"fields": [], "keep_fields": [], "update_database": False})

        self.patterns = {}
        self.warned = False

        # We'll only handle `fields` or `keep_fields`, but not both.
        if self.config["fields"] and self.config["keep_fields"]:
            self._log.warn("cannot blacklist and whitelist at the same time")

        # Blacklist mode.
        if self.config["fields"]:
            self.validate_config("fields")
            for field in self.config["fields"].as_str_seq():
                self.set_pattern(field)

        # Whitelist mode.
        elif self.config["keep_fields"]:
            self.validate_config("keep_fields")

            for field in MediaFile.fields():
                if field in self.config["keep_fields"].as_str_seq():
                    continue
                self.set_pattern(field)

            # These fields should always be preserved.
            for key in ("id", "path", "album_id"):
                if key in self.patterns:
                    del self.patterns[key]
Example #24
0
    def test_asis_updated_without_copy_does_not_move_file(self):
        self.setup_importer.run()
        medium = MediaFile(self.lib.items().get().path)
        medium.title = 'New Title'
        medium.save()

        old_path = os.path.join('Applied Artist', 'Applied Album',
                                'Applied Title 1.mp3')
        self.assert_file_in_lib(old_path)

        config['import']['copy'] = False
        self.importer.add_choice(importer.action.ASIS)
        self.importer.run()
        self.assert_file_not_in_lib('Applied Artist', 'Applied Album',
                                    'New Title.mp3')
        self.assert_file_in_lib(old_path)
Example #25
0
    def _create_import_dir(self, count=3):
        """Creates a directory with media files to import.
        Sets ``self.import_dir`` to the path of the directory. Also sets
        ``self.import_media`` to a list :class:`MediaFile` for all the files in
        the directory.

        The directory has following layout
          the_album/
            track_1.mp3
            track_2.mp3
            track_3.mp3

        :param count:  Number of files to create
        """
        self.import_dir = os.path.join(self.temp_dir, 'testsrcdir')
        if os.path.isdir(self.import_dir):
            shutil.rmtree(self.import_dir)

        album_path = os.path.join(self.import_dir, 'the_album')
        os.makedirs(album_path)

        resource_path = os.path.join(_common.RSRC, 'full.mp3')

        metadata = {
            'artist': 'Tag Artist',
            'album':  'Tag Album',
            'albumartist':  None,
            'mb_trackid': None,
            'mb_albumid': None,
            'comp': None
        }
        self.media_files = []
        for i in range(count):
            # Copy files
            medium_path = os.path.join(album_path, 'track_%d.mp3' % (i + 1))
            shutil.copy(resource_path, medium_path)
            medium = MediaFile(medium_path)

            # Set metadata
            metadata['track'] = i + 1
            metadata['title'] = 'Tag Title %d' % (i + 1)
            for attr in metadata:
                setattr(medium, attr, metadata[attr])
            medium.save()
            self.media_files.append(medium)
        self.import_media = self.media_files
Example #26
0
    def write(self, path=None, tags=None):
        """Write the item's metadata to a media file.

        All fields in `_media_fields` are written to disk according to
        the values on this object.

        `path` is the path of the mediafile to write the data to. It
        defaults to the item's path.

        `tags` is a dictionary of additional metadata the should be
        written to the file. (These tags need not be in `_media_fields`.)

        Can raise either a `ReadError` or a `WriteError`.
        """
        if path is None:
            path = self.path
        else:
            path = normpath(path)

        # Get the data to write to the file.
        item_tags = dict(self)
        item_tags = {k: v for k, v in item_tags.items()
                     if k in self._media_fields}  # Only write media fields.
        if tags is not None:
            item_tags.update(tags)
        plugins.send('write', item=self, path=path, tags=item_tags)

        # Open the file.
        try:
            mediafile = MediaFile(syspath(path),
                                  id3v23=beets.config['id3v23'].get(bool))
        except (OSError, IOError, UnreadableFileError) as exc:
            raise ReadError(self.path, exc)

        # Write the tags to the file.
        mediafile.update(item_tags)
        try:
            mediafile.save()
        except (OSError, IOError, MutagenError) as exc:
            raise WriteError(self.path, exc)

        # The file has a new mtime.
        if path == self.path:
            self.mtime = self.current_mtime()
        plugins.send('after_write', item=self, path=path)
Example #27
0
    def test_delete_partial_date(self):
        mediafile = self._mediafile_fixture('empty')

        mediafile.date = datetime.date(2001, 12, 3)
        mediafile.save()
        mediafile = MediaFile(mediafile.path)
        self.assertIsNotNone(mediafile.date)
        self.assertIsNotNone(mediafile.year)
        self.assertIsNotNone(mediafile.month)
        self.assertIsNotNone(mediafile.day)

        delattr(mediafile, 'month')
        mediafile.save()
        mediafile = MediaFile(mediafile.path)
        self.assertIsNotNone(mediafile.date)
        self.assertIsNotNone(mediafile.year)
        self.assertIsNone(mediafile.month)
        self.assertIsNone(mediafile.day)
Example #28
0
def embedAlbumArt(artwork, downloaded_track_list):
    logger.info('Embedding album art')
    
    for downloaded_track in downloaded_track_list:
        try:
            f = MediaFile(downloaded_track)
        except:
            logger.error(u'Could not read %s. Not adding album art' % downloaded_track.decode(headphones.SYS_ENCODING, 'replace'))
            continue
            
        logger.debug('Adding album art to: %s' % downloaded_track)
        
        try:
            f.art = artwork
            f.save()
        except Exception, e:
            logger.error(u'Error ebedding album art to: %s. Error: %s' % (downloaded_track.decode(headphones.SYS_ENCODING, 'replace'), str(e)))
            continue
Example #29
0
    def test_collect_item_and_path(self):
        path = self.create_mediafile_fixture()
        mediafile = MediaFile(path)
        item, = self.add_item_fixtures()

        item.album = mediafile.album = 'AAA'
        item.tracktotal = mediafile.tracktotal = 5
        item.title = 'TTT'
        mediafile.title = 'SSS'

        item.write()
        item.store()
        mediafile.save()

        out = self.run_with_output('--summarize', 'album:AAA', path)
        self.assertIn('album: AAA', out)
        self.assertIn('tracktotal: 5', out)
        self.assertIn('title: [various]', out)
Example #30
0
    def test_collect_item_and_path(self):
        path = self.create_mediafile_fixture()
        mediafile = MediaFile(path)
        item, = self.add_item_fixtures()

        item.album = mediafile.album = "AAA"
        item.tracktotal = mediafile.tracktotal = 5
        item.title = "TTT"
        mediafile.title = "SSS"

        item.write()
        item.store()
        mediafile.save()

        out = self.run_with_output("info", "--summarize", "album:AAA", path)
        self.assertIn(u"album: AAA", out)
        self.assertIn(u"tracktotal: 5", out)
        self.assertIn(u"title: [various]", out)
        self.remove_mediafile_fixtures()
Example #31
0
    def test_path(self):
        path = self.create_mediafile_fixture()

        mediafile = MediaFile(path)
        mediafile.albumartist = 'AAA'
        mediafile.disctitle = 'DDD'
        mediafile.genres = ['a', 'b', 'c']
        mediafile.composer = None
        mediafile.save()

        out = self.run_with_output('info', path)
        self.assertIn(path, out)
        self.assertIn('albumartist: AAA', out)
        self.assertIn('disctitle: DDD', out)
        self.assertIn('genres: a; b; c', out)
        self.assertNotIn('composer:', out)
        self.remove_mediafile_fixtures()
Example #32
0
    def test_overwrite_full(self):
        mediafile = self._mediafile_fixture('full')
        tags = self._generate_tags()

        for key, value in tags.items():
            setattr(mediafile, key, value)
        mediafile.save()

        # Make sure the tags are already set when writing a second time
        for key, value in tags.items():
            setattr(mediafile, key, value)
        mediafile.save()

        mediafile = MediaFile(mediafile.path)
        self.assertTags(mediafile, tags)
Example #33
0
    def test_write_dates(self):
        mediafile = self._mediafile_fixture('full')
        mediafile.date = datetime.date(2001, 1, 2)
        mediafile.original_date = datetime.date(1999, 12, 30)
        mediafile.save()

        mediafile = MediaFile(mediafile.path)
        self.assertEqual(mediafile.year, 2001)
        self.assertEqual(mediafile.month, 1)
        self.assertEqual(mediafile.day, 2)
        self.assertEqual(mediafile.date, datetime.date(2001, 1, 2))
        self.assertEqual(mediafile.original_year, 1999)
        self.assertEqual(mediafile.original_month, 12)
        self.assertEqual(mediafile.original_day, 30)
        self.assertEqual(mediafile.original_date, datetime.date(1999, 12, 30))
Example #34
0
    def test_embed_non_image_file(self):
        album = self.add_album_fixture()
        logging.getLogger('beets.embedart').setLevel(logging.DEBUG)

        handle, tmp_path = tempfile.mkstemp()
        os.write(handle, 'I am not an image.')
        os.close(handle)

        try:
            self.run_command('embedart', '-f', tmp_path)
        finally:
            os.remove(tmp_path)

        mediafile = MediaFile(syspath(album.items()[0].path))
        self.assertFalse(mediafile.images)  # No image added.
Example #35
0
    def validate_config(self, mode):
        """Check whether fields in the configuration are valid.

        `mode` should either be "fields" or "keep_fields", indicating
        the section of the configuration to validate.
        """
        for field in self.config[mode].as_str_seq():
            if field not in MediaFile.fields():
                self._log.error(u'invalid field: {0}', field)
                continue
            if mode == 'fields' and field in ('id', 'path', 'album_id'):
                self._log.warning(
                    u'field \'{0}\' ignored, zeroing '
                    u'it would be dangerous', field)
                continue
Example #36
0
    def test_extended_field_write(self):
        plugin = BeetsPlugin()
        plugin.add_media_field('customtag', field_extension)

        try:
            mediafile = self._mediafile_fixture('empty')
            mediafile.customtag = u'F#'
            mediafile.save()

            mediafile = MediaFile(mediafile.path)
            self.assertEqual(mediafile.customtag, u'F#')

        finally:
            delattr(MediaFile, 'customtag')
            Item._media_fields.remove('customtag')
Example #37
0
    def test_set_image_structure(self):
        mediafile = self._mediafile_fixture('empty')
        image = Image(data=self.png_data, desc=u'album cover',
                      type=ImageType.front)
        mediafile.images = [image]
        mediafile.save()

        mediafile = MediaFile(mediafile.path)
        self.assertEqual(len(mediafile.images), 1)

        image = mediafile.images[0]
        self.assertEqual(image.data, self.png_data)
        self.assertEqual(image.mime_type, 'image/png')
        self.assertExtendedImageAttributes(image, desc=u'album cover',
                                           type=ImageType.front)
Example #38
0
    def test_cli_saves_track_gain(self):
        for item in self.lib.items():
            self.assertIsNone(item.rg_track_peak)
            self.assertIsNone(item.rg_track_gain)
            mediafile = MediaFile(item.path)
            self.assertIsNone(mediafile.rg_track_peak)
            self.assertIsNone(mediafile.rg_track_gain)

        self.run_command('replaygain')

        # Skip the test if rg_track_peak and rg_track gain is None, assuming
        # that it could only happen if the decoder plugins are missing.
        if all(i.rg_track_peak is None and i.rg_track_gain is None
               for i in self.lib.items()):
            self.skipTest('decoder plugins could not be loaded.')

        for item in self.lib.items():
            self.assertIsNotNone(item.rg_track_peak)
            self.assertIsNotNone(item.rg_track_gain)
            mediafile = MediaFile(item.path)
            self.assertAlmostEqual(
                mediafile.rg_track_peak, item.rg_track_peak, places=6)
            self.assertAlmostEqual(
                mediafile.rg_track_gain, item.rg_track_gain, places=2)
Example #39
0
    def test_no_fields(self):
        item = self.add_item_fixture(year=2016)
        item.write()
        mediafile = MediaFile(syspath(item.path))
        self.assertEqual(mediafile.year, 2016)

        item_id = item.id

        self.load_plugins('zero')
        with control_stdin('y'):
            self.run_command('zero')

        item = self.lib.get_item(item_id)

        self.assertEqual(item['year'], 2016)
        self.assertEqual(mediafile.year, 2016)
Example #40
0
    def test_write_extended_tag_from_item(self):
        plugin = BeetsPlugin()
        plugin.add_media_field('customtag', field_extension)

        try:
            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')

        finally:
            delattr(MediaFile, 'customtag')
            Item._media_fields.remove('customtag')
Example #41
0
    def test_add_image_structure(self):
        mediafile = self._mediafile_fixture('image')
        self.assertEqual(len(mediafile.images), 2)

        image = Image(data=self.png_data, desc='the composer',
                         type=ImageType.composer)
        mediafile.images += [image]
        mediafile.save()

        mediafile = MediaFile(mediafile.path)
        self.assertEqual(len(mediafile.images), 3)

        image = next(
           (i for i in mediafile.images if i.desc == 'the composer'), None)
        self.assertExtendedImageAttributes(image,
                desc='the composer', type=ImageType.composer)
Example #42
0
    def test_move_and_write_after_tags_changed(self):
        item = self.add_external_track('myexternal')
        old_path = self.get_path(item)
        self.assertIsFile(old_path)

        item['title'] = 'a new title'
        item.store()
        item.try_write()  # Required to update mtime.
        self.runcli('alt', 'update', 'myexternal')

        item.load()
        new_path = self.get_path(item)
        self.assertIsNotFile(old_path)
        self.assertIsFile(new_path)
        mediafile = MediaFile(syspath(new_path))
        self.assertEqual(mediafile.title, 'a new title')
Example #43
0
    def test_add_tiff_image(self):
        mediafile = self._mediafile_fixture('image')
        self.assertEqual(len(mediafile.images), 2)

        image = Image(data=self.tiff_data, desc='the composer',
                         type=ImageType.composer)
        mediafile.images += [image]
        mediafile.save()

        mediafile = MediaFile(mediafile.path)
        self.assertEqual(len(mediafile.images), 3)

        # WMA does not preserve the order, so we have to work around this
        image = filter(lambda i: i.mime_type == 'image/tiff',
                           mediafile.images)[0]
        self.assertExtendedImageAttributes(image,
                desc='the composer', type=ImageType.composer)
Example #44
0
    def read(self, read_path=None):
        """Read the metadata from the associated file. If read_path is
        specified, read metadata from that file instead.
        """
        if read_path is None:
            read_path = self.path
        else:
            read_path = normpath(read_path)
        f = MediaFile(syspath(read_path))

        for key in ITEM_KEYS_META:
            setattr(self, key, getattr(f, key))
        self.path = read_path

        # Database's mtime should now reflect the on-disk value.
        if read_path == self.path:
            self.mtime = self.current_mtime()
Example #45
0
def updateFormat():
    myDB = db.DBConnection()
    tracks = myDB.select(
        'SELECT * from tracks WHERE Location IS NOT NULL and Format IS NULL')
    if len(tracks) > 0:
        logger.info('Finding media format for %s files' % len(tracks))
        for track in tracks:
            try:
                f = MediaFile(track['Location'])
            except Exception, e:
                logger.info("Exception from MediaFile for: " +
                            track['Location'] + " : " + str(e))
                continue
            controlValueDict = {"TrackID": track['TrackID']}
            newValueDict = {"Format": f.format}
            myDB.upsert("tracks", newValueDict, controlValueDict)
        logger.info('Finished finding media format for %s files' % len(tracks))
Example #46
0
 def _set_pattern(self, field):
     """Populate `self.fields_to_progs` for a given field.
     Do some sanity checks then compile the regexes.
     """
     if field not in MediaFile.fields():
         self._log.error(u'invalid field: {0}', field)
     elif field in ('id', 'path', 'album_id'):
         self._log.warning(
             u'field \'{0}\' ignored, zeroing '
             u'it would be dangerous', field)
     else:
         try:
             for pattern in self.config[field].as_str_seq():
                 prog = re.compile(pattern, re.IGNORECASE)
                 self.fields_to_progs.setdefault(field, []).append(prog)
         except confit.NotFoundError:
             # Matches everything
             self.fields_to_progs[field] = []
Example #47
0
    def test_whitelist_and_blacklist(self):
        item = self.add_item_fixture(year=2016)
        item.write()
        mf = MediaFile(syspath(item.path))
        self.assertEqual(mf.year, 2016)

        item_id = item.id
        self.config['zero']['fields'] = [u'year']
        self.config['zero']['keep_fields'] = [u'comments']

        self.load_plugins('zero')
        with control_stdin('y'):
            self.run_command('zero')

        item = self.lib.get_item(item_id)

        self.assertEqual(item['year'], 2016)
        self.assertEqual(mf.year, 2016)
Example #48
0
    def test_write_counters_without_total(self):
        mediafile = self._mediafile_fixture('full')
        self.assertEqual(mediafile.track, 2)
        self.assertEqual(mediafile.tracktotal, 3)
        self.assertEqual(mediafile.disc, 4)
        self.assertEqual(mediafile.disctotal, 5)

        mediafile.track = 10
        delattr(mediafile, 'tracktotal')
        mediafile.disc = 10
        delattr(mediafile, 'disctotal')
        mediafile.save()

        mediafile = MediaFile(mediafile.path)
        self.assertEqual(mediafile.track, 10)
        self.assertEqual(mediafile.tracktotal, None)
        self.assertEqual(mediafile.disc, 10)
        self.assertEqual(mediafile.disctotal, None)
Example #49
0
    def test_delete_art(self):
        mediafile = self._mediafile_fixture('empty')
        mediafile.art = self.jpg_data
        mediafile.save()

        mediafile = MediaFile(mediafile.path)
        self.assertIsNotNone(mediafile.art)

        del mediafile.art
        mediafile.save()

        mediafile = MediaFile(mediafile.path)
        self.assertIsNone(mediafile.art)
Example #50
0
    def create_importer(self, item_count=1, album_count=1):
        """Create files to import and return corresponding session.

        Copies the specified number of files to a subdirectory of
        `self.temp_dir` and creates a `TestImportSession` for this path.
        """
        import_dir = os.path.join(self.temp_dir, b'import')
        if not os.path.isdir(import_dir):
            os.mkdir(import_dir)

        album_no = 0
        while album_count:
            album = util.bytestring_path(u'album {0}'.format(album_no))
            album_dir = os.path.join(import_dir, album)
            if os.path.exists(album_dir):
                album_no += 1
                continue
            os.mkdir(album_dir)
            album_count -= 1

            track_no = 0
            album_item_count = item_count
            while album_item_count:
                title = u'track {0}'.format(track_no)
                src = os.path.join(_common.RSRC, b'full.mp3')
                title_file = util.bytestring_path('{0}.mp3'.format(title))
                dest = os.path.join(album_dir, title_file)
                if os.path.exists(dest):
                    track_no += 1
                    continue
                album_item_count -= 1
                shutil.copy(src, dest)
                mediafile = MediaFile(dest)
                mediafile.update({
                    'artist': 'artist',
                    'albumartist': 'album artist',
                    'title': title,
                    'album': album,
                    'mb_albumid': None,
                    'mb_trackid': None,
                })
                mediafile.save()

        config['import']['quiet'] = True
        config['import']['autotag'] = False
        config['import']['resume'] = False

        return TestImportSession(self.lib,
                                 loghandler=None,
                                 query=None,
                                 paths=[import_dir])
Example #51
0
    def test_no_patterns(self):
        self.config['zero']['fields'] = ['comments', 'month']

        item = self.add_item_fixture(
            comments=u'test comment',
            title=u'Title',
            month=1,
            year=2000,
        )
        item.write()

        self.load_plugins('zero')
        item.write()

        mf = MediaFile(syspath(item.path))
        self.assertIsNone(mf.comments)
        self.assertIsNone(mf.month)
        self.assertEqual(mf.title, u'Title')
        self.assertEqual(mf.year, 2000)
Example #52
0
    def test_subcommand_query_exclude(self):
        item = self.add_item_fixture(year=2016,
                                     day=13,
                                     month=3,
                                     comments=u'test comment')

        item.write()

        self.config['zero']['fields'] = ['comments']
        self.config['zero']['update_database'] = False
        self.config['zero']['auto'] = False

        self.load_plugins('zero')
        self.run_command('zero', 'year: 0000')

        mf = MediaFile(syspath(item.path))

        self.assertEqual(mf.year, 2016)
        self.assertEqual(mf.comments, u'test comment')
Example #53
0
    def album_imported(self, lib, album):
        self.write_album = True

        print_("Tagging Replay Gain:  %s - %s" %
               (album.albumartist, album.album))

        try:
            media_files = [MediaFile(item.path) for item in album.items()]
            media_files = [mf for mf in media_files if self.requires_gain(mf)]

            #calculate gain. Return value - track_data: array dictionary indexed by filename
            track_data, album_data = rgcalc.calculate(
                [mf.path for mf in media_files], True, self.ref_level)

            for mf in media_files:
                self.write_gain(mf, track_data, album_data)

        except (FileTypeError, UnreadableFileError, TypeError, ValueError), e:
            log.error("failed to calculate replaygain:  %s ", e)
Example #54
0
    def test_convert_write_tags(self):
        item = self.add_track(myexternal='true', format='m4a', title=u'TITLE')

        # We "convert" by copying the file. Setting the title simulates
        # a badly behaved converter
        mediafile_converted = MediaFile(syspath(item.path))
        mediafile_converted.title = u'WRONG'
        mediafile_converted.save()

        self.runcli('alt', 'update', 'myexternal')
        item.load()

        alt_mediafile = MediaFile(syspath(self.get_path(item)))
        self.assertEqual(alt_mediafile.title, u'TITLE')
Example #55
0
    def __init__(self):
        super(ZeroPlugin, self).__init__()

        # Listeners.
        self.register_listener('write', self.write_event)
        self.register_listener('import_task_choice',
                               self.import_task_choice_event)

        self.config.add({
            'fields': [],
            'keep_fields': [],
            'update_database': False,
        })

        self.patterns = {}
        self.warned = False

        # We'll only handle `fields` or `keep_fields`, but not both.
        if self.config['fields'] and self.config['keep_fields']:
            self._log.warning(
                u'cannot blacklist and whitelist at the same time')

        # Blacklist mode.
        if self.config['fields']:
            self.validate_config('fields')
            for field in self.config['fields'].as_str_seq():
                self.set_pattern(field)

        # Whitelist mode.
        elif self.config['keep_fields']:
            self.validate_config('keep_fields')

            for field in MediaFile.fields():
                if field in self.config['keep_fields'].as_str_seq():
                    continue
                self.set_pattern(field)

            # These fields should always be preserved.
            for key in ('id', 'path', 'album_id'):
                if key in self.patterns:
                    del self.patterns[key]
Example #56
0
 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
Example #57
0
    def write(self, path=None, tags=None):
        """Write the item's metadata to a media file.

        All fields in `_media_fields` are written to disk according to
        the values on this object.

        `path` is the path of the mediafile to write the data to. It
        defaults to the item's path.

        `tags` is a dictionary of additional metadata the should be
        written to the file. (These tags need not be in `_media_fields`.)

        Can raise either a `ReadError` or a `WriteError`.
        """
        if path is None:
            path = self.path
        else:
            path = normpath(path)

        # Get the data to write to the file.
        item_tags = dict(self)
        item_tags = {
            k: v
            for k, v in item_tags.items() if k in self._media_fields
        }  # Only write media fields.
        if tags is not None:
            item_tags.update(tags)
        plugins.send('write', item=self, path=path, tags=item_tags)

        # Open the file.
        try:
            mediafile = MediaFile(syspath(path),
                                  id3v23=beets.config['id3v23'].get(bool))
        except (OSError, IOError, UnreadableFileError) as exc:
            raise ReadError(self.path, exc)

        # Write the tags to the file.
        mediafile.update(item_tags)
        try:
            mediafile.save()
        except (OSError, IOError, MutagenError) as exc:
            raise WriteError(self.path, exc)

        # The file has a new mtime.
        if path == self.path:
            self.mtime = self.current_mtime()
        plugins.send('after_write', item=self, path=path)
Example #58
0
    def test_add_image_structure(self):
        mediafile = self._mediafile_fixture('image')
        self.assertEqual(len(mediafile.images), 2)

        image = Image(data=self.png_data,
                      desc='the composer',
                      type=Image.TYPES.composer)
        mediafile.images += [image]
        mediafile.save()

        mediafile = MediaFile(mediafile.path)
        self.assertEqual(len(mediafile.images), 3)

        # WMA does not preserve the order, so we have to work around this
        try:
            image = filter(lambda i: i.desc == 'the composer',
                           mediafile.images)[0]
        except IndexError:
            image = None
        self.assertExtendedImageAttributes(image,
                                           desc='the composer',
                                           type=Image.TYPES.composer)
Example #59
0
    def test_empty_query_n_response_no_changes(self):
        item = self.add_item_fixture(year=2016,
                                     day=13,
                                     month=3,
                                     comments=u'test comment')
        item.write()
        item_id = item.id
        self.config['zero']['fields'] = ['comments']
        self.config['zero']['update_database'] = True
        self.config['zero']['auto'] = False

        self.load_plugins('zero')
        with control_stdin('n'):
            self.run_command('zero')

        mf = MediaFile(syspath(item.path))
        item = self.lib.get_item(item_id)

        self.assertEqual(item['year'], 2016)
        self.assertEqual(mf.year, 2016)
        self.assertEqual(mf.comments, u'test comment')
        self.assertEqual(item['comments'], u'test comment')
Example #60
0
    def __init__(self):
        super(ZeroPlugin, self).__init__()

        self.register_listener('write', self.write_event)
        self.register_listener('import_task_choice',
                               self.import_task_choice_event)

        self.config.add({
            'auto': True,
            'fields': [],
            'keep_fields': [],
            'update_database': False,
        })

        self.fields_to_progs = {}
        self.warned = False
        """Read the bulk of the config into `self.fields_to_progs`.
        After construction, `fields_to_progs` contains all the fields that
        should be zeroed as keys and maps each of those to a list of compiled
        regexes (progs) as values.
        A field is zeroed if its value matches one of the associated progs. If
        progs is empty, then the associated field is always zeroed.
        """
        if self.config['fields'] and self.config['keep_fields']:
            self._log.warning(
                u'cannot blacklist and whitelist at the same time')
        # Blacklist mode.
        elif self.config['fields']:
            for field in self.config['fields'].as_str_seq():
                self._set_pattern(field)
        # Whitelist mode.
        elif self.config['keep_fields']:
            for field in MediaFile.fields():
                if (field not in self.config['keep_fields'].as_str_seq() and
                        # These fields should always be preserved.
                        field not in ('id', 'path', 'album_id')):
                    self._set_pattern(field)