class SimpleLogging:
    name = ""
    enable_logging = False

    def __init__(self, name):
        settings = xbmcaddon.Addon()
        prefix = settings.getAddonInfo('name')
        self.name = prefix + '.' + name
        self.enable_logging = settings.getSetting('log_debug') == "true"

        # params = {"setting": "debug.showloginfo"}
        # setting_result = json_rpc('Settings.getSettingValue').execute(params)
        # current_value = setting_result.get("result", None)
        # if current_value is not None:
        #     self.enable_logging = current_value.get("value", False)
        # xbmc.log("LOGGING_ENABLED %s : %s" % (self.name, str(self.enable_logging)), level=xbmc.LOGDEBUG)

    def __str__(self):
        return "LoggingEnabled: " + str(self.enable_logging)

    def info(self, fmt, *args, **kwargs):
        log_line = self.name + "|INFO|" + self.log_line(fmt, *args)
        xbmc.log(log_line, level=xbmc.LOGNOTICE)

    def error(self, fmt, *args, **kwargs):
        log_line = self.name + "|ERROR|" + self.log_line(fmt, *args)
        xbmc.log(log_line, level=xbmc.LOGERROR)

    def debug(self, fmt, *args, **kwargs):
        if self.enable_logging:
            log_line = self.name + "|DEBUG|" + self.log_line(fmt, *args)
            xbmc.log(log_line, level=xbmc.LOGNOTICE)

    @staticmethod
    def log_line(fmt, *args):
        new_args = []
        # convert any unicode to utf-8 strings
        for arg in args:
            if isinstance(arg, unicode):
                new_args.append(arg.encode("utf-8"))
            else:
                new_args.append(arg)
        log_line = fmt.format(*new_args)
        return log_line class DownloadUtils:
    use_https = False
    verify_cert = False

    def __init__(self, *args):
        settings = xbmcaddon.Addon()

        self.use_https = False
        if settings.getSetting('protocol') == "1":
            self.use_https = True
        log.debug("use_https: {0}", self.use_https)

        self.verify_cert = settings.getSetting('verify_cert') == 'true'
        log.debug("verify_cert: {0}", self.verify_cert)

    @timer
    def post_capabilities(self):

        url = "{server}/emby/Sessions/Capabilities/Full?format=json"
        data = {
            'IconUrl': "https://raw.githubusercontent.com/faush01/plugin.video.embycon/develop/kodi.png",
            'SupportsMediaControl': True,
            'PlayableMediaTypes': ["Video", "Audio"],
            'SupportedCommands': ["MoveUp",
                                  "MoveDown",
                                  "MoveLeft",
                                  "MoveRight",
                                  "Select",
                                  "Back",
                                  "ToggleContextMenu",
                                  "ToggleFullscreen",
                                  "ToggleOsdMenu",
                                  "GoHome",
                                  "PageUp",
                                  "NextLetter",
                                  "GoToSearch",
                                  "GoToSettings",
                                  "PageDown",
                                  "PreviousLetter",
                                  "TakeScreenshot",
                                  "VolumeUp",
                                  "VolumeDown",
                                  "ToggleMute",
                                  "SendString",
                                  "DisplayMessage",
                                  "SetAudioStreamIndex",
                                  "SetSubtitleStreamIndex",
                                  "SetRepeatMode",
                                  "Mute",
                                  "Unmute",
                                  "SetVolume",
                                  "PlayNext",
                                  "Play",
                                  "Playstate",
                                  "PlayMediaSource"]
        }

        self.download_url(url, post_body=data, method="POST")
        log.debug("Posted Capabilities: {0}", data)

    @timer
    def get_item_playback_info(self, item_id, force_transcode):

        addon_settings = xbmcaddon.Addon()

        # ["hevc", "h265", "h264", "mpeg4", "msmpeg4v3", "mpeg2video", "vc1"]
        filtered_codecs = []
        if addon_settings.getSetting("force_transcode_h265") == "true":
            filtered_codecs.append("hevc")
            filtered_codecs.append("h265")
        if addon_settings.getSetting("force_transcode_mpeg2") == "true":
            filtered_codecs.append("mpeg2video")
        if addon_settings.getSetting("force_transcode_msmpeg4v3") == "true":
            filtered_codecs.append("msmpeg4v3")
        if addon_settings.getSetting("force_transcode_mpeg4") == "true":
            filtered_codecs.append("mpeg4")

        playback_bitrate = addon_settings.getSetting("max_stream_bitrate")
        force_playback_bitrate = addon_settings.getSetting("force_max_stream_bitrate")
        if force_transcode:
            playback_bitrate = force_playback_bitrate

        audio_codec = addon_settings.getSetting("audio_codec")
        audio_playback_bitrate = addon_settings.getSetting("audio_playback_bitrate")
        audio_max_channels = addon_settings.getSetting("audio_max_channels")

        audio_bitrate = int(audio_playback_bitrate) * 1000
        bitrate = int(playback_bitrate) * 1000

        profile = {
            "Name": "Kodi",
            "MaxStaticBitrate": bitrate,
            "MaxStreamingBitrate": bitrate,
            "MusicStreamingTranscodingBitrate": audio_bitrate,
            "TimelineOffsetSeconds": 5,
            "TranscodingProfiles": [
                {
                    "Type": "Audio"
                },
                {
                    "Container": "ts",
                    "Protocol": "hls",
                    "Type": "Video",
                    "AudioCodec": audio_codec,
                    "VideoCodec": "h264",
                    "MaxAudioChannels": audio_max_channels
                },
                {
                    "Container": "jpeg",
                    "Type": "Photo"
                }
            ],
            "DirectPlayProfiles": [
                {
                    "Type": "Video"
                },
                {
                    "Type": "Audio"
                },
                {
                    "Type": "Photo"
                }
            ],
            "ResponseProfiles": [],
            "ContainerProfiles": [],
            "CodecProfiles": [],
            "SubtitleProfiles": [
                {
                    "Format": "srt",
                    "Method": "External"
                },
                {
                    "Format": "srt",
                    "Method": "Embed"
                },
                {
                    "Format": "ass",
                    "Method": "External"
                },
                {
                    "Format": "ass",
                    "Method": "Embed"
                },
                {
                    "Format": "sub",
                    "Method": "Embed"
                },
                {
                    "Format": "sub",
                    "Method": "External"
                },
                {
                    "Format": "ssa",
                    "Method": "Embed"
                },
                {
                    "Format": "ssa",
                    "Method": "External"
                },
                {
                    "Format": "smi",
                    "Method": "Embed"
                },
                {
                    "Format": "smi",
                    "Method": "External"
                },
                {
                    "Format": "pgssub",
                    "Method": "Embed"
                },
                {
                    "Format": "pgssub",
                    "Method": "External"
                },
                {
                    "Format": "dvdsub",
                    "Method": "Embed"
                },
                {
                    "Format": "dvdsub",
                    "Method": "External"
                },
                {
                    "Format": "pgs",
                    "Method": "Embed"
                },
                {
                    "Format": "pgs",
                    "Method": "External"
                }
            ]
        }

        if len(filtered_codecs) > 0:
            profile['DirectPlayProfiles'][0]['VideoCodec'] = "-%s" % ",".join(filtered_codecs)

        if force_transcode:
            profile['DirectPlayProfiles'] = []

        if addon_settings.getSetting("playback_video_force_8") == "true":
            profile['CodecProfiles'].append(
                {
                    "Type": "Video",
                    "Codec": "h264",
                    "Conditions": [
                        {
                            "Condition": "LessThanEqual",
                            "Property": "VideoBitDepth",
                            "Value": "8",
                            "IsRequired": False
                        }
                    ]
                }
            )
            profile['CodecProfiles'].append(
                {
                    "Type": "Video",
                    "Codec": "h265,hevc",
                    "Conditions": [
                        {
                            "Condition": "EqualsAny",
                            "Property": "VideoProfile",
                            "Value": "main"
                        }
                    ]
                }
            )

        playback_info = {
            'UserId': self.get_user_id(),
            'DeviceProfile': profile,
            'AutoOpenLiveStream': True
        }

        if force_transcode:
            url = "{server}/emby/Items/%s/PlaybackInfo?MaxStreamingBitrate=%s&EnableDirectPlay=false&EnableDirectStream=false" % (item_id, bitrate)
        else:
            url = "{server}/emby/Items/%s/PlaybackInfo?MaxStreamingBitrate=%s" % (item_id, bitrate)

        log.debug("PlaybackInfo : {0}", url)
        log.debug("PlaybackInfo : {0}", profile)
        play_info_result = self.download_url(url, post_body=playback_info, method="POST")
        play_info_result = json.loads(play_info_result)
        log.debug("PlaybackInfo : {0}", play_info_result)

        return play_info_result

    def get_server(self):
        settings = xbmcaddon.Addon()
        host = settings.getSetting('ipaddress')

        if len(host) == 0 or host == "<none>":
            return None

        port = settings.getSetting('port')

        if not port and self.use_https:
            port = "443"
            settings.setSetting("port", port)
        elif not port:
            port = "80"
            settings.setSetting("port", port)

        # if user entered a full path i.e. http://some_host:port
        if host.lower().strip().startswith("http://") or host.lower().strip().startswith("https://"):
            log.debug("Extracting host info from url: {0}", host)
            url_bits = urlparse(host.strip())

            if host.lower().strip().startswith("http://"):
                settings.setSetting('protocol', '0')
                self.use_https = False
            elif host.lower().strip().startswith("https://"):
                settings.setSetting('protocol', '1')
                self.use_https = True

            if url_bits.hostname is not None and len(url_bits.hostname) > 0:
                host = url_bits.hostname

                if url_bits.username and url_bits.password:
                    host = "%s:%s@" % (url_bits.username, url_bits.password) + host

                settings.setSetting("ipaddress", host)

            if url_bits.port is not None and url_bits.port > 0:
                port = str(url_bits.port)
                settings.setSetting("port", port)

        if self.use_https:
            server = "https://" + host + ":" + port
        else:
            server = "http://" + host + ":" + port

        return server

    @staticmethod
    def get_all_artwork(item, server):
        all_art = defaultdict(lambda: "")

        item_id = item["Id"]
        item_type = item["Type"]
        image_tags = item["ImageTags"]
        # bg_item_tags = item["ParentBackdropImageTags"]

        # All the image tags
        for tag_name in image_tags:
            tag = image_tags[tag_name]
            art_url = "%s/emby/Items/%s/Images/%s/0?Format=original&Tag=%s" % (server, item_id, tag_name, tag)
            all_art[tag_name] = art_url

        # Series images
        if item_type in ["Episode", "Season"]:
            image_tag = item["SeriesPrimaryImageTag"]
            series_id = item["SeriesId"]
            if image_tag and series_id:
                art_url = "%s/emby/Items/%s/Images/Primary/0?Format=original&Tag=%s" % (server, series_id, image_tag)
                all_art["Primary.Series"] = art_url

        return all_art

    def get_artwork(self, data, art_type, parent=False, index=0, server=None):

        item_id = data["Id"]
        item_type = data["Type"]

        if item_type in ["Episode", "Season"]:
            if art_type != "Primary" or parent is True:
                item_id = data["SeriesId"]

        image_tag = ""
        # "e3ab56fe27d389446754d0fb04910a34" # a place holder tag, needs to be in this format

        # for episodes always use the parent BG
        if item_type == "Episode" and art_type == "Backdrop":
            item_id = data["ParentBackdropItemId"]
            bg_item_tags = data["ParentBackdropImageTags"]
            if bg_item_tags is not None and len(bg_item_tags) > 0:
                image_tag = bg_item_tags[0]
        elif art_type == "Backdrop" and parent is True:
            item_id = data["ParentBackdropItemId"]
            bg_item_tags = data["ParentBackdropImageTags"]
            if bg_item_tags is not None and len(bg_item_tags) > 0:
                image_tag = bg_item_tags[0]
        elif art_type == "Backdrop":
            bg_tags = data["BackdropImageTags"]
            if bg_tags is not None and len(bg_tags) > index:
                image_tag = bg_tags[index]
                # log.debug("Background Image Tag: {0}", imageTag)
        elif parent is False:
            image_tags = data["ImageTags"]
            if image_tags is not None:
                image_tag_type = image_tags[art_type]
                if image_tag_type is not None:
                    image_tag = image_tag_type
                    # log.debug("Image Tag: {0}", imageTag)
        elif parent is True:
            if (item_type == "Episode" or item_type == "Season") and art_type == 'Primary':
                tag_name = 'SeriesPrimaryImageTag'
                id_name = 'SeriesId'
            else:
                tag_name = 'Parent%sImageTag' % art_type
                id_name = 'Parent%sItemId' % art_type
            parent_image_id = data[id_name]
            parent_image_tag = data[tag_name]
            if parent_image_id is not None and parent_image_tag is not None:
                item_id = parent_image_id
                image_tag = parent_image_tag
                # log.debug("Parent Image Tag: {0}", imageTag)

        # ParentTag not passed for Banner and Art
        if not image_tag and not ((art_type == 'Banner' or art_type == 'Art') and parent is True):
            # log.debug("No Image Tag for request:{0} item:{1} parent:{2}", art_type, item_type, parent)
            return ""

        artwork = "%s/emby/Items/%s/Images/%s/%s?Format=original&Tag=%s" % (server, item_id, art_type, index, image_tag)

        if self.use_https and not self.verify_cert:
            artwork += "|verifypeer=false"

        # log.debug("getArtwork: request:{0} item:{1} parent:{2} link:{3}", art_type, item_type, parent, artwork)

        '''
        # do not return non-existing images
        if (    (art_type != "Backdrop" and imageTag == "") |
                (art_type == "Backdrop" and data.get("BackdropImageTags") != None and len(data.get("BackdropImageTags")) == 0) |
                (art_type == "Backdrop" and data.get("BackdropImageTag") != None and len(data.get("BackdropImageTag")) == 0)
                ):
            artwork = ''
        '''

        return artwork

    def image_url(self, item_id, art_type, index, width, height, image_tag, server):

        # test imageTag e3ab56fe27d389446754d0fb04910a34
        artwork = "%s/emby/Items/%s/Images/%s/%s?Format=original&Tag=%s" % (server, item_id, art_type, index, image_tag)
        if int(width) > 0:
            artwork += '&MaxWidth=%s' % width
        if int(height) > 0:
            artwork += '&MaxHeight=%s' % height

        if self.use_https and not self.verify_cert:
            artwork += "|verifypeer=false"

        return artwork

    def get_user_artwork(self, user, item_type):

        if "PrimaryImageTag" not in user:
            return ""
        user_id = user.get("Id")
        tag = user.get("PrimaryImageTag")
        server = self.get_server()

        artwork = "%s/emby/Users/%s/Images/%s?Format=original&tag=%s" % (server, user_id, item_type, tag)

        if self.use_https and not self.verify_cert:
            artwork += "|verifypeer=false"

        return artwork

    def get_user_id(self):

        window = HomeWindow()
        userid = window.get_property("userid")
        user_image = window.get_property("userimage")

        if userid and user_image:
            log.debug("EmbyCon DownloadUtils -> Returning saved UserID: {0}", userid)
            return userid

        settings = xbmcaddon.Addon()
        user_details = load_user_details(settings)
        user_name = user_details.get("username", "")

        if not user_name:
            return ""
        log.debug("Looking for user name: {0}", user_name)

        try:
            json_data = self.download_url("{server}/emby/Users/Public?format=json", suppress=True, authenticate=False)
        except Exception as msg:
            log.error("Get User unable to connect: {0}", msg)
            return ""

        log.debug("GETUSER_JSONDATA_01: {0}", json_data)

        try:
            result = json.loads(json_data)
        except Exception as e:
            log.debug("Could not load user data: {0}", e)
            return ""

        if result is None:
            return ""

        log.debug("GETUSER_JSONDATA_02: {0}", result)

        secure = False
        for user in result:
            if user.get("Name") == unicode(user_name, "utf-8"):
                userid = user.get("Id")
                user_image = self.get_user_artwork(user, 'Primary')
                log.debug("Username Found: {0}", user.get("Name"))
                if user.get("HasPassword", False):
                    secure = True
                    log.debug("Username Is Secure (HasPassword=True)")
                break

        if secure or not userid:
            auth_ok = self.authenticate()
            if auth_ok == "":
                xbmcgui.Dialog().notification(string_load(30316),
                                              string_load(30044),
                                              icon="special://home/addons/plugin.video.embycon/icon.png")
                return ""
            if not userid:
                userid = window.get_property("userid")

        if userid and not user_image:
            user_image = 'DefaultUser.png'

        if userid == "":
            xbmcgui.Dialog().notification(string_load(30316),
                                          string_load(30045),
                                          icon="special://home/addons/plugin.video.embycon/icon.png")

        log.debug("userid: {0}", userid)

        window.set_property("userid", userid)
        window.set_property("userimage", user_image)

        return userid

    @timer
    def authenticate(self):

        window = HomeWindow()

        token = window.get_property("AccessToken")
        if token is not None and token != "":
            log.debug("EmbyCon DownloadUtils -> Returning saved AccessToken: {0}", token)
            return token

        settings = xbmcaddon.Addon()
        port = settings.getSetting("port")
        host = settings.getSetting("ipaddress")
        if host is None or host == "" or port is None or port == "":
            return ""

        url = "{server}/emby/Users/AuthenticateByName?format=json"

        user_details = load_user_details(settings)
        user_name = urllib.quote(user_details.get("username", ""))
        pwd_text = urllib.quote(user_details.get("password", ""))

        message_data = "username=" + user_name + "&pw=" + pwd_text

        resp = self.download_url(url, post_body=message_data, method="POST", suppress=True, authenticate=False)
        log.debug("AuthenticateByName: {0}", resp)

        access_token = None
        userid = None
        try:
            result = json.loads(resp)
            access_token = result.get("AccessToken")
            # userid = result["SessionInfo"].get("UserId")
            userid = result["User"].get("Id")
        except:
            pass

        if access_token is not None:
            log.debug("User Authenticated: {0}", access_token)
            log.debug("User Id: {0}", userid)
            window.set_property("AccessToken", access_token)
            window.set_property("userid", userid)
            # WINDOW.setProperty("userimage", "")

            self.post_capabilities()

            return access_token
        else:
            log.debug("User NOT Authenticated")
            window.set_property("AccessToken", "")
            window.set_property("userid", "")
            window.set_property("userimage", "")
            return ""

    def get_auth_header(self, authenticate=True):
        client_info = ClientInformation()
        txt_mac = client_info.get_device_id()
        version = client_info.get_version()
        client = client_info.get_client()

        settings = xbmcaddon.Addon()
        device_name = settings.getSetting('deviceName')
        # remove none ascii chars
        device_name = device_name.decode("ascii", errors='ignore')
        # remove some chars not valid for names
        device_name = device_name.replace("\"", "_")
        if len(device_name) == 0:
            device_name = "EmbyCon"

        headers = {}
        headers["Accept-encoding"] = "gzip"
        headers["Accept-Charset"] = "UTF-8,*"

        if authenticate is False:
            auth_string = "MediaBrowser Client=\"" + client + "\",Device=\"" + device_name + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
            # headers["Authorization"] = authString
            headers['X-Emby-Authorization'] = auth_string
            return headers
        else:
            userid = self.get_user_id()
            auth_string = "MediaBrowser UserId=\"" + userid + "\",Client=\"" + client + "\",Device=\"" + device_name + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
            # headers["Authorization"] = authString
            headers['X-Emby-Authorization'] = auth_string

            auth_token = self.authenticate()
            if auth_token != "":
                headers["X-MediaBrowser-Token"] = auth_token

            log.debug("EmbyCon Authentication Header: {0}", headers)
            return headers

    @timer
    def download_url(self, url, suppress=False, post_body=None, method="GET", authenticate=True, headers=None):
        log.debug("downloadUrl")

        return_data = "null"
        settings = xbmcaddon.Addon()
        user_details = load_user_details(settings)
        username = user_details.get("username", "")
        server = None

        http_timeout = int(settings.getSetting("http_timeout"))

        if authenticate and username == "":
            return return_data

        if settings.getSetting("suppressErrors") == "true":
            suppress = True

        log.debug("Before: {0}", url)

        if url.find("{server}") != -1:
            server = self.get_server()
            if server is None:
                return return_data
            url = url.replace("{server}", server)

        if url.find("{userid}") != -1:
            userid = self.get_user_id()
            if not userid:
                return return_data
            url = url.replace("{userid}", userid)

        if url.find("{ItemLimit}") != -1:
            show_x_filtered_items = settings.getSetting("show_x_filtered_items")
            url = url.replace("{ItemLimit}", show_x_filtered_items)

        if url.find("{field_filters}") != -1:
            filter_string = get_details_string()
            url = url.replace("{field_filters}", filter_string)

        if url.find("{random_movies}") != -1:
            home_window = HomeWindow()
            random_movies = home_window.get_property("random-movies")
            if not random_movies:
                return return_data
            url = url.replace("{random_movies}", random_movies)

        log.debug("After: {0}", url)
        conn = None

        try:

            url_bits = urlparse(url.strip())

            protocol = url_bits.scheme
            host_name = url_bits.hostname
            port = url_bits.port
            user_name = url_bits.username
            user_password = url_bits.password
            url_path = url_bits.path
            url_puery = url_bits.query

            if not host_name or host_name == "<none>":
                return return_data

            local_use_https = False
            if protocol.lower() == "https":
                local_use_https = True

            server = "%s:%s" % (host_name, port)
            url_path = url_path + "?" + url_puery

            if local_use_https and self.verify_cert:
                log.debug("Connection: HTTPS, Cert checked")
                conn = httplib.HTTPSConnection(server, timeout=http_timeout)
            elif local_use_https and not self.verify_cert:
                log.debug("Connection: HTTPS, Cert NOT checked")
                conn = httplib.HTTPSConnection(server, timeout=http_timeout, context=ssl._create_unverified_context())
            else:
                log.debug("Connection: HTTP")
                conn = httplib.HTTPConnection(server, timeout=http_timeout)

            head = self.get_auth_header(authenticate)

            if user_name and user_password:
                # add basic auth headers
                user_and_pass = b64encode(b"%s:%s" % (user_name, user_password)).decode("ascii")
                head["Authorization"] = 'Basic %s' % user_and_pass

            head["User-Agent"] = "EmbyCon-" + ClientInformation().get_version()
            log.debug("HEADERS: {0}", head)

            if post_body is not None:
                if isinstance(post_body, dict):
                    content_type = "application/json"
                    post_body = json.dumps(post_body)
                else:
                    content_type = "application/x-www-form-urlencoded"

                head["Content-Type"] = content_type
                log.debug("Content-Type: {0}", content_type)

                log.debug("POST DATA: {0}", post_body)
                conn.request(method=method, url=url_path, body=post_body, headers=head)
            else:
                conn.request(method=method, url=url_path, headers=head)

            data = conn.getresponse()
            log.debug("HTTP response: {0} {1}", data.status, data.reason)
            log.debug("GET URL HEADERS: {0}", data.getheaders())

            if int(data.status) == 200:
                ret_data = data.read()
                content_type = data.getheader('content-encoding')
                log.debug("Data Len Before: {0}", len(ret_data))
                if content_type == "gzip":
                    ret_data = StringIO.StringIO(ret_data)
                    gzipper = gzip.GzipFile(fileobj=ret_data)
                    return_data = gzipper.read()
                else:
                    return_data = ret_data
                if headers is not None and isinstance(headers, dict):
                    headers.update(data.getheaders())
                log.debug("Data Len After: {0}", len(return_data))
                log.debug("====== 200 returned =======")
                log.debug("Content-Type: {0}", content_type)
                log.debug("{0}", return_data)
                log.debug("====== 200 finished ======")

            elif int(data.status) >= 400:

                if int(data.status) == 401:
                    # remove any saved password
                    m = hashlib.md5()
                    m.update(username)
                    hashed_username = m.hexdigest()
                    log.error("HTTP response error 401 auth error, removing any saved passwords for user: {0}", hashed_username)
                    settings.setSetting("saved_user_password_" + hashed_username, "")
                    save_user_details(settings, "", "")

                log.error("HTTP response error: {0} {1}", data.status, data.reason)
                if suppress is False:
                    xbmcgui.Dialog().notification(string_load(30316),
                                                  string_load(30200) % str(data.reason),
                                                  icon="special://home/addons/plugin.video.embycon/icon.png")

        except Exception as msg:
            log.error("Unable to connect to {0} : {1}", server, msg)
            if suppress is False:
                xbmcgui.Dialog().notification(string_load(30316),
                                              str(msg),
                                              icon="special://home/addons/plugin.video.embycon/icon.png")

        finally:
            try:
                log.debug("Closing HTTP connection: {0}", conn)
                conn.close()
            except:
                pass

        return return_data class ResumeDialog(xbmcgui.WindowXMLDialog):
    resumePlay = -1
    resumeTimeStamp = ""
    action_exitkeys_id = None

    def __init__(self, *args, **kwargs):
        xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
        log.debug("ResumeDialog INITIALISED")

    def onInit(self):
        self.action_exitkeys_id = [10, 13]
        self.getControl(3010).setLabel(self.resumeTimeStamp)
        self.getControl(3011).setLabel(string_load(30237))

    def onFocus(self, controlId):
        pass

    def doAction(self, actionID):
        pass

    def onClick(self, controlID):

        if controlID == 3010:
            self.resumePlay = 0
            self.close()
        if controlID == 3011:
            self.resumePlay = 1
            self.close()

    def setResumeTime(self, timeStamp):
        self.resumeTimeStamp = timeStamp

    def getResumeAction(self):
        return self.resumePlay class PlayUtils:

    @staticmethod
    def get_play_url(media_source):
        log.debug("get_play_url - media_source: {0}", media_source)

        # check if strm file Container
        if media_source.get('Container') == 'strm':
            log.debug("Detected STRM Container")
            playurl, listitem_props = PlayUtils().get_strm_details(media_source)
            if playurl is None:
                log.debug("Error, no strm content")
                return None, None, None
            else:
                return playurl, "0", listitem_props

        # get all the options
        addon_settings = xbmcaddon.Addon()
        server = downloadUtils.get_server()
        use_https = addon_settings.getSetting('protocol') == "1"
        verify_cert = addon_settings.getSetting('verify_cert') == 'true'
        allow_direct_file_play = addon_settings.getSetting('allow_direct_file_play') == 'true'

        can_direct_play = media_source["SupportsDirectPlay"]
        can_direct_stream = media_source["SupportsDirectStream"]
        can_transcode = media_source["SupportsTranscoding"]
        container = media_source["Container"]

        playurl = None
        playback_type = None

        # check if file can be directly played
        if allow_direct_file_play and can_direct_play:
            direct_path = media_source["Path"]
            direct_path = direct_path.replace("\\", "/")
            direct_path = direct_path.strip()

            # handle DVD structure
            if container == "dvd":
                direct_path = direct_path + "/VIDEO_TS/VIDEO_TS.IFO"
            elif container == "bluray":
                direct_path = direct_path + "/BDMV/index.bdmv"

            if direct_path.startswith("//"):
                direct_path = "smb://" + direct_path[2:]

            log.debug("playback_direct_path: {0}", direct_path)

            if xbmcvfs.exists(direct_path):
                playurl = direct_path
                playback_type = "0"

        # check if file can be direct streamed
        if can_direct_stream and playurl is None:
            direct_stream_path = media_source["DirectStreamUrl"]
            direct_stream_path = server + "/emby" + direct_stream_path
            if use_https and not verify_cert:
                direct_stream_path += "|verifypeer=false"
            playurl = direct_stream_path
            playback_type = "1"

        # check is file can be transcoded
        if can_transcode and playurl is None:
            transcode_stream_path = media_source["TranscodingUrl"]

            url_path, url_params = transcode_stream_path.split('?')

            params = url_params.split('&')
            log.debug("Streaming Params Before : {0}", params)

            # remove the audio and subtitle indexes
            # this will be replaced by user selection dialogs in Kodi
            params_to_remove = ["AudioStreamIndex", "SubtitleStreamIndex", "AudioBitrate"]
            reduced_params = []
            for param in params:
                param_bits = param.split("=")
                if param_bits[0] not in params_to_remove:
                    reduced_params.append(param)

            audio_playback_bitrate = addon_settings.getSetting("audio_playback_bitrate")
            audio_bitrate = int(audio_playback_bitrate) * 1000
            reduced_params.append("AudioBitrate=%s" % audio_bitrate)

            playback_max_width = addon_settings.getSetting("playback_max_width")
            reduced_params.append("MaxWidth=%s" % playback_max_width)

            log.debug("Streaming Params After : {0}", reduced_params)

            new_url_params = "&".join(reduced_params)

            transcode_stream_path = server + "/emby" + url_path + "?" + new_url_params

            if use_https and not verify_cert:
                transcode_stream_path += "|verifypeer=false"

            playurl = transcode_stream_path
            playback_type = "2"

        return playurl, playback_type, []

    @staticmethod
    def get_strm_details(media_source):
        playurl = None
        listitem_props = []

        contents = media_source.get('Path').encode('utf-8')  # contains contents of strm file with linebreaks

        line_break = '\r'
        if '\r\n' in contents:
            line_break = '\r\n'
        elif '\n' in contents:
            line_break = '\n'

        lines = contents.split(line_break)
        for line in lines:
            line = line.strip()
            log.debug("STRM Line: {0}", line)
            if line.startswith('#KODIPROP:'):
                match = re.search('#KODIPROP:(?P<item_property>[^=]+?)=(?P<property_value>.+)', line)
                if match:
                    item_property = match.group('item_property')
                    property_value = match.group('property_value')
                    log.debug("STRM property found: {0} value: {1}", item_property, property_value)
                    listitem_props.append((item_property, property_value))
                else:
                    log.debug("STRM #KODIPROP incorrect format")
            elif line.startswith('#'):
                #  unrecognized, treat as comment
                log.debug("STRM unrecognized line identifier, ignored")
            elif line != '':
                playurl = line
                log.debug("STRM playback url found")

        log.debug("Playback URL: {0} ListItem Properties: {1}", playurl, listitem_props)
        return playurl, listitem_props def get_art(item, server):
    art = {
        'thumb': '',
        'fanart': '',
        'poster': '',
        'banner': '',
        'clearlogo': '',
        'clearart': '',
        'discart': '',
        'landscape': '',
        'tvshow.fanart': '',
        'tvshow.poster': '',
        'tvshow.clearart': '',
        'tvshow.clearlogo': '',
        'tvshow.banner': '',
        'tvshow.landscape': ''
    }

    image_tags = item["ImageTags"]
    if image_tags is not None and image_tags["Primary"] is not None:
        # image_tag = image_tags["Primary"]
        art['thumb'] = downloadUtils.get_artwork(item, "Primary", server=server)

    item_type = item["Type"]

    if item_type == "Genre":
        art['poster'] = downloadUtils.get_artwork(item, "Primary", server=server)
    elif item_type == "Episode":
        art['tvshow.poster'] = downloadUtils.get_artwork(item, "Primary", parent=True, server=server)
        # art['poster'] = downloadUtils.getArtwork(item, "Primary", parent=True, server=server)
        art['tvshow.clearart'] = downloadUtils.get_artwork(item, "Art", parent=True, server=server)
        art['clearart'] = downloadUtils.get_artwork(item, "Art", parent=True, server=server)
        art['tvshow.clearlogo'] = downloadUtils.get_artwork(item, "Logo", parent=True, server=server)
        art['clearlogo'] = downloadUtils.get_artwork(item, "Logo", parent=True, server=server)
        art['tvshow.banner'] = downloadUtils.get_artwork(item, "Banner", parent=True, server=server)
        art['banner'] = downloadUtils.get_artwork(item, "Banner", parent=True, server=server)
        art['tvshow.landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=True, server=server)
        art['landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=True, server=server)
        art['tvshow.fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=True, server=server)
        art['fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=True, server=server)
    elif item_type == "Season":
        art['tvshow.poster'] = downloadUtils.get_artwork(item, "Primary", parent=True, server=server)
        art['season.poster'] = downloadUtils.get_artwork(item, "Primary", parent=False, server=server)
        art['poster'] = downloadUtils.get_artwork(item, "Primary", parent=False, server=server)
        art['tvshow.clearart'] = downloadUtils.get_artwork(item, "Art", parent=True, server=server)
        art['clearart'] = downloadUtils.get_artwork(item, "Art", parent=True, server=server)
        art['tvshow.clearlogo'] = downloadUtils.get_artwork(item, "Logo", parent=True, server=server)
        art['clearlogo'] = downloadUtils.get_artwork(item, "Logo", parent=True, server=server)
        art['tvshow.banner'] = downloadUtils.get_artwork(item, "Banner", parent=True, server=server)
        art['season.banner'] = downloadUtils.get_artwork(item, "Banner", parent=False, server=server)
        art['banner'] = downloadUtils.get_artwork(item, "Banner", parent=False, server=server)
        art['tvshow.landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=True, server=server)
        art['season.landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=False, server=server)
        art['landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=False, server=server)
        art['tvshow.fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=True, server=server)
        art['fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=True, server=server)
    elif item_type == "Series":
        art['tvshow.poster'] = downloadUtils.get_artwork(item, "Primary", parent=False, server=server)
        art['poster'] = downloadUtils.get_artwork(item, "Primary", parent=False, server=server)
        art['tvshow.clearart'] = downloadUtils.get_artwork(item, "Art", parent=False, server=server)
        art['clearart'] = downloadUtils.get_artwork(item, "Art", parent=False, server=server)
        art['tvshow.clearlogo'] = downloadUtils.get_artwork(item, "Logo", parent=False, server=server)
        art['clearlogo'] = downloadUtils.get_artwork(item, "Logo", parent=False, server=server)
        art['tvshow.banner'] = downloadUtils.get_artwork(item, "Banner", parent=False, server=server)
        art['banner'] = downloadUtils.get_artwork(item, "Banner", parent=False, server=server)
        art['tvshow.landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=False, server=server)
        art['landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=False, server=server)
        art['tvshow.fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=False, server=server)
        art['fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=False, server=server)
    elif item_type == "Movie" or item_type == "BoxSet":
        art['poster'] = downloadUtils.get_artwork(item, "Primary", server=server)
        art['landscape'] = downloadUtils.get_artwork(item, "Thumb", server=server)
        art['banner'] = downloadUtils.get_artwork(item, "Banner", server=server)
        art['clearlogo'] = downloadUtils.get_artwork(item, "Logo", server=server)
        art['clearart'] = downloadUtils.get_artwork(item, "Art", server=server)
        art['discart'] = downloadUtils.get_artwork(item, "Disc", server=server)

    art['fanart'] = downloadUtils.get_artwork(item, "Backdrop", server=server)
    if not art['fanart']:
        art['fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=True, server=server)

    return art def send_event_notification(method, data):
    message_data = json.dumps(data)
    source_id = "embycon"
    base64_data = base64.b64encode(message_data)
    escaped_data = '\\"[\\"{0}\\"]\\"'.format(base64_data)
    command = 'XBMC.NotifyAll({0}.SIGNAL,{1},{2})'.format(source_id, method, escaped_data)
    log.debug("Sending notification event data: {0}", command)
    xbmc.executebuiltin(command) def convert_size(size_bytes):
    if size_bytes == 0:
        return "0B"
    size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
    i = int(math.floor(math.log(size_bytes, 1024)))
    p = math.pow(1024, i)
    s = round(size_bytes / p, 2)
    return "%s %s" % (s, size_name[i]) class HomeWindow:
    """
        xbmcgui.Window(10000) with add-on id prefixed to keys
    """

    def __init__(self):
        self.id_string = 'plugin.video.embycon-%s'
        self.window = xbmcgui.Window(10000)

    def get_property(self, key):
        key = self.id_string % key
        value = self.window.getProperty(key)
        # log.debug('HomeWindow: getProperty |{0}| -> |{1}|', key, value)
        return value

    def set_property(self, key, value):
        key = self.id_string % key
        # log.debug('HomeWindow: setProperty |{0}| -> |{1}|', key, value)
        self.window.setProperty(key, value)

    def clear_property(self, key):
        key = self.id_string % key
        # log.debug('HomeWindow: clearProperty |{0}|', key)
        self.window.clearProperty(key) def string_load(string_id):
    try:
        return addon.getLocalizedString(string_id).encode('utf-8', 'ignore')
    except Exception as e:
        log.error('Failed String Load: {0} ({1})', string_id, e)
        return str(string_id) class DataManager:

    addon_dir = xbmc.translatePath(xbmcaddon.Addon().getAddonInfo('profile'))

    def __init__(self, *args):
        # log.debug("DataManager __init__")
        pass

    @staticmethod
    def load_json_data(json_data):
        return json.loads(json_data, object_hook=lambda d: defaultdict(lambda: None, d))

    @timer
    def get_content(self, url):
        json_data = DownloadUtils().download_url(url)
        result = self.load_json_data(json_data)
        return result

    @timer
    def get_items(self, url, gui_options, use_cache=False):

        home_window = HomeWindow()
        log.debug("last_content_url : use_cache={0} url={1}", use_cache, url)
        home_window.set_property("last_content_url", url)

        download_utils = DownloadUtils()
        user_id = download_utils.get_user_id()
        server = download_utils.get_server()

        m = hashlib.md5()
        m.update(user_id + "|" + str(server) + "|" + url)
        url_hash = m.hexdigest()
        cache_file = os.path.join(self.addon_dir, "cache_" + url_hash + ".pickle")

        # changed_url = url + "&MinDateLastSavedForUser=" + urllib.unquote("2019-09-16T13:45:30")
        # results = self.GetContent(changed_url)
        # log.debug("DataManager Changes Since Date : {0}", results)

        item_list = None
        total_records = 0
        baseline_name = None
        cache_thread = CacheManagerThread()
        cache_thread.gui_options = gui_options

        home_window.set_property(cache_file, "true")

        clear_cache = home_window.get_property("skip_cache_for_" + url)
        if clear_cache and os.path.isfile(cache_file):
            log.debug("Clearing cache data and loading new data")
            home_window.clear_property("skip_cache_for_" + url)
            with FileLock(cache_file, timeout=5):
                xbmcvfs.delete(cache_file)

        # try to load the list item data from the cache
        if os.path.isfile(cache_file) and use_cache:
            log.debug("Loading url data from cached pickle data")

            with FileLock(cache_file, timeout=5):
                with open(cache_file, 'rb') as handle:
                    try:
                        cache_item = cPickle.load(handle)
                        cache_thread.cached_item = cache_item
                        item_list = cache_item.item_list
                        total_records = cache_item.total_records
                    except Exception as err:
                        log.error("Pickle Data Load Failed : {0}", err)
                        item_list = None

        # we need to load the list item data form the server
        if item_list is None or len(item_list) == 0:
            log.debug("Loading url data from server")

            results = self.get_content(url)

            if results is None:
                results = []

            if isinstance(results, dict):
                total_records = results.get("TotalRecordCount", 0)

            if isinstance(results, dict) and results.get("Items") is not None:
                baseline_name = results.get("BaselineItemName")
                results = results.get("Items", [])
            elif isinstance(results, list) and len(results) > 0 and results[0].get("Items") is not None:
                baseline_name = results[0].get("BaselineItemName")
                results = results[0].get("Items")

            item_list = []
            for item in results:
                item_data = extract_item_info(item, gui_options)
                item_data.baseline_itemname = baseline_name
                item_list.append(item_data)

            cache_item = CacheItem()
            cache_item.item_list = item_list
            cache_item.file_path = cache_file
            cache_item.items_url = url
            cache_item.user_id = user_id
            cache_item.last_action = "fresh_data"
            cache_item.date_saved = time.time()
            cache_item.date_last_used = time.time()
            cache_item.total_records = total_records

            cache_thread.cached_item = cache_item
            # copy.deepcopy(item_list)

        if not use_cache:
            cache_thread = None

        return cache_file, item_list, total_records, cache_thread def clear_old_cache_data():
    log.debug("clear_old_cache_data() : called")

    addon_dir = xbmc.translatePath(xbmcaddon.Addon().getAddonInfo('profile'))
    dirs, files = xbmcvfs.listdir(addon_dir)

    del_count = 0
    for filename in files:
        if filename.startswith("cache_") and filename.endswith(".pickle"):
            log.debug("clear_old_cache_data() : Checking CacheFile : {0}", filename)

            cache_item = None
            for x in range(0, 5):
                try:
                    data_file = os.path.join(addon_dir, filename)
                    with FileLock(data_file, timeout=5):
                        with open(data_file, 'rb') as handle:
                            cache_item = cPickle.load(handle)
                    break
                except Exception as error:
                    log.debug("clear_old_cache_data() : Pickle load error : {0}", error)
                    cache_item = None
                    xbmc.sleep(1000)

            if cache_item is not None:
                item_last_used = -1
                if cache_item.date_last_used is not None:
                    item_last_used = time.time() - cache_item.date_last_used

                log.debug("clear_old_cache_data() : Cache item last used : {0} sec ago", item_last_used)
                if item_last_used == -1 or item_last_used > (3600 * 24 * 7):
                    log.debug("clear_old_cache_data() : Deleting cache item age : {0}", item_last_used)
                    data_file = os.path.join(addon_dir, filename)
                    with FileLock(data_file, timeout=5):
                        xbmcvfs.delete(data_file)
                    del_count += 1
            else:
                log.debug("clear_old_cache_data() : Deleting unloadable cache item")
                data_file = os.path.join(addon_dir, filename)
                with FileLock(data_file, timeout=5):
                    xbmcvfs.delete(data_file)

    log.debug("clear_old_cache_data() : Cache items deleted : {0}", del_count) def extract_item_info(item, gui_options):

    item_details = ItemDetails()

    item_details.id = item["Id"]
    item_details.etag = item["Etag"]
    item_details.is_folder = item["IsFolder"]
    item_details.item_type = item["Type"]
    item_details.location_type = item["LocationType"]
    item_details.name = item["Name"]
    item_details.sort_name = item["SortName"]
    item_details.original_title = item_details.name

    if item_details.item_type == "Episode":
        item_details.episode_number = item["IndexNumber"]
        item_details.season_number = item["ParentIndexNumber"]
        item_details.series_id = item["SeriesId"]

        if item_details.season_number != 0:
            item_details.season_sort_number = item_details.season_number
            item_details.episode_sort_number = item_details.episode_number
        else:
            special_after_season = item["AirsAfterSeasonNumber"]
            special_before_season = item["AirsBeforeSeasonNumber"]
            special_before_episode = item["AirsBeforeEpisodeNumber"]

            if special_after_season:
                item_details.season_sort_number = special_after_season + 1
            elif special_before_season:
                item_details.season_sort_number = special_before_season - 1

            if special_before_episode:
                item_details.episode_sort_number = special_before_episode - 1

    elif item_details.item_type == "Season":
        item_details.season_number = item["IndexNumber"]
        item_details.series_id = item["SeriesId"]

    elif item_details.item_type == "Series":
        item_details.status = item["Status"]

    elif item_details.item_type == "Audio":
        item_details.track_number = item["IndexNumber"]
        item_details.album_name = item["Album"]
        artists = item["Artists"]
        if artists is not None and len(artists) > 0:
            item_details.song_artist = artists[0]  # get first artist

    elif item_details.item_type == "MusicAlbum":
        item_details.album_artist = item["AlbumArtist"]
        item_details.album_name = item_details.name

    if item_details.season_number is None:
        item_details.season_number = 0
    if item_details.episode_number is None:
        item_details.episode_number = 0

    if item["Taglines"] is not None and len(item["Taglines"]) > 0:
        item_details.tagline = item["Taglines"][0]

    item_details.tags = []
    if item["TagItems"] is not None and len(item["TagItems"]) > 0:
        for tag_info in item["TagItems"]:
            item_details.tags.append(tag_info["Name"])

    # set the item name
    # override with name format string from request
    name_format = gui_options["name_format"]
    name_format_type = gui_options["name_format_type"]

    if name_format is not None and item_details.item_type == name_format_type:
        name_info = {}
        name_info["ItemName"] = item["Name"]
        season_name = item["SeriesName"]
        if season_name:
            name_info["SeriesName"] = season_name
        else:
            name_info["SeriesName"] = ""
        name_info["SeasonIndex"] = u"%02d" % item_details.season_number
        name_info["EpisodeIndex"] = u"%02d" % item_details.episode_number
        log.debug("FormatName: {0} | {1}", name_format, name_info)
        item_details.name = unicode(name_format).format(**name_info).strip()

    year = item["ProductionYear"]
    prem_date = item["PremiereDate"]

    if year is not None:
        item_details.year = year
    elif item_details.year is None and prem_date is not None:
        item_details.year = int(prem_date[:4])

    if prem_date is not None:
        tokens = prem_date.split("T")
        item_details.premiere_date = tokens[0]

    create_date = item["DateCreated"]
    if create_date is not None:
        item_details.date_added = create_date.split('.')[0].replace('T', " ")

    # add the premiered date for Upcoming TV
    if item_details.location_type == "Virtual":
        airtime = item["AirTime"]
        item_details.name = item_details.name + ' - ' + item_details.premiere_date + ' - ' + str(airtime)

    if item_details.item_type == "Program":
        item_details.program_channel_name = item["ChannelName"]
        item_details.program_start_date = item["StartDate"]
        item_details.program_end_date = item["EndDate"]

    # Process MediaStreams
    media_streams = item["MediaStreams"]
    if media_streams is not None:
        media_info_list = []
        for mediaStream in media_streams:
            stream_type = mediaStream["Type"]
            if stream_type == "Video":
                media_info = {}
                media_info["type"] = "video"
                media_info["codec"] = mediaStream["Codec"]
                media_info["height"] = mediaStream["Height"]
                media_info["width"] = mediaStream["Width"]
                aspect_ratio = mediaStream["AspectRatio"]
                media_info["apect"] = aspect_ratio
                if aspect_ratio is not None and len(aspect_ratio) >= 3:
                    try:
                        aspect_width, aspect_height = aspect_ratio.split(':')
                        media_info["apect_ratio"] = float(aspect_width) / float(aspect_height)
                    except:
                        media_info["apect_ratio"] = 1.85
                else:
                    media_info["apect_ratio"] = 1.85
                media_info_list.append(media_info)
            if stream_type == "Audio":
                media_info = {}
                media_info["type"] = "audio"
                media_info["codec"] = mediaStream["Codec"]
                media_info["channels"] = mediaStream["Channels"]
                media_info["language"] = mediaStream["Language"]
                media_info_list.append(media_info)
            if stream_type == "Subtitle":
                item_details.subtitle_available = True
                media_info = {}
                media_info["type"] = "sub"
                media_info["language"] = mediaStream["Language"]
                media_info_list.append(media_info)

        item_details.media_streams = media_info_list

    # Process People
    people = item["People"]
    if people is not None:
        cast = []
        for person in people:
            person_type = person["Type"]
            if person_type == "Director" and person["Name"] is not None:
                item_details.director = item_details.director + person["Name"] + ' '
            elif person_type == "Writing" and person["Name"] is not None:
                item_details.writer = person["Name"]
            elif person_type == "Actor" and person["Name"] is not None:
                # log.debug("Person: {0}", person)
                person_name = person["Name"]
                person_role = person["Role"]
                person_id = person["Id"]
                person_tag = person["PrimaryImageTag"]
                if person_tag is not None:
                    person_thumbnail = download_utils.image_url(person_id,
                                                                "Primary", 0, 400, 400,
                                                                person_tag,
                                                                server=gui_options["server"])
                else:
                    person_thumbnail = ""
                person = {"name": person_name, "role": person_role, "thumbnail": person_thumbnail}
                cast.append(person)
        item_details.cast = cast

    # Process Studios
    studios = item["Studios"]
    if studios is not None:
        for studio in studios:
            if item_details.studio is None:  # Just take the first one
                studio_name = studio["Name"]
                item_details.studio = studio_name
                break

    # production location
    prod_location = item["ProductionLocations"]
    # log.debug("ProductionLocations : {0}", prod_location)
    if prod_location and len(prod_location) > 0:
        item_details.production_location = prod_location[0]

    # Process Genres
    genres = item["Genres"]
    if genres is not None and len(genres) > 0:
        item_details.genres = genres

    # Process UserData
    user_data = item["UserData"]
    if user_data is None:
        user_data = defaultdict(lambda: None, {})

    if user_data["Played"] is True:
        item_details.overlay = "6"
        item_details.play_count = 1
    else:
        item_details.overlay = "7"
        item_details.play_count = 0

    if user_data["IsFavorite"] is True:
        item_details.overlay = "5"
        item_details.favorite = "true"
    else:
        item_details.favorite = "false"

    reasonable_ticks = user_data["PlaybackPositionTicks"]
    if reasonable_ticks is not None:
        reasonable_ticks = int(reasonable_ticks) / 1000
        item_details.resume_time = int(reasonable_ticks / 10000)

    item_details.series_name = item["SeriesName"]
    item_details.plot = item["Overview"]

    runtime = item["RunTimeTicks"]
    if item_details.is_folder is False and runtime is not None:
        item_details.duration = long(runtime) / 10000000

    child_count = item["ChildCount"]
    if child_count is not None:
        item_details.total_seasons = child_count

    recursive_item_count = item["RecursiveItemCount"]
    if recursive_item_count is not None:
        item_details.total_episodes = recursive_item_count

    unplayed_item_count = user_data["UnplayedItemCount"]
    if unplayed_item_count is not None:
        item_details.unwatched_episodes = unplayed_item_count
        item_details.watched_episodes = item_details.total_episodes - unplayed_item_count

    item_details.number_episodes = item_details.total_episodes

    item_details.art = get_art(item, gui_options["server"])
    item_details.rating = item["OfficialRating"]
    item_details.mpaa = item["OfficialRating"]

    item_details.community_rating = item["CommunityRating"]
    if item_details.community_rating is None:
        item_details.community_rating = 0.0

    item_details.critic_rating = item["CriticRating"]
    if item_details.critic_rating is None:
        item_details.critic_rating = 0.0

    item_details.location_type = item["LocationType"]
    item_details.recursive_item_count = item["RecursiveItemCount"]
    item_details.recursive_unplayed_items_count = user_data["UnplayedItemCount"]

    item_details.mode = "GET_CONTENT"

    return item_details def add_gui_item(url, item_details, display_options, folder=True, default_sort=False):

    # log.debug("item_details: {0}", item_details.__dict__)

    if not item_details.name:
        return None

    if item_details.mode:
        mode = "&mode=%s" % item_details.mode
    else:
        mode = "&mode=0"

    # Create the URL to pass to the item
    if folder:
        u = sys.argv[0] + "?url=" + urllib.quote(url) + mode + "&media_type=" + item_details.item_type
        if item_details.name_format:
            u += '&name_format=' + urllib.quote(item_details.name_format)
        if default_sort:
            u += '&sort=none'
    else:
        u = sys.argv[0] + "?item_id=" + url + "&mode=PLAY"

    # Create the ListItem that will be displayed
    thumb_path = item_details.art["thumb"]

    list_item_name = item_details.name
    item_type = item_details.item_type.lower()
    is_video = item_type not in ['musicalbum', 'audio', 'music']

    # calculate percentage
    capped_percentage = 0
    if item_details.resume_time > 0:
        duration = float(item_details.duration)
        if duration > 0:
            resume = float(item_details.resume_time)
            percentage = int((resume / duration) * 100.0)
            capped_percentage = percentage

    total_items = item_details.total_episodes
    if total_items != 0:
        watched = float(item_details.watched_episodes)
        percentage = int((watched / float(total_items)) * 100.0)
        capped_percentage = percentage

    counts_added = False
    add_counts = display_options["addCounts"]
    if add_counts and item_details.unwatched_episodes != 0:
        counts_added = True
        list_item_name = list_item_name + (" (%s)" % item_details.unwatched_episodes)

    add_resume_percent = display_options["addResumePercent"]
    if (not counts_added
            and add_resume_percent
            and capped_percentage not in [0, 100]):
        list_item_name = list_item_name + (" (%s%%)" % capped_percentage)

    subtitle_available = display_options["addSubtitleAvailable"]
    if subtitle_available and item_details.subtitle_available:
        list_item_name += " (cc)"

    if item_details.item_type == "Program":
        start_time = datetime_from_string(item_details.program_start_date)
        end_time = datetime_from_string(item_details.program_end_date)

        duration = (end_time - start_time).total_seconds()
        time_done = (datetime.now() - start_time).total_seconds()
        percentage_done = (float(time_done) / float(duration)) * 100.0
        capped_percentage = int(percentage_done)

        start_time_string = start_time.strftime("%H:%M")
        end_time_string = end_time.strftime("%H:%M")

        item_details.duration = int(duration)
        item_details.resume_time = int(time_done)

        list_item_name = (item_details.program_channel_name +
                          " - " + list_item_name +
                          " - " + start_time_string + " to " + end_time_string +
                          " (" + str(int(percentage_done)) + "%)")

        time_info = "Start : " + start_time_string + "\n"
        time_info += "End : " + end_time_string + "\n"
        time_info += "Complete : " + str(int(percentage_done)) + "%\n"
        if item_details.plot:
            item_details.plot = time_info + item_details.plot
        else:
            item_details.plot = time_info

    if kodi_version > 17:
        list_item = xbmcgui.ListItem(list_item_name, offscreen=True)
    else:
        list_item = xbmcgui.ListItem(list_item_name, iconImage=thumb_path, thumbnailImage=thumb_path)

    # log.debug("Setting thumbnail as: {0}", thumbPath)

    item_properties = {}

    # calculate percentage
    if capped_percentage != 0:
        item_properties["complete_percentage"] = str(capped_percentage)

    item_properties["IsPlayable"] = 'false'

    if not folder and is_video:
        item_properties["TotalTime"] = str(item_details.duration)
        item_properties["ResumeTime"] = str(item_details.resume_time)

    list_item.setArt(item_details.art)

    item_properties["fanart_image"] = item_details.art['fanart']  # back compat
    item_properties["discart"] = item_details.art['discart']  # not avail to setArt
    item_properties["tvshow.poster"] = item_details.art['tvshow.poster']  # not avail to setArt

    if item_details.series_id:
        item_properties["series_id"] = item_details.series_id

    # new way
    info_labels = {}

    # add cast
    if item_details.cast is not None:
        if kodi_version >= 17:
            list_item.setCast(item_details.cast)
        else:
            info_labels['cast'] = info_labels['castandrole'] = [(cast_member['name'], cast_member['role']) for cast_member in item_details.cast]

    info_labels["title"] = list_item_name
    if item_details.sort_name:
        info_labels["sorttitle"] = item_details.sort_name
    else:
        info_labels["sorttitle"] = list_item_name

    info_labels["duration"] = item_details.duration
    info_labels["playcount"] = item_details.play_count
    if item_details.favorite == 'true':
        info_labels["top250"] = "1"

    info_labels["rating"] = item_details.rating
    info_labels["year"] = item_details.year

    if item_details.genres is not None and len(item_details.genres) > 0:
        genres_list = []
        for genre in item_details.genres:
            genres_list.append(urllib.quote(genre.encode('utf8')))
        item_properties["genres"] = urllib.quote("|".join(genres_list))

        info_labels["genre"] = " / ".join(item_details.genres)

    mediatype = 'video'

    if item_type == 'movie':
        mediatype = 'movie'
    elif item_type == 'boxset':
        mediatype = 'set'
    elif item_type == 'series':
        mediatype = 'tvshow'
    elif item_type == 'season':
        mediatype = 'season'
    elif item_type == 'episode':
        mediatype = 'episode'
    elif item_type == 'musicalbum':
        mediatype = 'album'
    elif item_type == 'musicartist':
        mediatype = 'artist'
    elif item_type == 'audio' or item_type == 'music':
        mediatype = 'song'

    info_labels["mediatype"] = mediatype

    if item_type == 'episode':
        info_labels["episode"] = item_details.episode_number
        info_labels["season"] = item_details.season_number
        info_labels["sortseason"] = item_details.season_sort_number
        info_labels["sortepisode"] = item_details.episode_sort_number
        info_labels["tvshowtitle"] = item_details.series_name
        if item_details.season_number == 0:
            item_properties["IsSpecial"] = "true"

    elif item_type == 'season':
        info_labels["season"] = item_details.season_number
        info_labels["episode"] = item_details.total_episodes
        info_labels["tvshowtitle"] = item_details.series_name
        if item_details.season_number == 0:
            item_properties["IsSpecial"] = "true"

    elif item_type == "series":
        info_labels["episode"] = item_details.total_episodes
        info_labels["season"] = item_details.total_seasons
        info_labels["status"] = item_details.status
        info_labels["tvshowtitle"] = item_details.name

    if is_video:

        info_labels["Overlay"] = item_details.overlay
        info_labels["tagline"] = item_details.tagline
        info_labels["studio"] = item_details.studio
        info_labels["premiered"] = item_details.premiere_date
        info_labels["plot"] = item_details.plot
        info_labels["director"] = item_details.director
        info_labels["writer"] = item_details.writer
        info_labels["dateadded"] = item_details.date_added
        info_labels["country"] = item_details.production_location
        info_labels["mpaa"] = item_details.mpaa
        info_labels["tag"] = item_details.tags

        if display_options["addUserRatings"]:
            info_labels["userrating"] = item_details.critic_rating

        if item_type in ('movie', 'series'):
            info_labels["trailer"] = "plugin://plugin.video.embycon?mode=playTrailer&id=" + item_details.id

        list_item.setInfo('video', info_labels)
        # log.debug("info_labels: {0}", info_labels)

        if item_details.media_streams is not None:
            for stream in item_details.media_streams:
                if stream["type"] == "video":
                    list_item.addStreamInfo('video',
                                            {'duration': item_details.duration,
                                             'aspect': stream["apect_ratio"],
                                             'codec': stream["codec"],
                                             'width': stream["width"],
                                             'height': stream["height"]})
                elif stream["type"] == "audio":
                    list_item.addStreamInfo('audio',
                                            {'codec': stream["codec"],
                                             'channels': stream["channels"],
                                             'language': stream["language"]})
                elif stream["type"] == "sub":
                    list_item.addStreamInfo('subtitle',
                                            {'language': stream["language"]})

        item_properties["TotalSeasons"] = str(item_details.total_seasons)
        item_properties["TotalEpisodes"] = str(item_details.total_episodes)
        item_properties["WatchedEpisodes"] = str(item_details.watched_episodes)
        item_properties["UnWatchedEpisodes"] = str(item_details.unwatched_episodes)
        item_properties["NumEpisodes"] = str(item_details.number_episodes)

        list_item.setRating("imdb", item_details.community_rating, 0, True)
        # list_item.setRating("rt", item_details.critic_rating, 0, False)
        item_properties["TotalTime"] = str(item_details.duration)

    else:
        info_labels["tracknumber"] = item_details.track_number
        if item_details.album_artist:
            info_labels["artist"] = item_details.album_artist
        elif item_details.song_artist:
            info_labels["artist"] = item_details.song_artist
        info_labels["album"] = item_details.album_name

        # log.debug("info_labels: {0}", info_labels)
        list_item.setInfo('music', info_labels)

    list_item.setContentLookup(False)
    item_properties["ItemType"] = item_details.item_type
    item_properties["id"] = item_details.id

    if item_details.baseline_itemname is not None:
        item_properties["suggested_from_watching"] = item_details.baseline_itemname

    # log.debug("item_properties: {0}", item_properties)
    if kodi_version > 17:
        list_item.setProperties(item_properties)
    else:
        for key, value in item_properties.iteritems():
            list_item.setProperty(key, value)

    return u, list_item, folder class ClientInformation:

    @staticmethod
    def get_device_id():

        window = HomeWindow()
        client_id = window.get_property("client_id")

        if client_id:
            return client_id

        emby_guid_path = xbmc.translatePath("special://temp/embycon_guid").decode('utf-8')
        log.debug("emby_guid_path: {0}", emby_guid_path)
        guid = xbmcvfs.File(emby_guid_path)
        client_id = guid.read()
        guid.close()

        if not client_id:
            client_id = str("%012X" % uuid4())
            log.debug("Generating a new guid: {0}", client_id)
            guid = xbmcvfs.File(emby_guid_path, 'w')
            guid.write(client_id)
            guid.close()
            log.debug("emby_client_id (NEW): {0}", client_id)
        else:
            log.debug("emby_client_id: {0}", client_id)

        window.set_property("client_id", client_id)
        return client_id

    @staticmethod
    def get_version():
        addon = xbmcaddon.Addon()
        version = addon.getAddonInfo("version")
        return version

    @staticmethod
    def get_client():
        return 'Kodi EmbyCon' def delete(item_id):

    json_data = downloadUtils.download_url("{server}/emby/Users/{userid}/Items/" + item_id + "?format=json")
    item = json.loads(json_data)

    item_id = item.get("Id")
    item_name = item.get("Name", "")
    series_name = item.get("SeriesName", "")
    ep_number = item.get("IndexNumber", -1)

    final_name = ""

    if series_name:
        final_name += series_name + " - "

    if ep_number != -1:
        final_name += "Episode %02d - " % (ep_number,)

    final_name += item_name

    if not item.get("CanDelete", False):
        xbmcgui.Dialog().ok(string_load(30135), string_load(30417), final_name)
        return

    return_value = xbmcgui.Dialog().yesno(string_load(30091), final_name, string_load(30092))
    if return_value:
        log.debug('Deleting Item: {0}', item_id)
        url = '{server}/emby/Items/' + item_id
        progress = xbmcgui.DialogProgress()
        progress.create(string_load(30052), string_load(30053))
        downloadUtils.download_url(url, method="DELETE")
        progress.close()
        check_for_new_content()
        home_window = HomeWindow()
        last_url = home_window.get_property("last_content_url")
        if last_url:
            home_window.set_property("skip_cache_for_" + last_url, "true")

        xbmc.executebuiltin("Container.Refresh") class CacheArtwork(threading.Thread):

    stop_all_activity = False

    def __init__(self):
        log.debug("CacheArtwork init")
        self.stop_all_activity = False
        super(CacheArtwork, self).__init__()

    def stop_activity(self):
        self.stop_all_activity = True

    def run(self):
        log.debug("CacheArtwork background thread started")
        last_update = 0
        home_window = HomeWindow()
        settings = xbmcaddon.Addon()
        latest_content_hash = "never"
        check_interval = int(settings.getSetting('cacheImagesOnScreenSaver_interval'))
        check_interval = check_interval * 60
        monitor = xbmc.Monitor()
        monitor.waitForAbort(5)

        while not self.stop_all_activity and not monitor.abortRequested() and xbmc.getCondVisibility("System.ScreenSaverActive"):
            content_hash = home_window.get_property("embycon_widget_reload")
            if (check_interval != 0 and (time.time() - last_update) > check_interval) or (latest_content_hash != content_hash):
                log.debug("CacheArtwork background thread - triggered")
                if monitor.waitForAbort(10):
                    break
                if self.stop_all_activity or monitor.abortRequested():
                    break
                self.cache_artwork_background()
                last_update = time.time()
                latest_content_hash = content_hash

            monitor.waitForAbort(5)

        log.debug("CacheArtwork background thread exited : stop_all_activity : {0}", self.stop_all_activity)

    @staticmethod
    def delete_cached_images(item_id):
        log.debug("cache_delete_for_links")

        progress = xbmcgui.DialogProgress()
        progress.create(string_load(30281))
        progress.update(30, string_load(30347))

        item_image_url_part = "emby/Items/%s/Images/" % item_id
        item_image_url_part = item_image_url_part.replace("/", "%2f")
        log.debug("texture ids: {0}", item_image_url_part)

        # is the web server enabled
        web_query = {"setting": "services.webserver"}
        result = JsonRpc('Settings.GetSettingValue').execute(web_query)
        xbmc_webserver_enabled = result['result']['value']
        if not xbmc_webserver_enabled:
            xbmcgui.Dialog().ok(string_load(30294), string_load(30295))
            return

        params = {"properties": ["url"]}
        json_result = JsonRpc('Textures.GetTextures').execute(params)
        textures = json_result.get("result", {}).get("textures", [])
        log.debug("texture ids: {0}", textures)

        progress.update(70, string_load(30346))

        delete_count = 0
        for texture in textures:
            texture_id = texture["textureid"]
            texture_url = texture["url"]
            if item_image_url_part in texture_url:
                delete_count += 1
                log.debug("removing texture id: {0}", texture_id)
                params = {"textureid": int(texture_id)}
                JsonRpc('Textures.RemoveTexture').execute(params)

        del textures

        progress.update(100, string_load(30125))
        progress.close()

        xbmcgui.Dialog().ok(string_load(30281), string_load(30344) % delete_count)

    def cache_artwork_interactive(self):
        log.debug("cache_artwork_interactive")

        xbmcplugin.endOfDirectory(int(sys.argv[1]), cacheToDisc=False)

        # is the web server enabled
        web_query = {"setting": "services.webserver"}
        result = JsonRpc('Settings.GetSettingValue').execute(web_query)
        xbmc_webserver_enabled = result['result']['value']
        if not xbmc_webserver_enabled:
            xbmcgui.Dialog().ok(string_load(30294), string_load(30295), string_load(30355))
            xbmc.executebuiltin('ActivateWindow(servicesettings)')
            return

        result_report = []

        # ask questions
        question_delete_unused = xbmcgui.Dialog().yesno(string_load(30296), string_load(30297))
        question_cache_images = xbmcgui.Dialog().yesno(string_load(30299), string_load(30300))

        delete_canceled = False
        # now do work - delete unused
        if question_delete_unused:
            delete_pdialog = xbmcgui.DialogProgress()
            delete_pdialog.create(string_load(30298), "")
            index = 0

            params = {"properties": ["url"]}
            json_result = JsonRpc('Textures.GetTextures').execute(params)
            textures = json_result.get("result", {}).get("textures", [])

            emby_texture_urls = self.get_emby_artwork(delete_pdialog)

            log.debug("kodi textures: {0}", textures)
            log.debug("emby texture urls: {0}", emby_texture_urls)

            if emby_texture_urls is not None:

                unused_texture_ids = set()
                for texture in textures:
                    url = texture.get("url")
                    url = urllib.unquote(url)
                    url = url.replace("image://", "")
                    url = url[0:-1]
                    if url.find("/emby/") > -1 and url not in emby_texture_urls or url.find("localhost:24276") > -1:
                        # log.debug("adding unused texture url: {0}", url)
                        unused_texture_ids.add(texture["textureid"])

                total = len(unused_texture_ids)
                log.debug("unused texture ids: {0}", unused_texture_ids)

                for texture_id in unused_texture_ids:
                    params = {"textureid": int(texture_id)}
                    JsonRpc('Textures.RemoveTexture').execute(params)
                    percentage = int((float(index) / float(total)) * 100)
                    message = "%s of %s" % (index, total)
                    delete_pdialog.update(percentage, message)

                    index += 1
                    if delete_pdialog.iscanceled():
                        delete_canceled = True
                        break

                result_report.append(string_load(30385) + str(len(textures)))
                result_report.append(string_load(30386) + str(len(unused_texture_ids)))
                result_report.append(string_load(30387) + str(index))

            del textures
            del emby_texture_urls
            del unused_texture_ids
            delete_pdialog.close()
            del delete_pdialog

        if delete_canceled:
            xbmc.sleep(2000)

        # now do work - cache images
        if question_cache_images:
            cache_pdialog = xbmcgui.DialogProgress()
            cache_pdialog.create(string_load(30301), "")
            cache_report = self.cache_artwork(cache_pdialog)
            cache_pdialog.close()
            del cache_pdialog
            if cache_report:
                result_report.extend(cache_report)

        if len(result_report) > 0:
            msg = "\r\n".join(result_report)
            xbmcgui.Dialog().textviewer(string_load(30125), msg, usemono=True)

    def cache_artwork_background(self):
        log.debug("cache_artwork_background")
        dp = xbmcgui.DialogProgressBG()
        dp.create(string_load(30301), "")
        result_text = None
        try:
            result_text = self.cache_artwork(dp)
        except Exception as err:
            log.error("Cache Images Failed : {0}", err)
        dp.close()
        del dp
        if result_text is not None:
            log.debug("Cache Images reuslt : {0}", " - ".join(result_text))

    def get_emby_artwork(self, progress):
        log.debug("get_emby_artwork")

        url = ""
        url += "{server}/emby/Users/{userid}/Items"
        url += "?Recursive=true"
        url += "&EnableUserData=False"
        url += "&Fields=BasicSyncInfo"
        url += "&IncludeItemTypes=Movie,Series,Episode,BoxSet"
        url += "&ImageTypeLimit=1"
        url += "&format=json"

        data_manager = DataManager()
        results = data_manager.get_content(url)
        if results is None:
            results = []

        if isinstance(results, dict):
            results = results.get("Items")

        server = downloadUtils.get_server()
        log.debug("Emby Item Count Count: {0}", len(results))

        if self.stop_all_activity:
            return None

        progress.update(0, string_load(30359))

        texture_urls = set()

        # image_types = ["thumb", "poster", "banner", "clearlogo", "tvshow.poster", "tvshow.banner", "tvshow.landscape"]
        for item in results:
            art = get_art(item, server)
            for art_type in art:
                texture_urls.add(art[art_type])

        return texture_urls

    def cache_artwork(self, progress):
        log.debug("cache_artwork")

        # is the web server enabled
        web_query = {"setting": "services.webserver"}
        result = JsonRpc('Settings.GetSettingValue').execute(web_query)
        xbmc_webserver_enabled = result['result']['value']
        if not xbmc_webserver_enabled:
            log.error("Kodi web server not enabled, can not cache images")
            return

        # get the port
        web_port = {"setting": "services.webserverport"}
        result = JsonRpc('Settings.GetSettingValue').execute(web_port)
        xbmc_port = result['result']['value']
        log.debug("xbmc_port: {0}", xbmc_port)

        # get the user
        web_user = {"setting": "services.webserverusername"}
        result = JsonRpc('Settings.GetSettingValue').execute(web_user)
        xbmc_username = result['result']['value']
        log.debug("xbmc_username: {0}", xbmc_username)

        # get the password
        web_pass = {"setting": "services.webserverpassword"}
        result = JsonRpc('Settings.GetSettingValue').execute(web_pass)
        xbmc_password = result['result']['value']

        progress.update(0, string_load(30356))

        params = {"properties": ["url"]}
        json_result = JsonRpc('Textures.GetTextures').execute(params)
        textures = json_result.get("result", {}).get("textures", [])
        log.debug("Textures.GetTextures Count: {0}", len(textures))

        if self.stop_all_activity:
            return

        progress.update(0, string_load(30357))

        texture_urls = set()
        for texture in textures:
            url = texture.get("url")
            url = urllib.unquote(url)
            url = url.replace("image://", "")
            url = url[0:-1]
            texture_urls.add(url)

        del textures
        del json_result

        log.debug("texture_urls Count: {0}", len(texture_urls))

        if self.stop_all_activity:
            return

        progress.update(0, string_load(30358))

        emby_texture_urls = self.get_emby_artwork(progress)
        if emby_texture_urls is None:
            return

        missing_texture_urls = set()
        # image_types = ["thumb", "poster", "banner", "clearlogo", "tvshow.poster", "tvshow.banner", "tvshow.landscape"]
        for image_url in emby_texture_urls:
            if image_url not in texture_urls and not image_url.endswith("&Tag=") and len(image_url) > 0:
                missing_texture_urls.add(image_url)

            if self.stop_all_activity:
                return

        log.debug("texture_urls: {0}", texture_urls)
        log.debug("missing_texture_urls: {0}", missing_texture_urls)
        log.debug("Number of existing textures: {0}", len(texture_urls))
        log.debug("Number of missing textures: {0}", len(missing_texture_urls))

        kodi_http_server = "localhost:" + str(xbmc_port)
        headers = {}
        if xbmc_password:
            auth = "%s:%s" % (xbmc_username, xbmc_password)
            headers = {'Authorization': 'Basic %s' % base64.b64encode(auth)}

        total = len(missing_texture_urls)
        index = 1

        count_done = 0
        for get_url in missing_texture_urls:
            # log.debug("texture_url: {0}", get_url)
            url = double_urlencode(get_url)
            kodi_texture_url = ("/image/image://%s" % url)
            log.debug("kodi_texture_url: {0}", kodi_texture_url)

            percentage = int((float(index) / float(total)) * 100)
            message = "%s of %s" % (index, total)
            progress.update(percentage, message)

            conn = httplib.HTTPConnection(kodi_http_server, timeout=20)
            conn.request(method="GET", url=kodi_texture_url, headers=headers)
            data = conn.getresponse()
            if data.status == 200:
                count_done += 1
            log.debug("Get Image Result: {0}", data.status)

            index += 1
            # if progress.iscanceled():
            # if "iscanceled" in dir(progress) and progress.iscanceled():
            if isinstance(progress, xbmcgui.DialogProgress) and progress.iscanceled():
                break

            if self.stop_all_activity:
                break

        result_report = []
        result_report.append(string_load(30302) + str(len(texture_urls)))
        result_report.append(string_load(30303) + str(len(missing_texture_urls)))
        result_report.append(string_load(30304) + str(count_done))
        return result_report class PictureViewer(xbmcgui.WindowXMLDialog):
    picture_url = None
    action_exitkeys_id = None

    def __init__(self, *args, **kwargs):
        log.debug("PictureViewer: __init__")
        xbmcgui.WindowXML.__init__(self, *args, **kwargs)

    def onInit(self):
        log.debug("PictureViewer: onInit")
        self.action_exitkeys_id = [10, 13]

        picture_control = self.getControl(3010)

        picture_control.setImage(self.picture_url)
        # self.listControl.addItems(self.action_items)
        # self.setFocus(self.listControl)

        # bg_image = self.getControl(3010)
        # bg_image.setHeight(50 * len(self.action_items) + 20)

    def onFocus(self, controlId):
        pass

    def doAction(self, actionID):
        pass

    def onClick(self, controlID):
        pass

    def setPicture(self, url):
        self.picture_url = url def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        started = time.time()
        value = func(*args, **kwargs)
        ended = time.time()
        if enabled:
            data = ""
            if func.__name__ == "download_url" and len(args) > 1:
                data = args[1]
            elif func.__name__ == "main_entry_point" and len(sys.argv) > 2:
                data = sys.argv[2]
            log.info("timing_data|{0}|{1}|{2}|{3}", func.__name__, started, ended, data)
        return value
    return wrapper class PlayNextDialog(xbmcgui.WindowXMLDialog):

    action_exitkeys_id = None
    episode_info = None
    play_called = False
    auto_close_thread = None

    def __init__(self, *args, **kwargs):
        log.debug("PlayNextDialog: __init__")
        xbmcgui.WindowXML.__init__(self, *args, **kwargs)
        self.auto_close_thread = ActionAutoClose(self)
        self.auto_close_thread.set_timeout(30)
        self.auto_close_thread.start()

    def onInit(self):
        log.debug("PlayNextDialog: onInit")
        self.action_exitkeys_id = [10, 13]

        series_name = self.episode_info.get("SeriesName")
        season_name = self.episode_info.get("SeasonName", "n/a")
        next_epp_name = self.episode_info.get("Name", "n/a")

        epp_index = self.episode_info.get("IndexNumber", -1)
        season_index = self.episode_info.get("ParentIndexNumber", -1)
        epp_season_number = "s%02d-e%02d" % (season_index, epp_index)

        rating = self.episode_info.get("CommunityRating")
        if rating:
            next_epp_name += " (%s)" % (rating,)

        overview = self.episode_info.get("Overview")

        overview_label = self.getControl(3018)
        overview_label.setText(overview)

        series_label = self.getControl(3011)
        series_label.setLabel(series_name)

        season_label = self.getControl(3016)
        season_label.setLabel(season_name)

        epp_season_num = self.getControl(3017)
        epp_season_num.setLabel(epp_season_number)

        series_label = self.getControl(3012)
        series_label.setLabel(next_epp_name)

        epp_image = self.getControl(3015)
        epp_image.setImage(self.episode_info["art"]["thumb"])

        runtime_ticks = self.episode_info.get("RunTimeTicks", 0)
        duration = (runtime_ticks / 10000000.0) / 60.0 # convert ticks to minutes
        duration = int(round(duration, 0))
        duration_string = "%s m" % (duration,)
        duration_label = self.getControl(3019)
        duration_label.setLabel(duration_string)

        self.auto_close_thread.set_callback(self)

    def update_progress(self, percentage):
        count_down = self.getControl(3030)
        count_down.setPercent(percentage)

    def onFocus(self, control_id):
        pass

    def doAction(self, action_id):
        pass

    def onMessage(self, message):
        log.debug("PlayNextDialog: onMessage: {0}", message)

    def onAction(self, action):

        if action.getId() == 10:  # ACTION_PREVIOUS_MENU
            self.auto_close_thread.stop()
            self.close()
        elif action.getId() == 92:  # ACTION_NAV_BACK
            self.auto_close_thread.stop()
            self.close()
        else:
            self.auto_close_thread.set_last()
            log.debug("PlayNextDialog: onAction: {0}", action.getId())

    def onClick(self, control_id):
        if control_id == 3013:
            log.debug("PlayNextDialog: Play Next Episode")
            self.play_called
            self.auto_close_thread.stop()
            self.close()
            next_item_id = self.episode_info.get("Id")
            log.debug("Playing Next Episode: {0}", next_item_id)
            play_info = {}
            play_info["item_id"] = next_item_id
            play_info["auto_resume"] = "-1"
            play_info["force_transcode"] = False
            send_event_notification("embycon_play_action", play_info)

        self.auto_close_thread.set_last()

    def set_episode_info(self, info):
        self.episode_info = info

    def get_play_called(self):
        return self.play_called

    def stop_auto_close(self):
        self.auto_close_thread.stop()
import xbmc
import xbmcgui
import xbmcaddon
import json
import os
import base64
from datetime import timedelta
from .simple_logging import SimpleLogging
from .downloadutils import DownloadUtils
from .resume_dialog import ResumeDialog
from .utils import PlayUtils, get_art, send_event_notification, convert_size
from .kodi_utils import HomeWindow
from .translation import string_load
from .datamanager import DataManager, clear_old_cache_data
from .item_functions import extract_item_info, add_gui_item
from .clientinfo import ClientInformation
from .functions import delete
from .cache_images import CacheArtwork
from .picture_viewer import PictureViewer
from .tracking import timer
from .playnext import PlayNextDialog

    item_id = play_data.get("item_id")
    if item_id is None:
        return

    source_id = play_data.get("source_id")

    ticks = int(play_time * 10000000)
    duration = int(total_play_time * 10000000)
    paused = play_data.get("paused", False)
    playback_type = play_data.get("playback_type")
    play_session_id = play_data.get("play_session_id", "")
    live_stream_id = play_data.get("live_stream_id", "")

    playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
    playlist_position = playlist.getposition()
    playlist_size = playlist.size()

    volume, muted = get_volume()

    postdata = {
        'QueueableMediaTypes': "Video",
        'CanSeek': True,
        'ItemId': item_id,
        'MediaSourceId': source_id,
        'IsPaused': paused,
        'IsMuted': muted,
        'PlayMethod': playback_type,
        'PlaySessionId': play_session_id,
        'LiveStreamId': live_stream_id,
        'PlaylistIndex': playlist_position,
        'PlaylistLength': playlist_size,
        'VolumeLevel': volume
    }

    if duration is not None and duration > 0:
        postdata["RunTimeTicks"] = duration
        postdata["PositionTicks"] = ticks

    log.debug("Sending POST progress started: {0}", postdata)
    url = "{server}/emby/Sessions/Playing/Progress"
    download_utils.download_url(url, post_body=postdata, method="POST")


def get_volume():
    json_data = xbmc.executeJSONRPC(
        '{ "jsonrpc": "2.0", "method": "Application.GetProperties", "params": {"properties": ["volume", "muted"]}, "id": 1 }')
    result = json.loads(json_data)
    result = result.get('result', {})
    volume = result.get('volume')
    muted = result.get('muted')

    return volume, muted


def prompt_for_stop_actions(item_id, data):
    log.debug("prompt_for_stop_actions Called : {0}", data)

    settings = xbmcaddon.Addon()
    current_position = data.get("currentPossition", 0)
    duration = data.get("duration", 0)
    # media_source_id = data.get("source_id")
    next_episode = data.get("next_episode")
    item_type = data.get("item_type")
    can_delete = data.get("can_delete", False)

    prompt_next_percentage = int(settings.getSetting('promptPlayNextEpisodePercentage'))
    play_prompt = settings.getSetting('promptPlayNextEpisodePercentage_prompt') == "true"
    prompt_delete_episode_percentage = int(settings.getSetting('promptDeleteEpisodePercentage'))
    prompt_delete_movie_percentage = int(settings.getSetting('promptDeleteMoviePercentage'))

    # everything is off so return
    if (prompt_next_percentage == 100 and
            prompt_delete_episode_percentage == 100 and
            prompt_delete_movie_percentage == 100):
        return

    prompt_to_delete = False

    # if no runtime we cant calculate perceantge so just return
    if duration == 0:
        log.debug("No duration so returing")
        return

    # item percentage complete
    # percenatge_complete = int(((current_position * 10000000) / runtime) * 100)
    percenatge_complete = int((current_position / duration) * 100)
    log.debug("Episode Percentage Complete: {0}", percenatge_complete)

    if (can_delete and
            prompt_delete_episode_percentage < 100 and
            item_type == "Episode" and
            percenatge_complete > prompt_delete_episode_percentage):
        prompt_to_delete = True

    if (can_delete and
            prompt_delete_movie_percentage < 100 and
            item_type == "Movie" and
            percenatge_complete > prompt_delete_movie_percentage):
        prompt_to_delete = True

    if prompt_to_delete:
        log.debug("Prompting for delete")
        delete(item_id)

    # prompt for next episode
    if (next_episode is not None and
            prompt_next_percentage < 100 and
            item_type == "Episode" and
            percenatge_complete > prompt_next_percentage):

        # resp = True
        index = next_episode.get("IndexNumber", -1)
        if play_prompt:
            # series_name = next_episode.get("SeriesName")
            # next_epp_name = "Episode %02d - (%s)" % (index, next_episode.get("Name", "n/a"))

            plugin_path = settings.getAddonInfo('path')
            plugin_path_real = xbmc.translatePath(os.path.join(plugin_path))


            play_next_dialog = PlayNextDialog("PlayNextDialog.xml", plugin_path_real, "default", "720p")