# Buggy code
def _update_library(self, host=None, series_name=None):  # pylint: disable=too-many-return-statements, too-many-branches
    """Handle updating KODI host via HTTP JSON-RPC.

    Attempts to update the KODI video library for a specific tv show if passed,
    otherwise update the whole library if enabled.

    Args:
        host: KODI webserver host:port
        series_name: Name of a TV show to specifically target the library update for

    Returns:
        Returns True or False

    """
    if not host:
        log.warning("No KODI host passed, aborting update")
        return False

    log.info("Updating KODI library via JSON method for host: {0}", host)

    # if we're doing per-show
    if series_name:
        series_name = unquote_plus(series_name)
        tvshowid = -1
        path = ""

        log.debug("Updating library in KODI via JSON method for show {0}", series_name)

        # let's try letting kodi filter the shows
        shows_command = {
            "jsonrpc": "2.0",
            "method": "VideoLibrary.GetTVShows",
            "params": {
                "filter": {
                    "field": "title",
                    "operator": "is",
                    "value": series_name,
                },
                "properties": ["title"],
            },
            "id": "Medusa",
        }

        # get tvshowid by series_name
        series_response = self._send_to_kodi(shows_command, host)

        if (
            series_response
            and "result" in series_response
            and "tvshows" in series_response["result"]
        ):
            shows = series_response["result"]["tvshows"]
        else:
            # fall back to retrieving the entire show list
            shows_command = {
                "jsonrpc": "2.0",
                "method": "VideoLibrary.GetTVShows",
                "id": 1,
            }
            series_response = self._send_to_kodi(shows_command, host)

            if (
                series_response
                and "result" in series_response
                and "tvshows" in series_response["result"]
            ):
                shows = series_response["result"]["tvshows"]
            else:
                log.debug("KODI: No tvshows in KODI TV show list")
                return False

        for show in shows:
            if ("label" in show and show["label"] == series_name) or (
                "title" in show and show["title"] == series_name
            ):
                tvshowid = show["tvshowid"]
                # set the path is we have it already
                if "file" in show:
                    path = show["file"]

                break

        # this can be big, so free some memory
        del shows

        # we didn't find the show (exact match), thus revert to just doing a full update if enabled
        if tvshowid == -1:
            log.debug("Exact show name not matched in KODI TV show list")
            return False

        # lookup tv-show path if we don't already know it
        if not path:
            path_command = {
                "jsonrpc": "2.0",
                "method": "VideoLibrary.GetTVShowDetails",
                "params": {
                    "tvshowid": tvshowid,
                    "properties": ["file"],
                },
                "id": 1,
            }
            path_response = self._send_to_kodi(path_command, host)

            path = path_response["result"]["tvshowdetails"]["file"]

        log.debug(
            "Received Show: {0} with ID: {1} Path: {2}", series_name, tvshowid, path
        )

        if not path:
            log.warning(
                "No valid path found for {0} with ID: {1} on {2}",
                series_name,
                tvshowid,
                host,
            )
            return False

        log.debug("KODI Updating {0} on {1} at {2}", series_name, host, path)
        update_command = {
            "jsonrpc": "2.0",
            "method": "VideoLibrary.Scan",
            "params": {
                "directory": path,
            },
            "id": 1,
        }
        request = self._send_to_kodi(update_command, host)
        if not request:
            log.warning(
                "Update of show directory failed on {0} on {1} at {2}",
                series_name,
                host,
                path,
            )
            return False

        # catch if there was an error in the returned request
        for r in request:
            if "error" in r:
                log.warning(
                    "Error while attempting to update show directory for {0} on {1} at {2} ",
                    series_name,
                    host,
                    path,
                )
                return False

    # do a full update if requested
    else:
        log.debug("Doing Full Library KODI update on host: {0}", host)
        update_command = {
            "jsonrpc": "2.0",
            "method": "VideoLibrary.Scan",
            "id": 1,
        }
        request = self._send_to_kodi(update_command, host)

        if not request:
            log.warning("KODI Full Library update failed on: {0}", host)
            return False

    return True


# Traceback (AttributeError)
2019-03-15 05:03:02 ERROR    TORNADO :: [94fae84] API :: AttributeError("'str' object has no attribute 'decode'")
Traceback (most recent call last):
File "/Users/matt/Builds/medusa/medusa/server/api/v1/core.py", line 142, in get
out_dict = _call_dispatcher(args, kwargs)
File "/Users/matt/Builds/medusa/medusa/server/api/v1/core.py", line 212, in call_dispatcher
cur_out_dict = func(cur_args, cur_kwargs).run()  # call function and get response
File "/Users/matt/Builds/medusa/medusa/server/api/v1/core.py", line 1308, in run
failed=self.failed, proc_type=self.type
File "/Users/matt/Builds/medusa/medusa/process_tv.py", line 145, in process
ignore_subs=ignore_subs)
File "/Users/matt/Builds/medusa/medusa/process_tv.py", line 335, in process_files
self.process_media(path, self.video_files, force, is_priority, ignore_subs)
File "/Users/matt/Builds/medusa/medusa/process_tv.py", line 556, in process_media
self.result = processor.process()
File "/Users/matt/Builds/medusa/medusa/post_processor.py", line 1289, in process
notifiers.notify_download(ep_obj)
File "/Users/matt/Builds/medusa/medusa/notifiers/__init__.py", line 100, in notify_download
n.notify_download(ep_obj)
File "/Users/matt/Builds/medusa/medusa/notifiers/kodi.py", line 434, in notify_download
self._notify_kodi(common.notifyStrings[common.NOTIFY_DOWNLOAD], ep_obj.pretty_name_with_quality())
File "/Users/matt/Builds/medusa/medusa/notifiers/kodi.py", line 133, in _notify_kodi
result += cur_host + ':' + notify_result['result'].decode('utf-8')
AttributeError: 'str' object has no attribute 'decode'
2019-03-15 05:03:02 INFO     TORNADO :: [94fae84] Selected poster for series 275557 (score=3.3221824253021945, score_bay=5.644364850604389, rating=6.8, votes=20, res=680x1000): https://www.thetvdb.com/banners/posters/275557-6.jpg
2019-03-15 05:03:02 INFO     TORNADO :: [94fae84] Selected fanart for series 275557 (score=3.9240400637751476, score_bay=5.848080127550295, rating=6.9, votes=9, res=1920x1080): https://www.thetvdb.com/banners/fanart/original/275557-8.jpg
2019-03-15 05:03:00 INFO     TORNADO :: [94fae84] 275557: Changed modify date of Broad.City.S05E08.Sleep.No.More.720p.WEB-DL.mkv to series air date Mar 14,2019 (22:00)
2019-03-15 05:02:46 INFO     TORNADO :: [94fae84] Release name (broad.city.s05e08.720p.web.x264-tbs) found from file (broad.city.s05e08.720p.web.x264-tbs.nfo)
2019-03-15 05:02:46 INFO     TORNADO :: [94fae84] This download is marked a priority download so I'm going to replace an existing file if I find one
2019-03-15 05:02:46 INFO     TORNADO :: [94fae84] New size: 432.58 MB
2019-03-15 05:02:46 INFO     TORNADO :: [94fae84] New file: /Volumes/dvorak.8tb/SABnzbd/tv/Broad.City.S05E08.720p.WEB.x264-TBS[TGx]/broad.city.s05e08.720p.web.x264-tbs.mkv
2019-03-15 05:02:46 INFO     TORNADO :: [94fae84] Processing /Volumes/dvorak.8tb/SABnzbd/tv/Broad.City.S05E08.720p.WEB.x264-TBS[TGx]/broad.city.s05e08.720p.web.x264-tbs.mkv

# Fixed code
def _update_library(self, host=None, series_name=None):
    """Handle updating KODI host via HTTP JSON-RPC.

    Attempts to update the KODI video library for a specific tv show if passed,
    otherwise update the whole library if enabled.

    Args:
        host: KODI webserver host:port
        series_name: Name of a TV show to specifically target the library update for

    Returns:
        Returns True or False

    """
    if not host:
        log.warning("No KODI host passed, aborting update")
        return False

    log.info("Updating KODI library via JSON method for host: {0}", host)

    # if we're doing per-show
    if series_name:
        series_name = unquote_plus(series_name)
        tvshowid = -1
        path = ""

        log.debug("Updating library in KODI via JSON method for show {0}", series_name)

        # let's try letting kodi filter the shows
        shows_command = {
            "jsonrpc": "2.0",
            "method": "VideoLibrary.GetTVShows",
            "params": {
                "filter": {
                    "field": "title",
                    "operator": "is",
                    "value": series_name,
                },
                "properties": ["title"],
            },
            "id": "Medusa",
        }

        # get tvshowid by series_name
        series_response = self._send_to_kodi(shows_command, host)

        if (
            series_response
            and "result" in series_response
            and "tvshows" in series_response["result"]
        ):
            shows = series_response["result"]["tvshows"]
        else:
            # fall back to retrieving the entire show list
            shows_command = {
                "jsonrpc": "2.0",
                "method": "VideoLibrary.GetTVShows",
                "id": 1,
            }
            series_response = self._send_to_kodi(shows_command, host)

            if (
                series_response
                and "result" in series_response
                and "tvshows" in series_response["result"]
            ):
                shows = series_response["result"]["tvshows"]
            else:
                log.debug("KODI: No tvshows in KODI TV show list")
                return False

        for show in shows:
            if ("label" in show and show["label"] == series_name) or (
                "title" in show and show["title"] == series_name
            ):
                tvshowid = show["tvshowid"]
                # set the path is we have it already
                if "file" in show:
                    path = show["file"]

                break

        # this can be big, so free some memory
        del shows

        # we didn't find the show (exact match), thus revert to just doing a full update if enabled
        if tvshowid == -1:
            log.debug("Exact show name not matched in KODI TV show list")
            return False

        # lookup tv-show path if we don't already know it
        if not path:
            path_command = {
                "jsonrpc": "2.0",
                "method": "VideoLibrary.GetTVShowDetails",
                "params": {
                    "tvshowid": tvshowid,
                    "properties": ["file"],
                },
                "id": 1,
            }
            path_response = self._send_to_kodi(path_command, host)

            path = path_response["result"]["tvshowdetails"]["file"]

        log.debug(
            "Received Show: {0} with ID: {1} Path: {2}", series_name, tvshowid, path
        )

        if not path:
            log.warning(
                "No valid path found for {0} with ID: {1} on {2}",
                series_name,
                tvshowid,
                host,
            )
            return False

        log.debug("KODI Updating {0} on {1} at {2}", series_name, host, path)
        update_command = {
            "jsonrpc": "2.0",
            "method": "VideoLibrary.Scan",
            "params": {
                "directory": path,
            },
            "id": 1,
        }
        request = self._send_to_kodi(update_command, host)
        if not request:
            log.warning(
                "Update of show directory failed on {0} on {1} at {2}",
                series_name,
                host,
                path,
            )
            return False

        # catch if there was an error in the returned request
        for r in request:
            if "error" in r:
                log.warning(
                    "Error while attempting to update show directory for {0} on {1} at {2} ",
                    series_name,
                    host,
                    path,
                )
                return False

    # do a full update if requested
    else:
        log.debug("Doing Full Library KODI update on host: {0}", host)
        update_command = {
            "jsonrpc": "2.0",
            "method": "VideoLibrary.Scan",
            "id": 1,
        }
        request = self._send_to_kodi(update_command, host)

        if not request:
            log.warning("KODI Full Library update failed on: {0}", host)
            return False

    return True