Esempio n. 1
0
    def _example_to_filename(self, file):
        settings = SettingsOverride(
            config.setting, {
                'ascii_filenames': self.ui.ascii_filenames.isChecked(),
                'file_naming_format': self.ui.file_naming_format.toPlainText(),
                'move_files': self.ui.move_files.isChecked(),
                'move_files_to': os.path.normpath(
                    self.ui.move_files_to.text()),
                'rename_files': self.ui.rename_files.isChecked(),
                'windows_compatibility':
                self.ui.windows_compatibility.isChecked(),
            })

        try:
            if config.setting["enable_tagger_scripts"]:
                for s_pos, s_name, s_enabled, s_text in config.setting[
                        "list_of_scripts"]:
                    if s_enabled and s_text:
                        parser = ScriptParser()
                        parser.eval(s_text, file.metadata)
            filename = file.make_filename(file.filename, file.metadata,
                                          settings)
            if not settings["move_files"]:
                return os.path.basename(filename)
            return filename
        except ScriptError:
            return ""
        except TypeError:
            return ""
Esempio n. 2
0
 def _example_to_filename(self, file):
     settings = {
         'windows_compatibility':
         self.ui.windows_compatibility.isChecked(),
         'ascii_filenames':
         self.ui.ascii_filenames.isChecked(),
         'rename_files':
         self.ui.rename_files.isChecked(),
         'move_files':
         self.ui.move_files.isChecked(),
         'use_va_format':
         False,  # TODO remove
         'file_naming_format':
         unicode(self.ui.file_naming_format.toPlainText()),
         'move_files_to':
         os.path.normpath(unicode(self.ui.move_files_to.text()))
     }
     try:
         if config.setting["enable_tagger_script"]:
             script = config.setting["tagger_script"]
             parser = ScriptParser()
             parser.eval(script, file.metadata)
         filename = file._make_filename(file.filename, file.metadata,
                                        settings)
         if not settings["move_files"]:
             return os.path.basename(filename)
         return filename
     except SyntaxError:
         return ""
     except ScriptError:
         return ""
     except TypeError:
         return ""
Esempio n. 3
0
 def _script_to_filename(self, naming_format, file_metadata, settings=None):
     if settings is None:
         settings = config.setting
     metadata = Metadata()
     if config.setting["clear_existing_tags"]:
         metadata.copy(file_metadata)
     else:
         metadata.copy(self.orig_metadata)
         metadata.update(file_metadata)
     # make sure every metadata can safely be used in a path name
     for name in metadata.keys():
         if isinstance(metadata[name], str):
             metadata[name] = sanitize_filename(metadata[name])
     naming_format = naming_format.replace("\t", "").replace("\n", "")
     filename = ScriptParser().eval(naming_format, metadata, self)
     if settings["ascii_filenames"]:
         if isinstance(filename, str):
             filename = unaccent(filename)
         filename = replace_non_ascii(filename)
     # replace incompatible characters
     if settings["windows_compatibility"] or sys.platform == "win32":
         filename = replace_win32_incompat(filename)
     # remove null characters
     if isinstance(filename, (bytes, bytearray)):
         filename = filename.replace(b"\x00", "")
     return filename
Esempio n. 4
0
    def remove_file(self, file):
        if file not in self.linked_files:
            return
        self.linked_files.remove(file)
        self.num_linked_files -= 1
        file.copy_metadata(file.orig_metadata)
        self.album._remove_file(self, file)
        file.metadata_images_changed.disconnect(
            self.update_orig_metadata_images)

        if self.num_linked_files > 0:
            self.metadata.copy(self.linked_files[-1].orig_metadata)
        else:
            self.metadata.copy(self.orig_metadata)

        # Restore to non-associated state
        for s_name, s_text in enabled_tagger_scripts_texts():
            parser = ScriptParser()
            try:
                parser.eval(s_text, self.metadata)
            except:
                log.exception("Failed to run tagger script %s on track",
                              s_name)
            self.metadata.strip_whitespace()

        self.update()
Esempio n. 5
0
 def _example_to_filename(self, file):
     settings = {
         'windows_compatible_filenames':
         self.ui.windows_compatible_filenames.isChecked(),
         'ascii_filenames':
         self.ui.ascii_filenames.isChecked(),
         'rename_files':
         self.ui.rename_files.isChecked(),
         'move_files':
         self.config.setting["move_files"],
         'use_va_format':
         self.ui.use_va_format.isChecked(),
         'file_naming_format':
         unicode(self.ui.file_naming_format.toPlainText()),
         'va_file_naming_format':
         unicode(self.ui.va_file_naming_format.toPlainText()),
         'move_files_to':
         os.path.normpath(unicode(self.config.setting["move_files_to"])),
     }
     try:
         if self.config.setting["enable_tagger_script"]:
             script = self.config.setting["tagger_script"]
             parser = ScriptParser()
             parser.eval(script, file.metadata)
         filename = file._make_filename(file.filename, file.metadata,
                                        settings)
         return filename
     except SyntaxError, e:
         return ""
Esempio n. 6
0
    def _example_to_filename(self, file):
        """Produce the before and after file naming example tuple for the specified file.

        Args:
            file (File): File to produce example before and after names

        Returns:
            tuple: Example before and after names for the specified file
        """
        try:
            if self.settings["enable_tagger_scripts"]:
                for s_pos, s_name, s_enabled, s_text in self.settings[
                        "list_of_scripts"]:
                    if s_enabled and s_text:
                        parser = ScriptParser()
                        parser.eval(s_text, file.metadata)
            filename_before = file.filename
            filename_after = file.make_filename(filename_before, file.metadata,
                                                self.settings)
            if not self.settings["move_files"]:
                return os.path.basename(filename_before), os.path.basename(
                    filename_after)
            return filename_before, filename_after
        except ScriptError:
            return "", ""
        except TypeError:
            return "", ""
Esempio n. 7
0
 def run_scripts(metadata):
     for s_name, s_text in enabled_tagger_scripts_texts():
         parser = ScriptParser()
         try:
             parser.eval(s_text, metadata)
         except ScriptError:
             log.exception("Failed to run tagger script %s on track", s_name)
         metadata.strip_whitespace()
Esempio n. 8
0
 def setUp(self):
     config.setting = {
         'enabled_plugins': '',
     }
     self.parser = ScriptParser()
     def func_noargstest(parser):
         return ""
     register_script_function(func_noargstest, "noargstest")
Esempio n. 9
0
 def check_format(self):
     parser = ScriptParser()
     try:
         parser.eval(self.script_text)
     except Exception as e:
         raise ScriptCheckError("", str(e))
     if self.ui.rename_files.isChecked():
         if not self.script_text.strip():
             raise ScriptCheckError("", _("The file naming format must not be empty."))
Esempio n. 10
0
 def check_format(self):
     parser = ScriptParser()
     try:
         parser.eval(self.ui.file_naming_format.toPlainText())
     except Exception as e:
         raise OptionsCheckError("", string_(e))
     if self.ui.rename_files.isChecked():
         if not self.ui.file_naming_format.toPlainText().strip():
             raise OptionsCheckError("", _("The file naming format must not be empty."))
Esempio n. 11
0
    def _finalize_loading_album(self):
        self.enable_update_metadata_images(False)
        for track in self._new_tracks:
            track.orig_metadata.copy(track.metadata)
            track.metadata_images_changed.connect(self.update_metadata_images)

        # Prepare parser for user's script
        for s_name, s_text in enabled_tagger_scripts_texts():
            parser = ScriptParser()
            for track in self._new_tracks:
                # Run tagger script for each track
                try:
                    parser.eval(s_text, track.metadata)
                except ScriptError:
                    log.exception("Failed to run tagger script %s on track",
                                  s_name)
                track.metadata.strip_whitespace()
                track.scripted_metadata.update(track.metadata)
            # Run tagger script for the album itself
            try:
                parser.eval(s_text, self._new_metadata)
            except ScriptError:
                log.exception("Failed to run tagger script %s on album",
                              s_name)
            self._new_metadata.strip_whitespace()

        unmatched_files = [
            file for track in self.tracks for file in track.files
        ]
        self.metadata = self._new_metadata
        self.orig_metadata.copy(self.metadata)
        self.orig_metadata.images.clear()
        self.tracks = self._new_tracks
        del self._new_metadata
        del self._new_tracks
        self.loaded = True
        self.status = AlbumStatus.LOADED
        self.match_files(unmatched_files + self.unmatched_files.files)
        self.enable_update_metadata_images(True)
        self.update_metadata_images()
        self.update()
        self.tagger.window.set_statusbar_message(
            N_('Album %(id)s loaded: %(artist)s - %(album)s'), {
                'id': self.id,
                'artist': self.metadata['albumartist'],
                'album': self.metadata['album']
            },
            timeout=3000)
        for func, always in self._after_load_callbacks:
            func()
        self._after_load_callbacks = []
        if self.item.isSelected():
            self.tagger.window.refresh_metadatabox()
Esempio n. 12
0
 def check_format(self):
     """Parse the file naming script and check for errors.
     """
     config = get_config()
     parser = ScriptParser()
     script_text = self.get_script()
     try:
         parser.eval(script_text)
     except Exception as e:
         raise ScriptCheckError("", str(e))
     if config.setting["rename_files"]:
         if not self.get_script():
             raise ScriptCheckError(
                 "", _("The file naming format must not be empty."))
Esempio n. 13
0
 def _make_image_filename(self, filename, dirname, metadata):
     filename = ScriptParser().eval(filename, metadata)
     if config.setting["ascii_filenames"]:
         if isinstance(filename, unicode):
             filename = unaccent(filename)
         filename = replace_non_ascii(filename)
     if not filename:
         filename = "cover"
     if not os.path.isabs(filename):
         filename = os.path.join(dirname, filename)
     # replace incompatible characters
     if config.setting["windows_compatibility"] or sys.platform == "win32":
         filename = replace_win32_incompat(filename)
     # remove null characters
     filename = filename.replace("\x00", "")
     return encode_filename(filename)
Esempio n. 14
0
def script_to_filename(naming_format, metadata, file=None, settings=None):
    if settings is None:
        settings = config.setting
    # make sure every metadata can safely be used in a path name
    for name in metadata:
        values = [sanitize_filename(str(v)) for v in metadata.getall(name)]
        metadata.set(name, values)
    naming_format = naming_format.replace("\t", "").replace("\n", "")
    filename = ScriptParser().eval(naming_format, metadata, file)
    if settings["ascii_filenames"]:
        filename = replace_non_ascii(filename, pathsave=True)
    # replace incompatible characters
    if settings["windows_compatibility"] or sys.platform == "win32":
        filename = replace_win32_incompat(filename)
    # remove null characters
    filename = filename.replace("\x00", "")
    return filename
Esempio n. 15
0
    def _run_script(self, script):
        s_name = script[1]
        s_text = script[3]
        parser = ScriptParser()

        for obj in self._get_unique_metadata_objects():
            try:
                parser.eval(s_text, obj.metadata)
                obj.update()
            except ScriptError as e:
                log.exception('Error running tagger script "%s" on object %r', s_name, obj)
                msg = N_('Script error in "%(script)s": %(message)s')
                mparms = {
                    'script': s_name,
                    'message': string_(e),
                }
                self.tagger.window.set_statusbar_message(msg, mparms)
Esempio n. 16
0
 def _script_to_filename(self, format, file_metadata, settings):
     metadata = Metadata()
     metadata.copy(file_metadata)
     # make sure every metadata can safely be used in a path name
     for name in metadata.keys():
         if isinstance(metadata[name], basestring):
             metadata[name] = sanitize_filename(metadata[name])
     format = format.replace("\t", "").replace("\n", "")
     filename = ScriptParser().eval(format, metadata, self)
     # replace incompatible characters
     if settings["windows_compatible_filenames"] or sys.platform == "win32":
         filename = replace_win32_incompat(filename)
     if settings["ascii_filenames"]:
         if isinstance(filename, unicode):
             filename = unaccent(filename)
         filename = replace_non_ascii(filename)
     return filename
Esempio n. 17
0
 def _parse_recording(self, recording):
     recording_to_metadata(recording, self, self.config)
     self._customize_metadata()
     m = self.metadata
     run_track_metadata_processors(self.album, m, None, recording)
     if self.config.setting["enable_tagger_script"]:
         script = self.config.setting["tagger_script"]
         if script:
             parser = ScriptParser()
             try:
                 parser.eval(script, m)
             except:
                 self.log.error(traceback.format_exc())
             m.strip_whitespace()
     self.loaded = True
     if self.callback:
         self.callback()
     self.tagger.nats.update(True)
Esempio n. 18
0
    def _parse_recording(self, recording):
        m = self.metadata
        recording_to_metadata(recording, m, self)
        self._customize_metadata()
        run_track_metadata_processors(self.album, m, None, recording)
        for s_name, s_text in enabled_tagger_scripts_texts():
            parser = ScriptParser()
            try:
                parser.eval(s_text, m)
            except ScriptError:
                log.exception("Failed to run tagger script %s on track",
                              s_name)
            m.strip_whitespace()

        self.loaded = True
        if self.callback:
            self.callback()
            self.callback = None
        self.tagger.nats.update(True)
Esempio n. 19
0
    def _parse_recording(self, recording):
        m = self.metadata
        recording_to_metadata(recording, m, self)
        self._customize_metadata()
        run_track_metadata_processors(self.album, m, None, recording)
        if config.setting["enable_tagger_scripts"]:
            for s_pos, s_name, s_enabled, s_text in config.setting[
                    "list_of_scripts"]:
                if s_enabled and s_text:
                    parser = ScriptParser()
                    try:
                        parser.eval(s_text, m)
                    except:
                        log.error(traceback.format_exc())
                    m.strip_whitespace()

        self.loaded = True
        if self.callback:
            self.callback()
            self.callback = None
        self.tagger.nats.update(True)
Esempio n. 20
0
    def update_file_metadata(self, file):
        if file not in self.linked_files:
            return
        file.copy_metadata(self.orig_metadata)
        file.metadata['~extension'] = file.orig_metadata['~extension']
        self.metadata.copy(file.metadata)

        # Re-run tagger scripts with updated metadata
        for s_name, s_text in enabled_tagger_scripts_texts():
            parser = ScriptParser()
            try:
                parser.eval(s_text, file.metadata)
                parser.eval(s_text, self.metadata)
            except:
                log.exception("Failed to run tagger script %s on file", s_name)
            file.metadata.strip_whitespace()
            self.metadata.strip_whitespace()

        file.metadata.changed = True
        file.update(signal=False)
        self.update()
Esempio n. 21
0
def script_to_filename_with_metadata(naming_format,
                                     metadata,
                                     file=None,
                                     settings=None):
    """Creates a valid filename from a script with the given metadata.

    Args:
        naming_format: A string containing the tagger script. The result of
            executing this script will be the filename.
        metadata: A Metadata object. The metadata will not be modified.
        file: A File object (optional)
        settings: The settings. If not set config.setting will be used.

    Returns:
        A tuple with the filename as first element and the updated metadata
        with changes from the script as second.
    """
    if settings is None:
        config = get_config()
        settings = config.setting
    # make sure every metadata can safely be used in a path name
    win_compat = IS_WIN or settings["windows_compatibility"]
    new_metadata = Metadata()
    for name in metadata:
        new_metadata[name] = [
            sanitize_filename(str(v), win_compat=win_compat)
            for v in metadata.getall(name)
        ]
    naming_format = naming_format.replace("\t", "").replace("\n", "")
    filename = ScriptParser().eval(naming_format, new_metadata, file)
    if settings["ascii_filenames"]:
        filename = replace_non_ascii(filename,
                                     pathsave=True,
                                     win_compat=win_compat)
    # replace incompatible characters
    if win_compat:
        filename = replace_win32_incompat(filename)
    # remove null characters
    filename = filename.replace("\x00", "")
    return (filename, new_metadata)
Esempio n. 22
0
def script_to_filename(naming_format, metadata, file=None, settings=None):
    if settings is None:
        settings = config.setting
    # make sure every metadata can safely be used in a path name
    win_compat = IS_WIN or settings["windows_compatibility"]
    meta = Metadata()
    for name in metadata:
        meta[name] = [
            sanitize_filename(str(v), win_compat=win_compat)
            for v in metadata.getall(name)
        ]
    naming_format = naming_format.replace("\t", "").replace("\n", "")
    filename = ScriptParser().eval(naming_format, meta, file)
    if settings["ascii_filenames"]:
        filename = replace_non_ascii(filename,
                                     pathsave=True,
                                     win_compat=win_compat)
    # replace incompatible characters
    if win_compat:
        filename = replace_win32_incompat(filename)
    # remove null characters
    filename = filename.replace("\x00", "")
    return filename
Esempio n. 23
0
 def _make_image_filename(self, filename, dirname, _metadata):
     metadata = Metadata()
     metadata.copy(_metadata)
     metadata["coverart_maintype"] = self.maintype
     metadata["coverart_comment"] = self.comment
     if self.is_front:
         metadata.add_unique("coverart_types", "front")
     for cover_type in self.types:
         metadata.add_unique("coverart_types", cover_type)
     filename = ScriptParser().eval(filename, metadata)
     if config.setting["ascii_filenames"]:
         filename = replace_non_ascii(filename, pathsave=True)
     if not filename:
         filename = "cover"
     if not os.path.isabs(filename):
         filename = os.path.join(dirname, filename)
     # replace incompatible characters
     if config.setting["windows_compatibility"] or sys.platform == "win32":
         filename = replace_win32_incompat(filename)
     # remove null characters
     if isinstance(filename, bytes):
         filename = filename.replace(b"\x00", "")
     return encode_filename(filename)
Esempio n. 24
0
 def setUp(self):
     QtCore.QObject.config = FakeConfig()
     self.parser = ScriptParser()
Esempio n. 25
0
 def check_va_format(self):
     parser = ScriptParser()
     try:
         parser.eval(unicode(self.ui.va_file_naming_format.toPlainText()))
     except Exception, e:
         raise OptionsCheckError("", str(e))
Esempio n. 26
0
    def _finalize_loading(self, error):
        if error:
            self.metadata.clear()
            self.status = _("[could not load album %s]") % self.id
            del self._new_metadata
            del self._new_tracks
            self.update()
            return

        if self._requests > 0:
            return

        if not self._tracks_loaded:
            artists = set()
            totalalbumtracks = 0
            absolutetracknumber = 0
            va = self._new_metadata[
                'musicbrainz_albumartistid'] == VARIOUS_ARTISTS_ID

            djmix_ars = {}
            if hasattr(self._new_metadata, "_djmix_ars"):
                djmix_ars = self._new_metadata._djmix_ars

            for medium_node in self._release_node.medium_list[0].medium:
                mm = Metadata()
                mm.copy(self._new_metadata)
                medium_to_metadata(medium_node, mm)
                discpregap = False

                for dj in djmix_ars.get(mm["discnumber"], []):
                    mm.add("djmixer", dj)

                if "pregap" in medium_node.children:
                    discpregap = True
                    absolutetracknumber += 1
                    track = self._finalize_loading_track(
                        medium_node.pregap[0], mm, artists, va,
                        absolutetracknumber, discpregap)
                    track.metadata['~pregap'] = "1"

                for track_node in medium_node.track_list[0].track:
                    absolutetracknumber += 1
                    track = self._finalize_loading_track(
                        track_node, mm, artists, va, absolutetracknumber,
                        discpregap)

                if "data_track_list" in medium_node.children:
                    for track_node in medium_node.data_track_list[0].track:
                        absolutetracknumber += 1
                        track = self._finalize_loading_track(
                            track_node, mm, artists, va, absolutetracknumber,
                            discpregap)
                        track.metadata['~datatrack'] = "1"

            totalalbumtracks = str(absolutetracknumber)

            for track in self._new_tracks:
                track.metadata["~totalalbumtracks"] = totalalbumtracks
                if len(artists) > 1:
                    track.metadata["~multiartist"] = "1"
            del self._release_node
            self._tracks_loaded = True

        if not self._requests:
            # Prepare parser for user's script
            if config.setting["enable_tagger_script"]:
                script = config.setting["tagger_script"]
                if script:
                    parser = ScriptParser()
                    for track in self._new_tracks:
                        # Run tagger script for each track
                        try:
                            parser.eval(script, track.metadata)
                        except:
                            self.error_append(traceback.format_exc())
                        # Strip leading/trailing whitespace
                        track.metadata.strip_whitespace()
                    # Run tagger script for the album itself
                    try:
                        parser.eval(script, self._new_metadata)
                    except:
                        self.error_append(traceback.format_exc())
                    self._new_metadata.strip_whitespace()

            for track in self.tracks:
                for file in list(track.linked_files):
                    file.move(self.unmatched_files)
            self.metadata = self._new_metadata
            self.tracks = self._new_tracks
            del self._new_metadata
            del self._new_tracks
            self.loaded = True
            self.status = None
            self.match_files(self.unmatched_files.files)
            self.update()
            self.tagger.window.set_statusbar_message(
                N_('Album %(id)s loaded: %(artist)s - %(album)s'), {
                    'id': self.id,
                    'artist': self.metadata['albumartist'],
                    'album': self.metadata['album']
                },
                timeout=3000)
            for func in self._after_load_callbacks:
                func()
            self._after_load_callbacks = []
Esempio n. 27
0
 def check(self):
     parser = ScriptParser()
     try:
         parser.eval(self.ui.tagger_script.toPlainText())
     except Exception as e:
         raise ScriptCheckError(_("Script Error"), str(e))
Esempio n. 28
0
    def _finalize_loading(self, error):
        if error:
            self.metadata.clear()
            self.metadata['album'] = _("[could not load album %s]") % self.id
            del self._new_metadata
            del self._new_tracks
            self.update()
            return

        if self._requests > 0:
            return

        if not self._tracks_loaded:
            artists = set()
            totalalbumtracks = 0

            djmix_ars = {}
            if hasattr(self._new_metadata, "_djmix_ars"):
                djmix_ars = self._new_metadata._djmix_ars

            for medium_node in self._release_node.medium_list[0].medium:
                mm = Metadata()
                mm.copy(self._new_metadata)
                medium_to_metadata(medium_node, mm)
                totalalbumtracks += int(mm["totaltracks"])

                for dj in djmix_ars.get(mm["discnumber"], []):
                    mm.add("djmixer", dj)

                for track_node in medium_node.track_list[0].track:
                    track = Track(track_node.recording[0].id, self)
                    self._new_tracks.append(track)

                    # Get track metadata
                    tm = track.metadata
                    tm.copy(mm)
                    track_to_metadata(track_node, track, self.config)
                    track._customize_metadata()

                    self._new_metadata.length += tm.length
                    artists.add(tm["musicbrainz_artistid"])

                    # Run track metadata plugins
                    try:
                        run_track_metadata_processors(self, tm,
                                                      self._release_node,
                                                      track_node)
                    except:
                        self.log.error(traceback.format_exc())

            totalalbumtracks = str(totalalbumtracks)

            for track in self._new_tracks:
                track.metadata["~totalalbumtracks"] = totalalbumtracks
                if len(artists) > 1:
                    track.metadata["compilation"] = "1"

            del self._release_node
            self._tracks_loaded = True

        if not self._requests:
            # Prepare parser for user's script
            if self.config.setting["enable_tagger_script"]:
                script = self.config.setting["tagger_script"]
                if script:
                    parser = ScriptParser()
                    for track in self._new_tracks:
                        # Run tagger script for each track
                        try:
                            parser.eval(script, track.metadata)
                        except:
                            self.log.error(traceback.format_exc())
                        # Strip leading/trailing whitespace
                        track.metadata.strip_whitespace()
                    # Run tagger script for the album itself
                    try:
                        parser.eval(script, self._new_metadata)
                    except:
                        self.log.error(traceback.format_exc())
                    self._new_metadata.strip_whitespace()

            for track in self.tracks:
                for file in list(track.linked_files):
                    file.move(self.unmatched_files)
            self.metadata = self._new_metadata
            self.tracks = self._new_tracks
            del self._new_metadata
            del self._new_tracks
            self.loaded = True
            self.match_files(self.unmatched_files.files)
            self.update()
            self.tagger.window.set_statusbar_message('Album %s loaded',
                                                     self.id,
                                                     timeout=3000)
            while self._after_load_callbacks.qsize() > 0:
                func = self._after_load_callbacks.get()
                func()
Esempio n. 29
0
 def setUp(self):
     config.setting = {
         'enabled_plugins': '',
     }
     self.parser = ScriptParser()
Esempio n. 30
0
    def _finalize_loading(self, error):
        if error:
            self.metadata.clear()
            self.status = _("[could not load album %s]") % self.id
            del self._new_metadata
            del self._new_tracks
            self.update()
            return

        if self._requests > 0:
            return

        if not self._tracks_loaded:
            artists = set()
            all_media = []
            absolutetracknumber = 0

            va = self._new_metadata['musicbrainz_albumartistid'] == VARIOUS_ARTISTS_ID

            djmix_ars = {}
            if hasattr(self._new_metadata, "_djmix_ars"):
                djmix_ars = self._new_metadata._djmix_ars

            for medium_node in self._release_node['media']:
                mm = Metadata()
                mm.copy(self._new_metadata)
                medium_to_metadata(medium_node, mm)
                discpregap = False
                format = medium_node.get('format')
                if format:
                    all_media.append(format)

                for dj in djmix_ars.get(mm["discnumber"], []):
                    mm.add("djmixer", dj)

                if 'discs' in medium_node:
                    discids = [disc.get('id') for disc in medium_node['discs']]
                    mm['~musicbrainz_discids'] = discids
                    mm['musicbrainz_discid'] = list(self._discids.intersection(discids))

                if "pregap" in medium_node:
                    discpregap = True
                    absolutetracknumber += 1
                    track = self._finalize_loading_track(medium_node['pregap'], mm, artists, va, absolutetracknumber, discpregap)
                    track.metadata['~pregap'] = "1"

                track_count = medium_node['track-count']
                if track_count:
                    tracklist_node = medium_node['tracks']
                    for track_node in tracklist_node:
                        absolutetracknumber += 1
                        track = self._finalize_loading_track(track_node, mm, artists, va, absolutetracknumber, discpregap)

                if "data-tracks" in medium_node:
                    for track_node in medium_node['data-tracks']:
                        absolutetracknumber += 1
                        track = self._finalize_loading_track(track_node, mm, artists, va, absolutetracknumber, discpregap)
                        track.metadata['~datatrack'] = "1"

            totalalbumtracks = absolutetracknumber
            self._new_metadata['~totalalbumtracks'] = totalalbumtracks
            # Generate a list of unique media, but keep order of first appearance
            self._new_metadata['media'] = " / ".join(list(OrderedDict.fromkeys(all_media)))

            for track in self._new_tracks:
                track.metadata["~totalalbumtracks"] = totalalbumtracks
                if len(artists) > 1:
                    track.metadata["~multiartist"] = "1"
            del self._release_node
            del self._release_artist_nodes
            self._tracks_loaded = True

        if not self._requests:
            self.enable_update_metadata_images(False)
            # Prepare parser for user's script
            for s_name, s_text in enabled_tagger_scripts_texts():
                parser = ScriptParser()
                for track in self._new_tracks:
                    # Run tagger script for each track
                    try:
                        parser.eval(s_text, track.metadata)
                    except ScriptError:
                        log.exception("Failed to run tagger script %s on track", s_name)
                    track.metadata.strip_whitespace()
                # Run tagger script for the album itself
                try:
                    parser.eval(s_text, self._new_metadata)
                except ScriptError:
                    log.exception("Failed to run tagger script %s on album", s_name)
                self._new_metadata.strip_whitespace()

            for track in self.tracks:
                track.metadata_images_changed.connect(self.update_metadata_images)
                for file in list(track.linked_files):
                    file.move(self.unmatched_files)
            self.metadata = self._new_metadata
            self.tracks = self._new_tracks
            del self._new_metadata
            del self._new_tracks
            self.loaded = True
            self.status = None
            self.match_files(self.unmatched_files.files)
            self.enable_update_metadata_images(True)
            self.update()
            self.tagger.window.set_statusbar_message(
                N_('Album %(id)s loaded: %(artist)s - %(album)s'),
                {
                    'id': self.id,
                    'artist': self.metadata['albumartist'],
                    'album': self.metadata['album']
                },
                timeout=3000
            )
            for func in self._after_load_callbacks:
                func()
            self._after_load_callbacks = []