# Buggy code
def editShow(
    self,
    indexername=None,
    seriesid=None,
    location=None,
    allowed_qualities=None,
    preferred_qualities=None,
    exceptions_list=None,
    flatten_folders=None,
    paused=None,
    directCall=False,
    air_by_date=None,
    sports=None,
    dvd_order=None,
    indexer_lang=None,
    subtitles=None,
    rls_ignore_words=None,
    rls_require_words=None,
    anime=None,
    blacklist=None,
    whitelist=None,
    scene=None,
    defaultEpStatus=None,
    quality_preset=None,
):
    # @TODO: Replace with PATCH /api/v2/show/{id}

    allowed_qualities = allowed_qualities or []
    preferred_qualities = preferred_qualities or []
    exceptions = exceptions_list or set()

    anidb_failed = False
    errors = 0

    if not indexername or not seriesid:
        error_string = "No show was selected"
        if directCall:
            errors += 1
            return errors
        else:
            return self._genericMessage("Error", error_string)

    series_obj = Show.find_by_id(
        app.showList, indexer_name_to_id(indexername), seriesid
    )

    if not series_obj:
        error_string = "Unable to find the specified show ID: {show}".format(
            show=series_obj
        )
        if directCall:
            errors += 1
            return errors
        else:
            return self._genericMessage("Error", error_string)

    t = PageTemplate(rh=self, filename="editShow.mako")
    return t.render(
        show=series_obj,
        title="Edit Show",
        header="Edit Show",
        controller="home",
        action="editShow",
    )


# Traceback (AttributeError)
2018-04-22 19:13:13 DEBUG    FINDPROPERS :: [6d54662] Starting new thread: FINDPROPERS
2018-04-22 19:13:13 INFO     FINDPROPERS :: [6d54662] Beginning the search for new propers
2018-04-22 19:13:13 INFO     FINDPROPERS :: [6d54662] Using proper search days: 2
2018-04-22 19:13:13 INFO     FINDPROPERS :: [Rarbg] :: [6d54662] Searching for any new PROPER releases from Rarbg
2018-04-22 19:13:13 DEBUG    FINDPROPERS :: [Rarbg] :: [6d54662] 295647: Setter sets location to E:\TV\Blindspot\Season 3\Blindspot.S03E18.PROPER.720p.HDTV.x264-KILLERS.mkv
2018-04-22 19:13:13 DEBUG    FINDPROPERS :: [Rarbg] :: [6d54662] Checking if E:\TV\Blindspot\Season 3\Blindspot.S03E18.PROPER.720p.HDTV.x264-KILLERS.nfo exists: True
2018-04-22 19:13:13 DEBUG    FINDPROPERS :: [Rarbg] :: [6d54662] Checking if E:\TV\Blindspot\Season 3\Blindspot.S03E18.PROPER.720p.HDTV.x264-KILLERS-thumb.jpg exists: True
2018-04-22 19:13:14 DEBUG    FINDPROPERS :: [Rarbg] :: [6d54662] GET URL: http://torrentapi.org/pubapi_v2.php?get_token=get_token&amp;app_id=medusa&amp;format=json [Status: 200]
2018-04-22 19:13:14 DEBUG    FINDPROPERS :: [Rarbg] :: [6d54662] User-Agent: Medusa/0.2.2 (Windows; 7; 83ab66f0-4626-11e8-99e3-001fd0d1e3a5)
2018-04-22 19:13:14 DEBUG    FINDPROPERS :: [Rarbg] :: [6d54662] Search mode: Episode
2018-04-22 19:13:14 DEBUG    FINDPROPERS :: [Rarbg] :: [6d54662] Search string: Blindspot S03E18 {{PROPER|REPACK|REAL|RERIP}}
2018-04-22 19:13:14 DEBUG    FINDPROPERS :: [Rarbg] :: [6d54662] Searching only ranked torrents
2018-04-22 19:13:19 DEBUG    FINDPROPERS :: [Rarbg] :: [6d54662] GET URL: http://torrentapi.org/pubapi_v2.php?sort=seeders&amp;min_leechers=0&amp;min_seeders=1&amp;search_tvdb=295647&amp;app_id=medusa&amp;search_string=Blindspot+S03E18+%7B%7BPROPER%7CREPACK%7CREAL%7CRERIP%7D%7D&amp;ranked=1&amp;category=tv&amp;format=json_extended&amp;token=l7huma64or&amp;limit=100&amp;mode=search [Status: 200]
2018-04-22 19:13:19 DEBUG    FINDPROPERS :: [Rarbg] :: [6d54662] User-Agent: Medusa/0.2.2 (Windows; 7; 83ab66f0-4626-11e8-99e3-001fd0d1e3a5)
2018-04-22 19:13:19 DEBUG    FINDPROPERS :: [Rarbg] :: [6d54662] Found result: Blindspot.S03E18.PROPER.HDTV.x264-KILLERS[rartv] with 1049 seeders and 271 leechers
2018-04-22 19:13:19 DEBUG    FINDPROPERS :: [Rarbg] :: [6d54662] Found result: Blindspot.S03E18.PROPER.720p.HDTV.x264-KILLERS[rartv] with 695 seeders and 99 leechers
2018-04-22 19:13:19 ERROR    FINDPROPERS :: [Rarbg] :: [6d54662] Exception generated: 'unicode' object has no attribute 'series_name'
Traceback (most recent call last):
File "C:\Medusa\medusa\scheduler.py", line 93, in run
self.action.run(self.force)
File "C:\Medusa\medusa\search\proper.py", line 67, in run
propers = self._get_proper_results()
File "C:\Medusa\medusa\search\proper.py", line 126, in _get_proper_results
cur_propers = cur_provider.find_propers(recently_aired)
File "C:\Medusa\medusa\providers\generic_provider.py", line 203, in find_propers
search_strings = self._get_episode_search_strings(episode_obj, add_string=term)
File "C:\Medusa\medusa\providers\generic_provider.py", line 621, in _get_episode_search_strings
all_possible_show_names = episode.series.get_all_possible_names()
File "C:\Medusa\medusa\tv\series.py", line 2139, in get_all_possible_names
show_names = {exception.series_name for exception in get_scene_exceptions(self, season)}
File "C:\Medusa\medusa\tv\series.py", line 2139, in <setcomp>
show_names = {exception.series_name for exception in get_scene_exceptions(self, season)}
AttributeError: 'unicode' object has no attribute 'series_name'

# Fixed code
def editShow(
    self,
    indexername=None,
    seriesid=None,
    location=None,
    allowed_qualities=None,
    preferred_qualities=None,
    exceptions_list=None,
    flatten_folders=None,
    paused=None,
    directCall=False,
    air_by_date=None,
    sports=None,
    dvd_order=None,
    indexer_lang=None,
    subtitles=None,
    rls_ignore_words=None,
    rls_require_words=None,
    anime=None,
    blacklist=None,
    whitelist=None,
    scene=None,
    defaultEpStatus=None,
    quality_preset=None,
):
    allowed_qualities = allowed_qualities or []
    preferred_qualities = preferred_qualities or []
    exceptions = exceptions_list or set()

    anidb_failed = False
    errors = 0

    if not indexername or not seriesid:
        error_string = "No show was selected"
        if directCall:
            errors += 1
            return errors
        else:
            return self._genericMessage("Error", error_string)

    series_obj = Show.find_by_id(
        app.showList, indexer_name_to_id(indexername), seriesid
    )

    if not series_obj:
        error_string = "Unable to find the specified show ID: {show}".format(
            show=series_obj
        )
        if directCall:
            errors += 1
            return errors
        else:
            return self._genericMessage("Error", error_string)

    series_obj.exceptions = get_scene_exceptions(series_obj)

    # If user set quality_preset remove all preferred_qualities
    if try_int(quality_preset, None):
        preferred_qualities = []

    if (
        not location
        and not allowed_qualities
        and not preferred_qualities
        and not flatten_folders
    ):
        t = PageTemplate(rh=self, filename="editShow.mako")

        if series_obj.is_anime:
            if not series_obj.release_groups:
                series_obj.release_groups = BlackAndWhiteList(series_obj)
            whitelist = series_obj.release_groups.whitelist
            blacklist = series_obj.release_groups.blacklist

            groups = []
            if set_up_anidb_connection() and not anidb_failed:
                try:
                    anime = adba.Anime(app.ADBA_CONNECTION, name=series_obj.name)
                    groups = anime.get_groups()
                except Exception as e:
                    errors += 1
                    logger.log(
                        "Unable to retreive Fansub Groups from AniDB. Error:{error}".format(
                            error=e.message
                        ),
                        logger.WARNING,
                    )

        with series_obj.lock:
            show = series_obj
            scene_exceptions = get_scene_exceptions(series_obj)

        if series_obj.is_anime:
            return t.render(
                show=show,
                scene_exceptions=scene_exceptions,
                groups=groups,
                whitelist=whitelist,
                blacklist=blacklist,
                title="Edit Show",
                header="Edit Show",
                controller="home",
                action="editShow",
            )
        else:
            return t.render(
                show=show,
                scene_exceptions=scene_exceptions,
                title="Edit Show",
                header="Edit Show",
                controller="home",
                action="editShow",
            )

    flatten_folders = not config.checkbox_to_value(
        flatten_folders
    )  # UI inverts this value
    dvd_order = config.checkbox_to_value(dvd_order)
    paused = config.checkbox_to_value(paused)
    air_by_date = config.checkbox_to_value(air_by_date)
    scene = config.checkbox_to_value(scene)
    sports = config.checkbox_to_value(sports)
    anime = config.checkbox_to_value(anime)
    subtitles = config.checkbox_to_value(subtitles)

    do_update = False
    # In mass edit, we can't change language so we need to check if indexer_lang is set
    if indexer_lang and series_obj.lang != indexer_lang:
        msg = "{{status}} {language} for {indexer_name} show {show_id}".format(
            language=indexer_lang,
            show_id=series_obj.indexerid,
            indexer_name=indexerApi(series_obj.indexer).name,
        )
        status = "Unexpected result when changing language to"
        log_level = logger.WARNING
        language = series_obj.lang
        try:
            do_update = self.check_show_for_language(
                series_obj,
                indexer_lang,
            )
        except IndexerShowNotFoundInLanguage:
            errors += 1
            status = "Could not change language to"
        except IndexerException as e:
            errors += 1
            status = "Failed getting show in"
            msg += " Please try again later. Error: {error}".format(
                error=e.message,
            )
        else:
            language = indexer_lang
            status = "Changing language to"
            log_level = logger.INFO
        finally:
            indexer_lang = language
            msg = msg.format(status=status)
            logger.log(msg, log_level)

    if scene == series_obj.scene and anime == series_obj.anime:
        do_update_scene_numbering = False
    else:
        do_update_scene_numbering = True

    if not isinstance(allowed_qualities, list):
        allowed_qualities = [allowed_qualities]

    if not isinstance(preferred_qualities, list):
        preferred_qualities = [preferred_qualities]

    if isinstance(exceptions, list):
        exceptions = set(exceptions)

    if not isinstance(exceptions, set):
        exceptions = {exceptions}

    # If directCall from mass_edit_update no scene exceptions handling or
    # blackandwhite list handling
    if directCall:
        do_update_exceptions = False
    else:
        if exceptions == series_obj.exceptions:
            do_update_exceptions = False
        else:
            do_update_exceptions = True

        with series_obj.lock:
            if anime:
                if not series_obj.release_groups:
                    series_obj.release_groups = BlackAndWhiteList(series_obj)

                if whitelist:
                    shortwhitelist = short_group_names(whitelist)
                    series_obj.release_groups.set_white_keywords(shortwhitelist)
                else:
                    series_obj.release_groups.set_white_keywords([])

                if blacklist:
                    shortblacklist = short_group_names(blacklist)
                    series_obj.release_groups.set_black_keywords(shortblacklist)
                else:
                    series_obj.release_groups.set_black_keywords([])

    with series_obj.lock:
        new_quality = Quality.combine_qualities(
            [int(q) for q in allowed_qualities], [int(q) for q in preferred_qualities]
        )
        series_obj.quality = new_quality

        # reversed for now
        if bool(series_obj.flatten_folders) != bool(flatten_folders):
            series_obj.flatten_folders = flatten_folders
            try:
                app.show_queue_scheduler.action.refreshShow(series_obj)
            except CantRefreshShowException as e:
                errors += 1
                logger.log(
                    "Unable to refresh show '{show}': {error}".format(
                        show=series_obj.name, error=e.message
                    ),
                    logger.WARNING,
                )

        # Check if we should erase parsed cached results for that show
        do_erase_parsed_cache = False
        for item in [
            ("scene", scene),
            ("anime", anime),
            ("sports", sports),
            ("air_by_date", air_by_date),
            ("dvd_order", dvd_order),
        ]:
            if getattr(series_obj, item[0]) != item[1]:
                do_erase_parsed_cache = True
                # Break if at least one setting was changed
                break

        series_obj.paused = paused
        series_obj.scene = scene
        series_obj.anime = anime
        series_obj.sports = sports
        series_obj.subtitles = subtitles
        series_obj.air_by_date = air_by_date
        series_obj.default_ep_status = int(defaultEpStatus)
        series_obj.dvd_order = dvd_order

        if not directCall:
            series_obj.lang = indexer_lang
            series_obj.rls_ignore_words = rls_ignore_words.strip()
            series_obj.rls_require_words = rls_require_words.strip()

        # if we change location clear the db of episodes, change it, write to db, and rescan
        old_location = os.path.normpath(series_obj._location)
        new_location = os.path.normpath(location)
        if old_location != new_location:
            changed_location = True
            logger.log(
                "Changing show location to: {new}".format(new=new_location), logger.INFO
            )
            if not os.path.isdir(new_location):
                if app.CREATE_MISSING_SHOW_DIRS:
                    logger.log("Show directory doesn't exist, creating it", logger.INFO)
                    try:
                        os.mkdir(new_location)
                    except OSError as error:
                        errors += 1
                        changed_location = False
                        logger.log(
                            "Unable to create the show directory '{location}'. Error: {msg}".format(
                                location=new_location, msg=error
                            ),
                            logger.WARNING,
                        )
                    else:
                        logger.log("New show directory created", logger.INFO)
                        helpers.chmod_as_parent(new_location)
                else:
                    logger.log(
                        "New location '{location}' does not exist. "
                        "Enable setting 'Create missing show dirs'".format(
                            location=location
                        ),
                        logger.WARNING,
                    )

            # Save new location to DB only if we changed it
            if changed_location:
                series_obj.location = new_location

            if (do_update or changed_location) and os.path.isdir(new_location):
                try:
                    app.show_queue_scheduler.action.refreshShow(series_obj)
                except CantRefreshShowException as e:
                    errors += 1
                    logger.log(
                        "Unable to refresh show '{show}'. Error: {error}".format(
                            show=series_obj.name, error=e.message
                        ),
                        logger.WARNING,
                    )

        # Save all settings changed while in series_obj.lock
        series_obj.save_to_db()

    # force the update
    if do_update:
        try:
            app.show_queue_scheduler.action.updateShow(series_obj)
            time.sleep(cpu_presets[app.CPU_PRESET])
        except CantUpdateShowException as e:
            errors += 1
            logger.log(
                "Unable to update show '{show}': {error}".format(
                    show=series_obj.name, error=e.message
                ),
                logger.WARNING,
            )

    if do_update_exceptions:
        try:
            update_scene_exceptions(series_obj, exceptions)
            time.sleep(cpu_presets[app.CPU_PRESET])
            name_cache.build_name_cache(series_obj)
        except CantUpdateShowException:
            errors += 1
            logger.log(
                "Unable to force an update on scene exceptions for show '{show}': {error}".format(
                    show=series_obj.name, error=e.message
                ),
                logger.WARNING,
            )

    if do_update_scene_numbering or do_erase_parsed_cache:
        try:
            xem_refresh(series_obj)
            time.sleep(cpu_presets[app.CPU_PRESET])
        except CantUpdateShowException:
            errors += 1
            logger.log(
                "Unable to force an update on scene numbering for show '{show}': {error}".format(
                    show=series_obj.name, error=e.message
                ),
                logger.WARNING,
            )

        # Must erase cached DB results when toggling scene numbering
        self.erase_cache(series_obj)

        # Erase parsed cached names as we are changing scene numbering
        series_obj.flush_episodes()
        series_obj.erase_cached_parse()

        # Need to refresh show as we updated scene numbering or changed show format
        try:
            app.show_queue_scheduler.action.refreshShow(series_obj)
        except CantRefreshShowException as e:
            errors += 1
            logger.log(
                "Unable to refresh show '{show}'. Please manually trigger a full show refresh. "
                "Error: {error}".format(show=series_obj.name, error=e.message),
                logger.WARNING,
            )

    if directCall:
        return errors

    if errors:
        ui.notifications.error(
            "Errors",
            "{num} error{s} while saving changes. Please check logs".format(
                num=errors, s="s" if errors > 1 else ""
            ),
        )

    logger.log(
        "Finished editing show: {show}".format(show=series_obj.name), logger.DEBUG
    )
    return self.redirect(
        "/home/displayShow?indexername={series_obj.indexer_name}&seriesid={series_obj.series_id}".format(
            series_obj=series_obj
        )
    )