def _filter_duplicate_generation_prefs(
            self, preset_type: PresetPrefType) -> None:
        preset_names, preset_pref_lists = self.get_preset(
            preset_type=preset_type)
        seen = set()
        filtered_names = []
        filtered_pref_lists = []
        duplicates = []
        for name, pref_list in zip(preset_names, preset_pref_lists):
            value = tuple(pref_list)
            if value in seen:
                duplicates.append(name)
            else:
                seen.add(value)
                filtered_names.append(name)
                filtered_pref_lists.append(pref_list)

        if duplicates:
            human_readable = preset_type.name[len("preset_"):].replace(
                "_", " ")
            logging.warning(
                "Removed %s duplicate(s) from %s presets: %s",
                len(duplicates),
                human_readable,
                make_internationalized_list(duplicates),
            )
            self.set_preset(
                preset_type=preset_type,
                preset_names=filtered_names,
                preset_pref_lists=filtered_pref_lists,
            )
    def file_types_present_details(self,
                                   title_case=True,
                                   singular_natural=False) -> str:
        """
        Displays details about how many files are selected or ready to be downloaded.

        :param title_case: whether the details should use title case or not.
        :param singular_natural: if True, instead of '1 photo', return 'A photo'. If True,
         title_case parameter is treated as always False.
        :return:
        """

        p = self[FileType.photo]
        v = self[FileType.video]

        if v > 1:
            # Translators: %(variable)s represents Python code, not a plural of the term
            # variable. You must keep the %(variable)s untranslated, or the program will
            # crash.
            videos = _('%(no_videos)s Videos') % dict(no_videos=thousands(v))
        elif v == 1:
            if singular_natural:
                # translators: natural language expression signifying a single video
                videos = _('a video')
            else:
                videos = _('1 Video')

        if p > 1:
            # Translators: %(variable)s represents Python code, not a plural of the term
            # variable. You must keep the %(variable)s untranslated, or the program will
            # crash.
            photos = _('%(no_photos)s Photos') % dict(no_photos=thousands(p))
        elif p == 1:
            if singular_natural:
                # translators: natural language expression signifying a single photo
                photos = _('a photo')
            else:
                photos = _('1 Photo')

        if (p > 0) and (v > 0):
            s = make_internationalized_list([photos, videos])
        elif (p == 0) and (v == 0):
            return ''
        elif v > 0:
            s = videos
        else:
            s = photos

        if title_case or singular_natural:
            return s
        else:
            return s.lower()
    def details(self) -> List[str]:
        d = []
        if len(self.missing_metadata) == 1:
            d.append(
                escape(
                    # Translators: %(variable)s represents Python code, not a plural of the term
                    # variable. You must keep the %(variable)s untranslated, or the program will
                    # crash.
                    _("The %(type)s metadata is missing.")) %
                dict(type=self.missing_metadata[0]))
        elif len(self.missing_metadata) > 1:
            d.append(
                escape(_("The following metadata is missing: %s.")) %
                make_internationalized_list(self.missing_metadata))

        if self.bad_converstion_date_time:
            d.append(
                escape(_('Date/time conversion failed: %s.')) %
                self.bad_conversion_exception)

        if self.invalid_date_time:
            d.append(
                escape(
                    _("Could not extract valid date/time metadata or determine the file "
                      "modification time.")))

        if self.missing_extension:
            d.append(escape(_("Filename does not have an extension.")))

        if self.missing_image_no:
            d.append(escape(_("Filename does not have a number component.")))

        if self.component_error:
            d.append(
                escape(
                    _("Error generating component %(component)s. Error: %(error)s"
                      )) % dict(component=self.component_problem,
                                error=self.component_exception))

        return d