# Buggy code
def _format_pattern(self, pattern=None, multi=None, anime_type=None):
    """Manipulate an episode naming pattern and then fills the template in.

    :param pattern:
    :type pattern: str
    :param multi:
    :type multi: bool
    :param anime_type:
    :type anime_type: int
    :return:
    :rtype: str
    """
    if pattern is None:
        pattern = app.NAMING_PATTERN

    if multi is None:
        multi = app.NAMING_MULTI_EP

    if app.NAMING_CUSTOM_ANIME:
        if anime_type is None:
            anime_type = app.NAMING_ANIME
    else:
        anime_type = 3

    replace_map = self.__replace_map()

    result_name = pattern

    # if there's no release group in the db, let the user know we replaced it
    if replace_map["%RG"] and replace_map["%RG"] != app.UNKNOWN_RELEASE_GROUP:
        if not hasattr(self, "release_group") or not self.release_group:
            log.debug(
                "{id}: Episode has no release group, replacing it with {rg}",
                {"id": self.series.series_id, "rg": replace_map["%RG"]},
            )
            self.release_group = replace_map[
                "%RG"
            ]  # if release_group is not in the db, put it there

    # if there's no release name then replace it with a reasonable facsimile
    if not replace_map["%RN"]:
        if self.series.air_by_date or self.series.sports:
            result_name = result_name.replace(
                "%RN", "%S.N.%A.D.%E.N-" + replace_map["%RG"]
            )
            result_name = result_name.replace(
                "%rn", "%s.n.%A.D.%e.n-" + replace_map["%RG"].lower()
            )

        elif anime_type != 3:
            result_name = result_name.replace(
                "%RN", "%S.N.%AB.%E.N-" + replace_map["%RG"]
            )
            result_name = result_name.replace(
                "%rn", "%s.n.%ab.%e.n-" + replace_map["%RG"].lower()
            )

        else:
            result_name = result_name.replace(
                "%RN", "%S.N.S%0SE%0E.%E.N-" + replace_map["%RG"]
            )
            result_name = result_name.replace(
                "%rn", "%s.n.s%0se%0e.%e.n-" + replace_map["%RG"].lower()
            )

    if not replace_map["%RT"]:
        result_name = re.sub("([ _.-]*)%RT([ _.-]*)", r"\2", result_name)

    # split off ep name part only
    name_groups = re.split(r"[\\/]", result_name)

    # figure out the double-ep numbering style for each group, if applicable
    for cur_name_group in name_groups:
        season_ep_regex = r"""
                                (?P<pre_sep>[ _.-]*)
                                ((?:s(?:eason|eries)?\s*)?%0?S(?![._]?N))
                                (.*?)
                                (%0?E(?![._]?N))
                                (?P<post_sep>[ _.-]*)
                              """
        ep_only_regex = r"(E?%0?E(?![._]?N))"

        # try the normal way
        season_ep_match = re.search(season_ep_regex, cur_name_group, re.I | re.X)
        ep_only_match = re.search(ep_only_regex, cur_name_group, re.I | re.X)

        # if we have a season and episode then collect the necessary data
        if season_ep_match:
            season_format = season_ep_match.group(2)
            ep_sep = season_ep_match.group(3)
            ep_format = season_ep_match.group(4)
            sep = season_ep_match.group("pre_sep")
            if not sep:
                sep = season_ep_match.group("post_sep")
            if not sep:
                sep = " "

            # force 2-3-4 format if they chose to extend
            if multi in (
                NAMING_EXTEND,
                NAMING_LIMITED_EXTEND,
                NAMING_LIMITED_EXTEND_E_PREFIXED,
            ):
                ep_sep = "-"

            regex_used = season_ep_regex

        # if there's no season then there's not much choice so we'll just force them to use 03-04-05 style
        elif ep_only_match:
            season_format = ""
            ep_sep = "-"
            ep_format = ep_only_match.group(1)
            sep = ""
            regex_used = ep_only_regex

        else:
            continue

        # we need at least this much info to continue
        if not ep_sep or not ep_format:
            continue

        # start with the ep string, eg. E03
        ep_string = self.__format_string(ep_format.upper(), replace_map)
        for other_ep in self.related_episodes:
            # for limited extend we only append the last ep
            if (
                multi in (NAMING_LIMITED_EXTEND, NAMING_LIMITED_EXTEND_E_PREFIXED)
                and other_ep != self.related_episodes[-1]
            ):
                continue

            elif multi == NAMING_DUPLICATE:
                # add " - S01"
                ep_string += sep + season_format

            elif multi == NAMING_SEPARATED_REPEAT:
                ep_string += sep

            # add "E04"
            ep_string += ep_sep

            if multi == NAMING_LIMITED_EXTEND_E_PREFIXED:
                ep_string += "E"

            ep_string += other_ep.__format_string(
                ep_format.upper(), other_ep.__replace_map()
            )

        if anime_type != 3:
            if self.absolute_number == 0:
                cur_absolute_number = self.episode
            else:
                cur_absolute_number = self.absolute_number

            if self.season != 0:  # don't set absolute numbers if we are on specials !
                if anime_type == 1:  # this crazy person wants both ! (note: +=)
                    ep_string += sep + "%(#)03d" % {"#": cur_absolute_number}
                elif (
                    anime_type == 2
                ):  # total anime freak only need the absolute number ! (note: =)
                    ep_string = "%(#)03d" % {"#": cur_absolute_number}

                for rel_ep in self.related_episodes:
                    if rel_ep.absolute_number != 0:
                        ep_string += "-" + "%(#)03d" % {"#": rel_ep.absolute_number}
                    else:
                        ep_string += "-" + "%(#)03d" % {"#": rel_ep.episode}

        regex_replacement = None
        if anime_type == 2:
            regex_replacement = r"\g<pre_sep>" + ep_string + r"\g<post_sep>"
        elif season_ep_match:
            regex_replacement = r"\g<pre_sep>\g<2>\g<3>" + ep_string + r"\g<post_sep>"
        elif ep_only_match:
            regex_replacement = ep_string

        if regex_replacement:
            # fill out the template for this piece and then insert this piece into the actual pattern
            cur_name_group_result = re.sub(
                "(?i)(?x)" + regex_used, regex_replacement, cur_name_group
            )
            # cur_name_group_result = cur_name_group.replace(ep_format, ep_string)
            result_name = result_name.replace(cur_name_group, cur_name_group_result)

    parsed_result_name = self.__format_string(result_name, replace_map)

    # With the episode name filenames tend to grow very large. Worst case scenario we even need to add `-thumb.jpg`
    # to the filename. To make sure we stay under the 255 character limit, we're working with 244 chars, taking into
    # account the thumbnail.
    if len(parsed_result_name) > 244 and any(
        ["%E.N" in result_name, "%EN" in result_name, "%E_N" in result_name]
    ):
        for remove_pattern in ("%E.N", "%EN", "%E_N"):
            result_name = result_name.replace(remove_pattern, "")
        # The Episode name can be appended with a - or . in between. Therefor we're removing it.
        # Creating a clean filename.
        result_name = result_name.strip("-. ")
        parsed_result_name = self.__format_string(result_name, replace_map)
        log.debug(
            "{id}: Cutting off the episode name, as the total filename is too long. > 255 chars.",
            {"id": self.series.series_id},
        )

    log.debug(
        "{id}: Formatting pattern: {pattern} -> {result}",
        {
            "id": self.series.series_id,
            "pattern": result_name,
            "result": parsed_result_name,
        },
    )

    return parsed_result_name


# Traceback (IndexError)
2018-03-02 09:34:54 DEBUG    Thread-17 :: [d6eb72d] Processing path: /media/usb/SABnzbd/done/[HorribleSubs]_Dragon_Ball_Super_-_125_[1080p]
2018-03-02 09:34:54 DEBUG    Thread-17 :: [d6eb72d] Processing folder: /media/usb0/SABnzbd/done/[HorribleSubs]_Dragon_Ball_Super_-_125_[1080p]
2018-03-02 09:34:54 DEBUG    Thread-17 :: [d6eb72d] Post-processing files: [u'[HorribleSubs]_Dragon_Ball_Super_-_125_[1080p].mkv']
2018-03-02 09:34:54 DEBUG    Thread-17 :: [d6eb72d] Post-processing video files: [u'[HorribleSubs]_Dragon_Ball_Super_-_125_[1080p].mkv']
2018-03-02 09:34:54 INFO     Thread-17 :: [d6eb72d] Processing /media/usb0/SABnzbd/done/[HorribleSubs]_Dragon_Ball_Super_-_125_[1080p]/[HorribleSubs]_Dragon_Ball_Super_-_125_[1080p].mkv
2018-03-02 09:34:54 DEBUG    Thread-17 :: [d6eb72d] Analyzing name: [HorribleSubs]_Dragon_Ball_Super_-_125_[1080p].mkv
2018-03-02 09:34:55 DEBUG    Thread-17 :: [d6eb72d] Scene numbering enabled series Dragon Ball Super is anime
2018-03-02 09:34:55 DEBUG    Thread-17 :: [d6eb72d] 295068: Season and episode lookup for Dragon Ball Super using absolute number 125
2018-03-02 09:34:55 DEBUG    Thread-17 :: [d6eb72d] 295068: Found season and episode which is Dragon Ball Super S05E49
2018-03-02 09:34:55 DEBUG    Thread-17 :: [d6eb72d] Scene numbering enabled series Dragon Ball Super using indexer for absolute 125: None
2018-03-02 09:34:55 DEBUG    Thread-17 :: [d6eb72d] Matched release [HorribleSubs]_Dragon_Ball_Super_-_125_[1080p].mkv to a series in your database: Dragon Ball Super
2018-03-02 09:34:55 DEBUG    Thread-17 :: [d6eb72d] Parsed [HorribleSubs]_Dragon_Ball_Super_-_125_[1080p].mkv into release_group: HorribleSubs, title: Dragon Ball Super, absolute_episode: [125], episode: [49], screen_size: 1080p, container: mkv, mimetype: video/x-matroska, type: episode, parsing_time: 0.386642932892, total_time: 1.33264017105, quality: 1080p HDTV, season: 5
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] Show information parsed from file name
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] Retrieving episode object for Dragon Ball Super S05E49
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] The episode file has a quality in it, using that: 1080p HDTV
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] Quality of the episode we are processing: 1080p HDTV
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] Snatch in history: False
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] Manually snatched: False
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] Info hash: None
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] NZB: False
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] Current quality: N/A
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] New quality: 1080p HDTV
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] Proper: False
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] This episode is a priority download: False
2018-03-02 09:34:56 INFO     Thread-17 :: [d6eb72d] New file: /media/usb0/SABnzbd/done/[HorribleSubs]_Dragon_Ball_Super_-_125_[1080p]/[HorribleSubs]_Dragon_Ball_Super_-_125_[1080p].mkv
2018-03-02 09:34:56 INFO     Thread-17 :: [d6eb72d] New size: 539.08 MB
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] There is no existing file so there's no worries about replacing it
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] Trying to determine free space on destination drive
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] Found release name [HorribleSubs]_Dragon_Ball_Super_-_125_[1080p]
2018-03-02 09:34:56 DEBUG    Thread-17 :: [d6eb72d] Scene numbering enabled series Dragon Ball Super is anime
2018-03-02 09:34:57 DEBUG    Thread-17 :: [d6eb72d] 295068: Season and episode lookup for Dragon Ball Super using absolute number 125
2018-03-02 09:34:57 DEBUG    Thread-17 :: [d6eb72d] 295068: Found season and episode which is Dragon Ball Super S05E49
2018-03-02 09:34:57 DEBUG    Thread-17 :: [d6eb72d] Scene numbering enabled series Dragon Ball Super using indexer for absolute 125: None
2018-03-02 09:34:57 DEBUG    Thread-17 :: [d6eb72d] Matched release [HorribleSubs]_Dragon_Ball_Super_-_125_[1080p] to a series in your database: Dragon Ball Super
2018-03-02 09:34:57 DEBUG    Thread-17 :: [d6eb72d] Parsed [HorribleSubs]_Dragon_Ball_Super_-_125_[1080p] into release_group: HorribleSubs, title: Dragon Ball Super, absolute_episode: [125], episode: [49], screen_size: 1080p, type: episode, parsing_time: 0.222476959229, total_time: 0.959728002548, quality: 1080p HDTV, season: 5
2018-03-02 09:34:57 DEBUG    Thread-17 :: [d6eb72d] Folder name ([HorribleSubs]_Dragon_Ball_Super_-_125_[1080p]) appears to be a valid release name. Using it.
2018-03-02 09:34:57 DEBUG    Thread-17 :: [d6eb72d] Using cached parse result for [HorribleSubs]_Dragon_Ball_Super_-_125_[1080p]
2018-03-02 09:34:57 DEBUG    Thread-17 :: [d6eb72d] Found codec for Dragon Ball Super Majestic! Advent of the God of Destruction, Toppo!!
2018-03-02 09:34:57 ERROR    Thread-17 :: [d6eb72d] Exception generated: unknown group name: u'pre_sep'
Traceback (most recent call last):
  File "/opt/medusa/medusa/server/web/core/base.py", line 283, in async_call
    result = function(**kwargs)
  File "/opt/medusa/medusa/server/web/home/post_process.py", line 49, in processEpisode
    ignore_subs=argToBool(ignore_subs)
  File "/opt/medusa/medusa/process_tv.py", line 146, in process
    ignore_subs=ignore_subs)
  File "/opt/medusa/medusa/process_tv.py", line 335, in process_files
    self.process_media(path, self.video_files, force, is_priority, ignore_subs)
  File "/opt/medusa/medusa/process_tv.py", line 536, in process_media
    self.result = processor.process()
  File "/opt/medusa/medusa/post_processor.py", line 1182, in process
    proper_path = ep_obj.proper_path()
  File "/opt/medusa/medusa/tv/episode.py", line 1735, in proper_path
    result = self.formatted_filename(anime_type=anime_type)
  File "/opt/medusa/medusa/tv/episode.py", line 1802, in formatted_filename
    return sanitize_filename(self._format_pattern(name_groups[-1], multi, anime_type))
  File "/opt/medusa/medusa/tv/episode.py", line 1701, in _format_pattern
    cur_name_group_result = re.sub('(?i)(?x)' + regex_used, regex_replacement, cur_name_group)
  File "/usr/lib/python2.7/re.py", line 155, in sub
    return _compile(pattern, flags).sub(repl, string, count)
  File "/usr/lib/python2.7/re.py", line 286, in _subx
    template = _compile_repl(template, pattern)
  File "/usr/lib/python2.7/re.py", line 271, in _compile_repl
    p = sre_parse.parse_template(repl, pattern)
  File "/usr/lib/python2.7/sre_parse.py", line 781, in parse_template
    raise IndexError(msg)
IndexError: unknown group name: u'pre_sep'

# Fixed code
def _format_pattern(self, pattern=None, multi=None, anime_type=None):
    """Manipulate an episode naming pattern and then fills the template in.

    :param pattern:
    :type pattern: str
    :param multi:
    :type multi: bool
    :param anime_type:
    :type anime_type: int
    :return:
    :rtype: str
    """
    if pattern is None:
        pattern = app.NAMING_PATTERN

    if multi is None:
        multi = app.NAMING_MULTI_EP

    if app.NAMING_CUSTOM_ANIME:
        if anime_type is None:
            anime_type = app.NAMING_ANIME
    else:
        anime_type = 3

    replace_map = self.__replace_map()

    result_name = pattern

    # if there's no release group in the db, let the user know we replaced it
    if replace_map["%RG"] and replace_map["%RG"] != app.UNKNOWN_RELEASE_GROUP:
        if not hasattr(self, "release_group") or not self.release_group:
            log.debug(
                "{id}: Episode has no release group, replacing it with {rg}",
                {"id": self.series.series_id, "rg": replace_map["%RG"]},
            )
            self.release_group = replace_map[
                "%RG"
            ]  # if release_group is not in the db, put it there

    # if there's no release name then replace it with a reasonable facsimile
    if not replace_map["%RN"]:
        if self.series.air_by_date or self.series.sports:
            result_name = result_name.replace(
                "%RN", "%S.N.%A.D.%E.N-" + replace_map["%RG"]
            )
            result_name = result_name.replace(
                "%rn", "%s.n.%A.D.%e.n-" + replace_map["%RG"].lower()
            )

        elif anime_type != 3:
            result_name = result_name.replace(
                "%RN", "%S.N.%AB.%E.N-" + replace_map["%RG"]
            )
            result_name = result_name.replace(
                "%rn", "%s.n.%ab.%e.n-" + replace_map["%RG"].lower()
            )

        else:
            result_name = result_name.replace(
                "%RN", "%S.N.S%0SE%0E.%E.N-" + replace_map["%RG"]
            )
            result_name = result_name.replace(
                "%rn", "%s.n.s%0se%0e.%e.n-" + replace_map["%RG"].lower()
            )

    if not replace_map["%RT"]:
        result_name = re.sub("([ _.-]*)%RT([ _.-]*)", r"\2", result_name)

    # split off ep name part only
    name_groups = re.split(r"[\\/]", result_name)

    # figure out the double-ep numbering style for each group, if applicable
    for cur_name_group in name_groups:
        season_ep_regex = r"""
                                (?P<pre_sep>[ _.-]*)
                                ((?:s(?:eason|eries)?\s*)?%0?S(?![._]?N))
                                (.*?)
                                (%0?E(?![._]?N))
                                (?P<post_sep>[ _.-]*)
                              """
        ep_only_regex = r"(E?%0?E(?![._]?N))"

        # try the normal way
        season_ep_match = re.search(season_ep_regex, cur_name_group, re.I | re.X)
        ep_only_match = re.search(ep_only_regex, cur_name_group, re.I | re.X)

        # if we have a season and episode then collect the necessary data
        if season_ep_match:
            season_format = season_ep_match.group(2)
            ep_sep = season_ep_match.group(3)
            ep_format = season_ep_match.group(4)
            sep = season_ep_match.group("pre_sep")
            if not sep:
                sep = season_ep_match.group("post_sep")
            if not sep:
                sep = " "

            # force 2-3-4 format if they chose to extend
            if multi in (
                NAMING_EXTEND,
                NAMING_LIMITED_EXTEND,
                NAMING_LIMITED_EXTEND_E_PREFIXED,
            ):
                ep_sep = "-"

            regex_used = season_ep_regex

        # if there's no season then there's not much choice so we'll just force them to use 03-04-05 style
        elif ep_only_match:
            season_format = ""
            ep_sep = "-"
            ep_format = ep_only_match.group(1)
            sep = ""
            regex_used = ep_only_regex

        else:
            continue

        # we need at least this much info to continue
        if not ep_sep or not ep_format:
            continue

        # start with the ep string, eg. E03
        ep_string = self.__format_string(ep_format.upper(), replace_map)
        for other_ep in self.related_episodes:
            # for limited extend we only append the last ep
            if (
                multi in (NAMING_LIMITED_EXTEND, NAMING_LIMITED_EXTEND_E_PREFIXED)
                and other_ep != self.related_episodes[-1]
            ):
                continue

            elif multi == NAMING_DUPLICATE:
                # add " - S01"
                ep_string += sep + season_format

            elif multi == NAMING_SEPARATED_REPEAT:
                ep_string += sep

            # add "E04"
            ep_string += ep_sep

            if multi == NAMING_LIMITED_EXTEND_E_PREFIXED:
                ep_string += "E"

            ep_string += other_ep.__format_string(
                ep_format.upper(), other_ep.__replace_map()
            )

        if anime_type != 3:
            if self.absolute_number == 0:
                cur_absolute_number = self.episode
            else:
                cur_absolute_number = self.absolute_number

            if self.season != 0:  # don't set absolute numbers if we are on specials !
                if anime_type == 1:  # this crazy person wants both ! (note: +=)
                    ep_string += sep + "%(#)03d" % {"#": cur_absolute_number}
                elif (
                    anime_type == 2
                ):  # total anime freak only need the absolute number ! (note: =)
                    ep_string = "%(#)03d" % {"#": cur_absolute_number}

                for rel_ep in self.related_episodes:
                    if rel_ep.absolute_number != 0:
                        ep_string += "-" + "%(#)03d" % {"#": rel_ep.absolute_number}
                    else:
                        ep_string += "-" + "%(#)03d" % {"#": rel_ep.episode}

        regex_replacement = None
        if anime_type == 2 and not ep_only_match:
            regex_replacement = r"\g<pre_sep>" + ep_string + r"\g<post_sep>"
        elif season_ep_match:
            regex_replacement = r"\g<pre_sep>\g<2>\g<3>" + ep_string + r"\g<post_sep>"
        elif ep_only_match:
            regex_replacement = ep_string

        if regex_replacement:
            # fill out the template for this piece and then insert this piece into the actual pattern
            cur_name_group_result = re.sub(
                "(?i)(?x)" + regex_used, regex_replacement, cur_name_group
            )
            # cur_name_group_result = cur_name_group.replace(ep_format, ep_string)
            result_name = result_name.replace(cur_name_group, cur_name_group_result)

    parsed_result_name = self.__format_string(result_name, replace_map)

    # With the episode name filenames tend to grow very large. Worst case scenario we even need to add `-thumb.jpg`
    # to the filename. To make sure we stay under the 255 character limit, we're working with 244 chars, taking into
    # account the thumbnail.
    if len(parsed_result_name) > 244 and any(
        ["%E.N" in result_name, "%EN" in result_name, "%E_N" in result_name]
    ):
        for remove_pattern in ("%E.N", "%EN", "%E_N"):
            result_name = result_name.replace(remove_pattern, "")
        # The Episode name can be appended with a - or . in between. Therefor we're removing it.
        # Creating a clean filename.
        result_name = result_name.strip("-. ")
        parsed_result_name = self.__format_string(result_name, replace_map)
        log.debug(
            "{id}: Cutting off the episode name, as the total filename is too long. > 255 chars.",
            {"id": self.series.series_id},
        )

    log.debug(
        "{id}: Formatting pattern: {pattern} -> {result}",
        {
            "id": self.series.series_id,
            "pattern": result_name,
            "result": parsed_result_name,
        },
    )

    return parsed_result_name