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 def load_user_details(settings):
    save_user_to_settings = settings.getSetting("save_user_to_settings") == "true"
    if save_user_to_settings:
        user_name = settings.getSetting("username")
        user_password = settings.getSetting("password")
    else:
        home_window = HomeWindow()
        user_name = home_window.get_property("username")
        user_password = home_window.get_property("password")

    user_details = {}
    user_details["username"] = user_name
    user_details["password"] = user_password
    return user_details 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) 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' 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_cached_server_data():
    log.debug("clear_cached_server_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.endswith(".lock"):
            lock_file = os.path.join(addon_dir, filename)
            log.debug("Deleteing lock File: {0}", lock_file)
            xbmcvfs.delete(lock_file)
        if filename.startswith("cache_") and filename.endswith(".pickle"):
            cache_file = os.path.join(addon_dir, filename)
            log.debug("Deleteing CacheFile: {0}", cache_file)
            xbmcvfs.delete(cache_file)
            del_count += 1

    msg = string_load(30394) % del_count
    xbmcgui.Dialog().ok(string_load(30393), msg) def check_server(force=False, change_user=False, notify=False):
    log.debug("checkServer Called")

    settings = xbmcaddon.Addon()
    server_url = ""
    something_changed = False
    du = DownloadUtils()

    if force is False:
        # if not forcing use server details from settings
        svr = du.get_server()
        if svr is not None:
            server_url = svr

    # if the server is not set then try to detect it
    if server_url == "":

        # scan for local server
        server_info = get_server_details()

        addon = xbmcaddon.Addon()
        server_icon = addon.getAddonInfo('icon')

        server_list = []
        for server in server_info:
            server_item = xbmcgui.ListItem(server.get("Name", string_load(30063)))
            sub_line = server.get("Address")
            server_item.setLabel2(sub_line)
            server_item.setProperty("address", server.get("Address"))
            art = {"Thumb": server_icon}
            server_item.setArt(art)
            server_list.append(server_item)

        if len(server_list) > 0:
            return_index = xbmcgui.Dialog().select(__addon_name__ + " : " + string_load(30166),
                                                   server_list,
                                                   useDetails=True)
            if return_index != -1:
                server_url = server_info[return_index]["Address"]

        if not server_url:
            return_index = xbmcgui.Dialog().yesno(__addon_name__, string_load(30282), string_load(30370))
            if not return_index:
                xbmc.executebuiltin("ActivateWindow(Home)")
                return

            while True:
                kb = xbmc.Keyboard()
                kb.setHeading(string_load(30372))
                if server_url:
                    kb.setDefault(server_url)
                else:
                    kb.setDefault("http://<server address>:8096")
                kb.doModal()
                if kb.isConfirmed():
                    server_url = kb.getText()
                else:
                    xbmc.executebuiltin("ActivateWindow(Home)")
                    return

                url_bits = urlparse(server_url)
                server_address = url_bits.hostname
                server_port = str(url_bits.port)
                server_protocol = url_bits.scheme
                user_name = url_bits.username
                user_password = url_bits.password

                if user_name and user_password:
                    temp_url = "%s://%s:%s@%s:%s/emby/Users/Public?format=json" % (server_protocol, user_name, user_password, server_address, server_port)
                else:
                    temp_url = "%s://%s:%s/emby/Users/Public?format=json" % (server_protocol, server_address, server_port)

                log.debug("Testing_Url: {0}", temp_url)
                progress = xbmcgui.DialogProgress()
                progress.create(__addon_name__ + " : " + string_load(30376))
                progress.update(0, string_load(30377))
                json_data = du.download_url(temp_url, authenticate=False)
                progress.close()

                result = json.loads(json_data)
                if result is not None:
                    xbmcgui.Dialog().ok(__addon_name__ + " : " + string_load(30167),
                                        "%s://%s:%s/" % (server_protocol, server_address, server_port))
                    break
                else:
                    return_index = xbmcgui.Dialog().yesno(__addon_name__ + " : " + string_load(30135),
                                                          server_url,
                                                          string_load(30371))
                    if not return_index:
                        xbmc.executebuiltin("ActivateWindow(Home)")
                        return

        log.debug("Selected server: {0}", server_url)

        # parse the url
        url_bits = urlparse(server_url)
        server_address = url_bits.hostname
        server_port = str(url_bits.port)
        server_protocol = url_bits.scheme
        user_name = url_bits.username
        user_password = url_bits.password
        log.debug("Detected server info {0} - {1} - {2}", server_protocol, server_address, server_port)

        # save the server info
        settings.setSetting("port", server_port)

        if user_name and user_password:
            server_address = "%s:%s@%s" % (url_bits.username, url_bits.password, server_address)

        settings.setSetting("ipaddress", server_address)

        if server_protocol == "https":
            settings.setSetting("protocol", "1")
        else:
            settings.setSetting("protocol", "0")

        something_changed = True

    # do we need to change the user
    user_details = load_user_details(settings)
    current_username = user_details.get("username", "")
    current_username = unicode(current_username, "utf-8")

    # if asked or we have no current user then show user selection screen
    if something_changed or change_user or len(current_username) == 0:

        # stop playback when switching users
        xbmc.Player().stop()
        du = DownloadUtils()

        # get a list of users
        log.debug("Getting user list")
        json_data = du.download_url(server_url + "/emby/Users/Public?format=json", authenticate=False)

        log.debug("jsonData: {0}", json_data)
        try:
            result = json.loads(json_data)
        except:
            result = None

        if result is None:
            xbmcgui.Dialog().ok(string_load(30135),
                                string_load(30201),
                                string_load(30169) + server_url)

        else:
            selected_id = -1
            users = []
            for user in result:
                config = user.get("Configuration")
                if config is not None:
                    if config.get("IsHidden", False) is False:
                        name = user.get("Name")
                        admin = user.get("Policy", {}).get("IsAdministrator", False)

                        time_ago = ""
                        last_active = user.get("LastActivityDate")
                        if last_active:
                            last_active_date = datetime_from_string(last_active)
                            log.debug("LastActivityDate: {0}", last_active_date)
                            ago = datetime.now() - last_active_date
                            log.debug("LastActivityDate: {0}", ago)
                            days = divmod(ago.seconds, 86400)
                            hours = divmod(days[1], 3600)
                            minutes = divmod(hours[1], 60)
                            log.debug("LastActivityDate: {0} {1} {2}", days[0], hours[0], minutes[0])
                            if days[0]:
                                time_ago += " %sd" % days[0]
                            if hours[0]:
                                time_ago += " %sh" % hours[0]
                            if minutes[0]:
                                time_ago += " %sm" % minutes[0]
                            time_ago = time_ago.strip()
                            if not time_ago:
                                time_ago = "Active: now"
                            else:
                                time_ago = "Active: %s ago" % time_ago
                            log.debug("LastActivityDate: {0}", time_ago)

                        user_item = xbmcgui.ListItem(name)
                        user_image = du.get_user_artwork(user, 'Primary')
                        if not user_image:
                            user_image = "DefaultUser.png"
                        art = {"Thumb": user_image}
                        user_item.setArt(art)
                        user_item.setLabel2("TEST")

                        sub_line = time_ago

                        if user.get("HasPassword", False) is True:
                            sub_line += ", Password"
                            user_item.setProperty("secure", "true")

                            m = hashlib.md5()
                            m.update(name)
                            hashed_username = m.hexdigest()
                            saved_password = settings.getSetting("saved_user_password_" + hashed_username)
                            if saved_password:
                                sub_line += ": Saved"

                        else:
                            user_item.setProperty("secure", "false")

                        if admin:
                            sub_line += ", Admin"
                        else:
                            sub_line += ", User"

                        user_item.setProperty("manual", "false")
                        user_item.setLabel2(sub_line)
                        users.append(user_item)

                        if current_username == name:
                            selected_id = len(users) - 1

            if current_username:
                selection_title = string_load(30180) + " (" + current_username + ")"
            else:
                selection_title = string_load(30180)

            # add manual login
            user_item = xbmcgui.ListItem(string_load(30365))
            art = {"Thumb": "DefaultUser.png"}
            user_item.setArt(art)
            user_item.setLabel2(string_load(30366))
            user_item.setProperty("secure", "true")
            user_item.setProperty("manual", "true")
            users.append(user_item)

            return_value = xbmcgui.Dialog().select(selection_title,
                                                   users,
                                                   preselect=selected_id,
                                                   autoclose=20000,
                                                   useDetails=True)

            if return_value > -1 and return_value != selected_id:

                something_changed = True
                selected_user = users[return_value]
                secured = selected_user.getProperty("secure") == "true"
                manual = selected_user.getProperty("manual") == "true"
                selected_user_name = selected_user.getLabel()

                log.debug("Selected User Name: {0} : {1}", return_value, selected_user_name)

                if manual:
                    kb = xbmc.Keyboard()
                    kb.setHeading(string_load(30005))
                    if current_username:
                        kb.setDefault(current_username)
                    kb.doModal()
                    if kb.isConfirmed():
                        selected_user_name = kb.getText()
                        log.debug("Manual entered username: {0}", selected_user_name)
                    else:
                        return

                if secured:
                    # we need a password, check the settings first
                    m = hashlib.md5()
                    m.update(selected_user_name)
                    hashed_username = m.hexdigest()
                    saved_password = settings.getSetting("saved_user_password_" + hashed_username)
                    allow_password_saving = settings.getSetting("allow_password_saving") == "true"

                    # if not saving passwords but have a saved ask to clear it
                    if not allow_password_saving and saved_password:
                        clear_password = xbmcgui.Dialog().yesno(string_load(30368), string_load(30369))
                        if clear_password:
                            settings.setSetting("saved_user_password_" + hashed_username, "")

                    if saved_password:
                        log.debug("Saving username and password: {0}", selected_user_name)
                        log.debug("Using stored password for user: {0}", hashed_username)
                        save_user_details(settings, selected_user_name, saved_password)

                    else:
                        kb = xbmc.Keyboard()
                        kb.setHeading(string_load(30006))
                        kb.setHiddenInput(True)
                        kb.doModal()
                        if kb.isConfirmed():
                            log.debug("Saving username and password: {0}", selected_user_name)
                            save_user_details(settings, selected_user_name, kb.getText())

                            # should we save the password
                            if allow_password_saving:
                                save_password = xbmcgui.Dialog().yesno(string_load(30363), string_load(30364))
                                if save_password:
                                    log.debug("Saving password for fast user switching: {0}", hashed_username)
                                    settings.setSetting("saved_user_password_" + hashed_username, kb.getText())
                else:
                    log.debug("Saving username with no password: {0}", selected_user_name)
                    save_user_details(settings, selected_user_name, "")

        if something_changed:
            home_window = HomeWindow()
            home_window.clear_property("userid")
            home_window.clear_property("AccessToken")
            home_window.clear_property("userimage")
            home_window.clear_property("embycon_widget_reload")
            du = DownloadUtils()
            du.authenticate()
            du.get_user_id()
            xbmc.executebuiltin("ActivateWindow(Home)")
            if "estuary_embycon" in xbmc.getSkinDir():
                xbmc.executebuiltin("SetFocus(9000, 0, absolute)")
            xbmc.executebuiltin("ReloadSkin()") def check_connection_speed():
    log.debug("check_connection_speed")

    settings = xbmcaddon.Addon()
    verify_cert = settings.getSetting('verify_cert') == 'true'
    http_timeout = int(settings.getSetting("http_timeout"))
    speed_test_data_size = int(settings.getSetting("speed_test_data_size"))
    test_data_size = speed_test_data_size * 1000000

    du = DownloadUtils()
    server = du.get_server()

    url = server + "/emby/playback/bitratetest?size=%s" % test_data_size

    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

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

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

    if local_use_https and verify_cert:
        log.debug("Connection: HTTPS, Cert checked")
        conn = httplib.HTTPSConnection(server, timeout=http_timeout)
    elif local_use_https and not 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 = du.get_auth_header(True)
    head["User-Agent"] = "EmbyCon-" + ClientInformation().get_version()

    conn.request(method="GET", url=url_path, headers=head)

    progress_dialog = xbmcgui.DialogProgress()
    message = 'Testing with {0} MB of data'.format(speed_test_data_size)
    progress_dialog.create("EmbyCon connection speed test", message)
    total_data_read = 0
    total_time = time.time()

    log.debug("Starting Connection Speed Test")
    response = conn.getresponse()
    last_percentage_done = 0
    if int(response.status) == 200:
        data = response.read(10240)
        while len(data) > 0:
            total_data_read += len(data)
            percentage_done = int(float(total_data_read) / float(test_data_size) * 100.0)
            if last_percentage_done != percentage_done:
                progress_dialog.update(percentage_done)
                last_percentage_done = percentage_done
            data = response.read(10240)
    else:
        log.error("HTTP response error: {0} {1}", response.status, response.reason)
        error_message = "HTTP response error: %s\n%s" % (response.status, response.reason)
        xbmcgui.Dialog().ok("Speed Test Error", error_message)
        return -1

    total_data_read_kbits = (total_data_read * 8) / 1000
    total_time = time.time() - total_time
    speed = int(total_data_read_kbits / total_time)
    log.debug("Finished Connection Speed Test, speed: {0} total_data: {1}, total_time: {2}", speed, total_data_read, total_time)

    progress_dialog.close()
    del progress_dialog

    heading = "Speed Test Result : {0:,} Kbs".format(speed)
    message = "Do you want to set this speed as your max stream bitrate for playback?\n"
    message += "{0:,} MB over {1} sec".format(int((total_data_read / 1000000)), total_time)

    response = xbmcgui.Dialog().yesno(heading, message)
    if response:
        settings.setSetting("max_stream_bitrate", str(speed))

    return speed 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 def display_main_menu():
    handle = int(sys.argv[1])
    xbmcplugin.setContent(handle, 'files')

    add_menu_directory_item(string_load(30406),
                            "plugin://plugin.video.embycon/?mode=SHOW_ADDON_MENU&type=library")
    add_menu_directory_item(string_load(30407),
                            "plugin://plugin.video.embycon/?mode=SHOW_ADDON_MENU&type=show_global_types")
    add_menu_directory_item(string_load(30408),
                            "plugin://plugin.video.embycon/?mode=SHOW_ADDON_MENU&type=show_custom_widgets")
    add_menu_directory_item(string_load(30409),
                            "plugin://plugin.video.embycon/?mode=SHOW_ADDON_MENU&type=addon_items")
    add_menu_directory_item("Custom Nodes",
                            "plugin://plugin.video.embycon/?mode=SHOW_ADDON_MENU&type=custom_nodes")

    xbmcplugin.endOfDirectory(handle) def display_menu(params):
    menu_type = params.get("type")
    if menu_type == "library":
        display_library_views(params)
    elif menu_type == "library_item":
        display_library_view(params)
    elif menu_type == "show_global_types":
        show_global_types(params)
    elif menu_type == "global_list_movies":
        display_movies_type(params, None)
    elif menu_type == "global_list_tvshows":
        display_tvshow_type(params, None)
    elif menu_type == "show_custom_widgets":
        show_widgets()
    elif menu_type == "addon_items":
        display_addon_menu(params)
    elif menu_type == "show_movie_years":
        show_movie_years(params)
    elif menu_type == "show_movie_tags":
        show_movie_tags(params)
    elif menu_type == "custom_nodes":
        show_custom_nodes(params)
    elif menu_type == "create_new_node":
        create_new_node(params) def show_movie_alpha_list(menu_params):
    log.debug("== ENTER: showMovieAlphaList() ==")

    xbmcplugin.setContent(int(sys.argv[1]), 'movies')

    settings = xbmcaddon.Addon()
    server = downloadUtils.get_server()
    if server is None:
        return

    group_movies = settings.getSetting('group_movies') == "true"
    parent_id = menu_params.get("parent_id")

    url_params = {}
    url_params["IncludeItemTypes"] = "Movie"
    url_params["Recursive"] = True
    url_params["GroupItemsIntoCollections"] = group_movies
    url_params["UserId"] = "{userid}"
    url_params["SortBy"] = "Name"
    url_params["SortOrder"] = "Ascending"
    if parent_id is not None:
        url_params["ParentId"] = parent_id

    prefix_url = get_emby_url("{server}/emby/Items/Prefixes", url_params)

    data_manager = DataManager()
    result = data_manager.get_content(prefix_url)

    if not result:
        return

    alpha_list = []
    for prefix in result:
        alpha_list.append(prefix.get("Name"))

    collections = []
    for alphaName in alpha_list:
        item_data = {}
        item_data['title'] = alphaName
        item_data['media_type'] = "Movies"

        params = {}
        params["Fields"] = "{field_filters}"
        params["CollapseBoxSetItems"] = group_movies
        params["GroupItemsIntoCollections"] = group_movies
        params["Recursive"] = True
        params["IncludeItemTypes"] = "Movie"
        params["SortBy"] = "Name"
        params["SortOrder"] = "Ascending"
        params["ImageTypeLimit"] = 1

        if parent_id is not None:
            params["ParentId"] = parent_id

        if alphaName == "#":
            params["NameLessThan"] = "A"
        else:
            params["NameStartsWith"] = alphaName

        url = get_emby_url("{server}/emby/Users/{userid}/Items", params)
        item_data['path'] = url

        art = {"thumb": "http://localhost:24276/" + base64.b64encode(url)}
        item_data['art'] = art

        collections.append(item_data)

    for collection in collections:
        url = (sys.argv[0] + "?url=" + urllib.quote(collection['path']) +
               "&mode=GET_CONTENT&media_type=" + collection["media_type"])
        log.debug("addMenuDirectoryItem: {0} ({1})", collection.get('title'), url)
        add_menu_directory_item(collection.get('title', string_load(30250)), url, art=collection.get("art"))

    xbmcplugin.endOfDirectory(int(sys.argv[1])) def show_tvshow_alpha_list(menu_params):
    log.debug("== ENTER: showTvShowAlphaList() ==")

    server = downloadUtils.get_server()
    if server is None:
        return

    parent_id = menu_params.get("parent_id")

    url_params = {}
    url_params["IncludeItemTypes"] = "Series"
    url_params["Recursive"] = True
    url_params["UserId"] = "{userid}"
    url_params["SortBy"] = "Name"
    url_params["SortOrder"] = "Ascending"
    if parent_id is not None:
        menu_params["ParentId"] = parent_id
    prefix_url = get_emby_url("{server}/emby/Items/Prefixes", url_params)

    data_manager = DataManager()
    result = data_manager.get_content(prefix_url)

    if not result:
        return

    alpha_list = []
    for prefix in result:
        alpha_list.append(prefix.get("Name"))

    collections = []
    for alpha_name in alpha_list:
        item_data = {}
        item_data['title'] = alpha_name
        item_data['media_type'] = "tvshows"

        params = {}
        params["Fields"] = "{field_filters}"
        params["ImageTypeLimit"] = 1
        params["IncludeItemTypes"] = "Series"
        params["SortBy"] = "Name"
        params["SortOrder"] = "Ascending"
        params["Recursive"] = True
        params["IsMissing"] = False

        if parent_id is not None:
            params["ParentId"] = parent_id

        if alpha_name == "#":
            params["NameLessThan"] = "A"
        else:
            params["NameStartsWith"] = alpha_name

        path = get_emby_url("{server}/emby/Users/{userid}/Items", params)

        item_data['path'] = path

        art = {"thumb": "http://localhost:24276/" + base64.b64encode(path)}
        item_data['art'] = art

        collections.append(item_data)

    for collection in collections:
        url = (sys.argv[0] + "?url=" + urllib.quote(collection['path']) +
               "&mode=GET_CONTENT&media_type=" + collection["media_type"])
        log.debug("addMenuDirectoryItem: {0} ({1})", collection.get('title'), url)
        add_menu_directory_item(collection.get('title', string_load(30250)), url, art=collection.get("art"))

    xbmcplugin.endOfDirectory(int(sys.argv[1])) def show_genre_list(menu_params):
    log.debug("showGenreList: {0}", menu_params)

    server = downloadUtils.get_server()
    if server is None:
        return

    parent_id = menu_params.get("parent_id")
    item_type = menu_params.get("item_type")

    kodi_type = "Movies"
    emby_type = "Movie"
    if item_type is not None and item_type == "tvshow":
        emby_type = "Series"
        kodi_type = "tvshows"

    params = {}
    params["IncludeItemTypes"] = emby_type
    params["UserId"] = "{userid}"
    params["Recursive"] = True
    params["SortBy"] = "Name"
    params["SortOrder"] = "Ascending"
    params["ImageTypeLimit"] = 1

    if parent_id is not None:
        params["ParentId"] = parent_id

    url = get_emby_url("{server}/emby/Genres", params)

    data_manager = DataManager()
    result = data_manager.get_content(url)

    if result is not None:
        result = result.get("Items")
    else:
        result = []

    settings = xbmcaddon.Addon()
    group_movies = settings.getSetting('group_movies') == "true"

    collections = []
    xbmcplugin.setContent(int(sys.argv[1]), 'genres')

    for genre in result:
        item_data = {}
        item_data['title'] = genre.get("Name")
        item_data['media_type'] = kodi_type

        # art = getArt(item=genre, server=server)
        # item_data['art'] = art

        params = {}
        params["Recursive"] = True
        params["CollapseBoxSetItems"] = str(group_movies)
        params["GroupItemsIntoCollections"] = str(group_movies)
        params["GenreIds"] = genre.get("Id")
        params["IncludeItemTypes"] = emby_type
        params["ImageTypeLimit"] = 1
        params["Fields"] = "{field_filters}"

        if parent_id is not None:
            params["ParentId"] = parent_id

        url = get_emby_url("{server}/emby/Users/{userid}/Items", params)

        art = {"thumb": "http://localhost:24276/" + base64.b64encode(url)}
        item_data['art'] = art

        item_data['path'] = url
        collections.append(item_data)

    for collection in collections:
        url = sys.argv[0] + ("?url=" + urllib.quote(collection['path']) +
                             "&mode=GET_CONTENT" +
                             "&media_type=" + collection["media_type"])
        log.debug("addMenuDirectoryItem: {0} - {1} - {2}", collection.get('title'), url, collection.get("art"))
        add_menu_directory_item(collection.get('title', string_load(30250)), url, art=collection.get("art"))

    xbmcplugin.endOfDirectory(int(sys.argv[1])) def show_search():
    add_menu_directory_item(string_load(30231), 'plugin://plugin.video.embycon/?mode=NEW_SEARCH&item_type=Movie')
    add_menu_directory_item(string_load(30229), 'plugin://plugin.video.embycon/?mode=NEW_SEARCH&item_type=Series')
    add_menu_directory_item(string_load(30235), 'plugin://plugin.video.embycon/?mode=NEW_SEARCH&item_type=Episode')
    add_menu_directory_item(string_load(30337), 'plugin://plugin.video.embycon/?mode=NEW_SEARCH&item_type=Audio')
    add_menu_directory_item(string_load(30338), 'plugin://plugin.video.embycon/?mode=NEW_SEARCH&item_type=MusicAlbum')
    add_menu_directory_item(string_load(30339), 'plugin://plugin.video.embycon/?mode=NEW_SEARCH&item_type=Person')

    xbmcplugin.endOfDirectory(int(sys.argv[1])) def show_movie_pages(menu_params):
    log.debug("showMoviePages: {0}", menu_params)

    parent_id = menu_params.get("parent_id")
    settings = xbmcaddon.Addon()
    group_movies = settings.getSetting('group_movies') == "true"

    params = {}
    params["IncludeItemTypes"] = "Movie"
    params["CollapseBoxSetItems"] = str(group_movies)
    params["GroupItemsIntoCollections"] = str(group_movies)
    params["Recursive"] = True
    params["IsMissing"] = False
    params["ImageTypeLimit"] = 0

    if parent_id:
        params["ParentId"] = parent_id

    url = get_emby_url("{server}/emby/Users/{userid}/Items", params)

    data_manager = DataManager()
    result = data_manager.get_content(url)

    if result is None:
        return

    total_results = result.get("TotalRecordCount", 0)
    log.debug("showMoviePages TotalRecordCount {0}", total_results)

    if result == 0:
        return

    page_limit = int(settings.getSetting('itemsPerPage'))
    if page_limit == 0:
        page_limit = 20

    start_index = 0
    collections = []

    while start_index < total_results:

        params = {}
        params["IncludeItemTypes"] = "Movie"
        params["CollapseBoxSetItems"] = str(group_movies)
        params["GroupItemsIntoCollections"] = str(group_movies)
        params["Recursive"] = True
        params["IsMissing"] = False
        params["ImageTypeLimit"] = 1
        params["SortBy"] = "Name"
        params["SortOrder"] = "Ascending"
        params["Fields"] = "{field_filters}"
        params["StartIndex"] = start_index
        params["Limit"] = page_limit

        if parent_id:
            params["ParentId"] = parent_id

        item_url = get_emby_url("{server}/emby/Users/{userid}/Items", params)

        page_upper = start_index + page_limit
        if page_upper > total_results:
            page_upper = total_results

        item_data = {}
        item_data['title'] = "Page (" + str(start_index + 1) + " - " + str(page_upper) + ")"
        item_data['path'] = item_url
        item_data['media_type'] = 'movies'

        item_data["art"] = {"thumb": "http://localhost:24276/" + base64.b64encode(item_url)}

        collections.append(item_data)
        start_index = start_index + page_limit

    for collection in collections:
        content_url = urllib.quote(collection['path'])
        url = sys.argv[0] + ("?url=" + content_url +
                             "&mode=GET_CONTENT" +
                             "&media_type=" + collection["media_type"])
        log.debug("addMenuDirectoryItem: {0} - {1} - {2}", collection.get('title'), url, collection.get("art"))
        add_menu_directory_item(collection.get('title', string_load(30250)), url, art=collection.get("art"))

    xbmcplugin.endOfDirectory(int(sys.argv[1])) def show_tvshow_pages(menu_params):
    log.debug("showTvShowPages: {0}", menu_params)

    parent_id = menu_params.get("parent_id")
    settings = xbmcaddon.Addon()

    params = {}
    params["IncludeItemTypes"] = "Series"
    params["IsMissing"] = False
    params["ImageTypeLimit"] = 0

    if parent_id:
        params["ParentId"] = parent_id

    url = get_emby_url("{server}/emby/Users/{userid}/Items", params)

    data_manager = DataManager()
    result = data_manager.get_content(url)

    if result is None:
        return

    total_results = result.get("TotalRecordCount", 0)
    log.debug("showMoviePages TotalRecordCount {0}", total_results)

    if result == 0:
        return

    page_limit = int(settings.getSetting('itemsPerPage'))
    if page_limit == 0:
        page_limit = 20

    start_index = 0
    collections = []

    while start_index < total_results:

        params = {}
        params["IncludeItemTypes"] = "Series"
        params["IsMissing"] = False
        params["ImageTypeLimit"] = 1
        params["SortBy"] = "Name"
        params["SortOrder"] = "Ascending"
        params["Fields"] = "{field_filters}"
        params["StartIndex"] = start_index
        params["Limit"] = page_limit

        if parent_id:
            params["ParentId"] = parent_id

        item_url = get_emby_url("{server}/emby/Users/{userid}/Items", params)

        page_upper = start_index + page_limit
        if page_upper > total_results:
            page_upper = total_results

        item_data = {}
        item_data['title'] = "Page (" + str(start_index + 1) + " - " + str(page_upper) + ")"
        item_data['path'] = item_url
        item_data['media_type'] = 'tvshows'

        item_data["art"] = {"thumb": "http://localhost:24276/" + base64.b64encode(item_url)}

        collections.append(item_data)
        start_index = start_index + page_limit

    for collection in collections:
        content_url = urllib.quote(collection['path'])
        url = sys.argv[0] + ("?url=" + content_url +
                             "&mode=GET_CONTENT" +
                             "&media_type=" + collection["media_type"])
        log.debug("addMenuDirectoryItem: {0} - {1} - {2}", collection.get('title'), url, collection.get("art"))
        add_menu_directory_item(collection.get('title', string_load(30250)), url, art=collection.get("art"))

    xbmcplugin.endOfDirectory(int(sys.argv[1])) def get_node_url(node_info):
    log.debug("get_node_url : {0}", node_info)

    base_params = {}
    base_params["Fields"] = "{field_filters}"
    base_params["ImageTypeLimit"] = 1
    base_params["IsMissing"] = False

    if "item_parent" in node_info and node_info["item_parent"]:
        base_params["ParentId"] = node_info["item_parent"]
    if "recursive" in node_info and node_info["recursive"]:
        base_params["Recursive"] = node_info["recursive"]
    if "item_type" in node_info and node_info["item_type"]:
        base_params["IncludeItemTypes"] = node_info["item_type"]
    if "item_limit" in node_info and node_info["item_limit"]:
        base_params["Limit"] = node_info["item_limit"]
    if "group" in node_info and node_info["group"]:
        base_params["GroupItemsIntoCollections"] = node_info["group"]
        base_params["CollapseBoxSetItems"] = node_info["group"]
    if "watched" in node_info and node_info["watched"]:
        base_params["IsPlayed"] = node_info["watched"]
    if "inprogress" in node_info and node_info["inprogress"] == "True":
        base_params["Filters"] = "IsResumable"
    if "sortby" in node_info and node_info["sortby"]:
        base_params["SortBy"] = node_info["sortby"]
    if "sortorder" in node_info and node_info["sortorder"]:
        base_params["SortOrder"] = node_info["sortorder"]

    path = get_emby_url("{server}/emby/Users/{userid}/Items", base_params)
    return path 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) def show_server_sessions():
    log.debug("showServerSessions Called")

    handle = int(sys.argv[1])
    download_utils = DownloadUtils()
    data_manager = DataManager()

    url = "{server}/emby/Users/{userid}"
    results = data_manager.get_content(url)

    is_admin = results.get("Policy", {}).get("IsAdministrator", False)
    if not is_admin:
        xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
        return

    url = "{server}/emby/Sessions"
    results = data_manager.get_content(url)
    log.debug("session_info: {0}", results)

    if results is None:
        return

    list_items = []
    for session in results:
        device_name = session.get("DeviceName", "na")
        user_name = session.get("UserName", "na")
        client_name = session.get("Client", "na")
        client_version = session.get("ApplicationVersion", "na")

        play_state = session.get("PlayState", None)
        now_playing = session.get("NowPlayingItem", None)
        transcoding_info = session.get("TranscodingInfo", None)

        session_info = user_name + " - " + client_name
        user_session_details = ""

        percenatge_played = 0
        position_ticks = 0
        runtime = 0
        play_method = "na"

        if play_state is not None:
            position_ticks = play_state.get("PositionTicks", 0)
            play_method = play_state.get("PlayMethod", "na")

        art = {}
        if now_playing:
            server = download_utils.get_server()
            art = get_art(now_playing, server)

            runtime = now_playing.get("RunTimeTicks", 0)
            if position_ticks > 0 and runtime > 0:
                percenatge_played = (position_ticks / float(runtime)) * 100.0
                percenatge_played = int(percenatge_played)

            session_info += " (" + now_playing.get("Name", "na") + " " + str(percenatge_played) + "%)"
            user_session_details += now_playing.get("Name", "na") + " " + str(percenatge_played) + "%" + "\n"

        else:
            session_info += " (idle)"
            user_session_details += "Idle" + "\n"

        transcoding_details = ""
        if transcoding_info:
            if not transcoding_info.get("IsVideoDirect", None):
                transcoding_details += "Video:" + transcoding_info.get("VideoCodec", "") + ":" + str(transcoding_info.get("Width", 0)) + "x" + str(transcoding_info.get("Height", 0)) + "\n"
            else:
                transcoding_details += "Video:direct\n"

            if not transcoding_info.get("IsAudioDirect", None):
                transcoding_details += "Audio:" + transcoding_info.get("AudioCodec", "") + ":" + str(transcoding_info.get("AudioChannels", 0)) + "\n"
            else:
                transcoding_details += "Audio:direct\n"

            transcoding_details += "Bitrate:" + str(transcoding_info.get("Bitrate", 0)) + "\n"

        list_item = xbmcgui.ListItem(label=session_info)
        list_item.setArt(art)

        user_session_details += device_name + "(" + client_version + ")\n"
        user_session_details += client_name + "\n"
        user_session_details += play_method + "\n"
        user_session_details += transcoding_details + "\n"

        info_labels = {}
        info_labels["duration"] = str(runtime / 10000000)
        info_labels["mediatype"] = "movie"
        info_labels["plot"] = user_session_details
        list_item.setInfo('video', info_labels)

        list_item.setProperty('TotalTime', str(runtime / 10000000))
        list_item.setProperty('ResumeTime', str(position_ticks / 10000000))
        list_item.setProperty("complete_percentage", str(percenatge_played))

        item_tuple = ("", list_item, False)
        list_items.append(item_tuple)

    xbmcplugin.setContent(handle, "movies")
    xbmcplugin.addDirectoryItems(handle, list_items)
    xbmcplugin.endOfDirectory(handle, cacheToDisc=False) class ActionMenu(xbmcgui.WindowXMLDialog):

    selected_action = None
    action_items = None
    auto_close_thread = None
    listControl = None
    action_exitkeys_id = None

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

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

        self.listControl = self.getControl(3000)
        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, control_id):
        pass

    def doAction(self, action_id):
        pass

    def onMessage(self, message):
        log.debug("ActionMenu: 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("ActionMenu: onAction: {0}", action.getId())

    def onClick(self, control_id):
        if control_id == 3000:
            self.selected_action = self.listControl.getSelectedItem()
            log.debug("ActionMenu: Selected Item: {0}", self.selected_action)
            self.auto_close_thread.stop()
            self.close()

    def setActionItems(self, action_items):
        self.action_items = action_items

    def getActionItem(self):
        return self.selected_action class BitrateDialog(xbmcgui.WindowXMLDialog):

    slider_control = None
    bitrate_label = None
    initial_bitrate_value = 0
    selected_transcode_value = 0

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

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

        self.slider_control = self.getControl(3000)
        self.slider_control.setInt(self.initial_bitrate_value, 400, 100, 15000)

        self.bitrate_label = self.getControl(3030)
        bitrate_label_string = str(self.slider_control.getInt()) + " Kbs"
        self.bitrate_label.setLabel(bitrate_label_string)

    def onFocus(self, control_id):
        pass

    def doAction(self, action_id):
        pass

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

    def onAction(self, action):

        # log.debug("onAction: onAction: {0} {1}", action.getId(), self.slider_control.getInt())

        bitrate_label_string = str(self.slider_control.getInt()) + " Kbs"
        self.bitrate_label.setLabel(bitrate_label_string)

        if action.getId() == 10:  # ACTION_PREVIOUS_MENU
            self.close()
        elif action.getId() == 92:  # ACTION_NAV_BACK
            self.close()
        elif action.getId() == 7:  # ENTER
            self.selected_transcode_value = self.slider_control.getInt()
            self.close()

    def onClick(self, control_id):
        if control_id == 3000:
            log.debug("ActionMenu: Selected Item: {0}", control_id)
            #self.close() class SafeDeleteDialog(xbmcgui.WindowXMLDialog):

    confirm = False
    message = "Demo Message"
    heading = "Demo Heading"
    action_exitkeys_id = None

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

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

        message_control = self.getControl(3)
        message_control.setText(self.message)

        message_control = self.getControl(4)
        message_control.setLabel(self.heading)

    def onFocus(self, controlId):
        pass

    def doAction(self, actionID):
        pass

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

    def onAction(self, action):

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

    def onClick(self, controlID):
        if controlID == 1:
            self.confirm = True
            self.close()
        elif controlID == 2:
            self.confirm = False
            self.close() @timer
def get_widget_content(handle, params):
    log.debug("getWigetContent Called: {0}", params)

    settings = xbmcaddon.Addon()
    hide_watched = settings.getSetting("hide_watched") == "true"

    widget_type = params.get("type")
    if widget_type is None:
        log.error("getWigetContent type not set")
        return

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

    url_verb = "{server}/emby/Users/{userid}/Items"
    url_params = {}
    url_params["Limit"] = "{ItemLimit}"
    url_params["format"] = "json"
    url_params["Fields"] = "{field_filters}"
    url_params["ImageTypeLimit"] = 1
    url_params["IsMissing"] = False

    if widget_type == "recent_movies":
        xbmcplugin.setContent(handle, 'movies')
        url_params["Recursive"] = True
        url_params["SortBy"] = "DateCreated"
        url_params["SortOrder"] = "Descending"
        url_params["Filters"] = "IsNotFolder"
        if hide_watched:
            url_params["IsPlayed"] = False
        url_params["IsVirtualUnaired"] = False
        url_params["IncludeItemTypes"] = "Movie"

    elif widget_type == "inprogress_movies":
        xbmcplugin.setContent(handle, 'movies')
        url_params["Recursive"] = True
        url_params["SortBy"] = "DatePlayed"
        url_params["SortOrder"] = "Descending"
        url_params["Filters"] = "IsResumable"
        url_params["IsVirtualUnaired"] = False
        url_params["IncludeItemTypes"] = "Movie"

    elif widget_type == "random_movies":
        xbmcplugin.setContent(handle, 'movies')
        url_params["Ids"] = "{random_movies}"

    elif widget_type == "recent_tvshows":
        xbmcplugin.setContent(handle, 'episodes')
        url_verb = '{server}/emby/Users/{userid}/Items/Latest'
        url_params["GroupItems"] = True
        url_params["Limit"] = 200
        url_params["Recursive"] = True
        url_params["SortBy"] = "DateCreated"
        url_params["SortOrder"] = "Descending"
        url_params["Fields"] = "{field_filters}"
        if hide_watched:
            url_params["IsPlayed"] = False
        url_params["IsVirtualUnaired"] = False
        url_params["IncludeItemTypes"] = "Episode"
        url_params["ImageTypeLimit"] = 1
        url_params["format"] = "json"

    elif widget_type == "recent_episodes":
        xbmcplugin.setContent(handle, 'episodes')
        url_params["Recursive"] = True
        url_params["SortBy"] = "DateCreated"
        url_params["SortOrder"] = "Descending"
        url_params["Filters"] = "IsNotFolder"
        if hide_watched:
            url_params["IsPlayed"] = False
        url_params["IsVirtualUnaired"] = False
        url_params["IncludeItemTypes"] = "Episode"

    elif widget_type == "inprogress_episodes":
        xbmcplugin.setContent(handle, 'episodes')
        url_params["Recursive"] = True
        url_params["SortBy"] = "DatePlayed"
        url_params["SortOrder"] = "Descending"
        url_params["Filters"] = "IsResumable"
        url_params["IsVirtualUnaired"] = False
        url_params["IncludeItemTypes"] = "Episode"

    elif widget_type == "nextup_episodes":
        xbmcplugin.setContent(handle, 'episodes')
        url_verb = "{server}/emby/Shows/NextUp"
        url_params["Limit"] = "{ItemLimit}"
        url_params["userid"] = "{userid}"
        url_params["Recursive"] = True
        url_params["Fields"] = "{field_filters}"
        url_params["format"] = "json"
        url_params["ImageTypeLimit"] = 1
        url_params["Legacynextup"] = "true"

    elif widget_type == "movie_recommendations":
        suggested_items_url_params = {}
        suggested_items_url_params["userId"] = "{userid}"
        suggested_items_url_params["categoryLimit"] = 15
        suggested_items_url_params["ItemLimit"] = 20
        suggested_items_url_params["ImageTypeLimit"] = 0
        suggested_items_url = get_emby_url("{server}/emby/Movies/Recommendations", suggested_items_url_params)

        data_manager = DataManager()
        suggested_items = data_manager.get_content(suggested_items_url)
        ids = []
        set_id = 0
        while len(ids) < 20 and suggested_items:
            items = suggested_items[set_id]
            log.debug("BaselineItemName : {0} - {1}", set_id, items.get("BaselineItemName"))
            items = items["Items"]
            rand = random.randint(0, len(items) - 1)
            # log.debug("random suggestions index : {0} {1}", rand, set_id)
            item = items[rand]
            if item["Type"] == "Movie" and item["Id"] not in ids and (not item["UserData"]["Played"] or not hide_watched):
                # log.debug("random suggestions adding : {0}", item["Id"])
                ids.append(item["Id"])
            # else:
            #     log.debug("random suggestions not valid : {0} - {1} - {2}", item["Id"], item["Type"], item["UserData"]["Played"])
            del items[rand]
            # log.debug("items len {0}", len(items))
            if len(items) == 0:
                # log.debug("Removing Set {0}", set_id)
                del suggested_items[set_id]
            set_id += 1
            if set_id >= len(suggested_items):
                set_id = 0

        id_list = ",".join(ids)
        log.debug("Recommended Items : {0}", len(ids), id_list)
        url_params["Ids"] = id_list

    items_url = get_emby_url(url_verb, url_params)

    list_items, detected_type, total_records = process_directory(items_url, None, params, False)

    # remove resumable items from next up
    if widget_type == "nextup_episodes":
        filtered_list = []
        for item in list_items:
            resume_time = item[1].getProperty("ResumeTime")
            if resume_time is None or float(resume_time) == 0.0:
                filtered_list.append(item)
        list_items = filtered_list

    # list_items = populateWidgetItems(items_url, widget_type)

    if detected_type is not None:
        # if the media type is not set then try to use the detected type
        log.debug("Detected content type: {0}", detected_type)
        content_type = None

        if detected_type == "Movie":
            content_type = 'movies'
        elif detected_type == "Episode":
            content_type = 'episodes'
        elif detected_type == "Series":
            content_type = 'tvshows'
        elif detected_type == "Music" or detected_type == "Audio" or detected_type == "Musicalbum":
            content_type = 'songs'

        if content_type:
            xbmcplugin.setContent(handle, content_type)

    xbmcplugin.addDirectoryItems(handle, list_items)
    xbmcplugin.endOfDirectory(handle, cacheToDisc=False) @timer
def get_widget_content_cast(handle, params):
    log.debug("getWigetContentCast Called: {0}", params)
    server = downloadUtils.get_server()

    item_id = params["id"]
    data_manager = DataManager()
    result = data_manager.get_content("{server}/emby/Users/{userid}/Items/" + item_id + "?format=json")
    log.debug("ItemInfo: {0}", result)

    if not result:
        return

    if result.get("Type", "") in ["Episode", "Season"] and params.get("auto", "true") == "true":
        series_id = result.get("SeriesId")
        if series_id:
            params["id"] = series_id
            return get_widget_content_cast(handle, params)

    list_items = []
    if result is not None:
        people = result.get("People", [])
    else:
        people = []

    for person in people:
        # if (person.get("Type") == "Director"):
        #     director = director + person.get("Name") + ' '
        # if (person.get("Type") == "Writing"):
        #     writer = person.get("Name")
        # if (person.get("Type") == "Writer"):
        #    writer = person.get("Name")
        if person.get("Type") == "Actor":
            person_name = person.get("Name")
            person_role = person.get("Role")
            person_id = person.get("Id")
            person_tag = person.get("PrimaryImageTag")
            person_thumbnail = None
            if person_tag:
                person_thumbnail = downloadUtils.image_url(person_id, "Primary", 0, 400, 400, person_tag, server=server)

            if kodi_version > 17:
                list_item = xbmcgui.ListItem(label=person_name, offscreen=True)
            else:
                list_item = xbmcgui.ListItem(label=person_name)

            list_item.setProperty("id", person_id)

            if person_thumbnail:
                art_links = {}
                art_links["thumb"] = person_thumbnail
                art_links["poster"] = person_thumbnail
                list_item.setArt(art_links)

            labels = {}
            labels["mediatype"] = "artist"
            list_item.setInfo(type="music", infoLabels=labels)

            if person_role:
                list_item.setLabel2(person_role)

            item_tupple = ("", list_item, False)
            list_items.append(item_tupple)

    xbmcplugin.setContent(handle, 'artists')
    xbmcplugin.addDirectoryItems(handle, list_items)
    xbmcplugin.endOfDirectory(handle, cacheToDisc=False) @timer
def check_for_new_content():
    log.debug("checkForNewContent Called")

    home_window = HomeWindow()

    url_params = {}
    url_params["Recursive"] = True
    url_params["limit"] = 1
    url_params["Fields"] = "DateCreated,Etag"
    url_params["SortBy"] = "DateCreated"
    url_params["SortOrder"] = "Descending"
    url_params["IncludeItemTypes"] = "Movie,Episode"
    url_params["ImageTypeLimit"] = 0
    url_params["format"] = "json"

    added_url = get_emby_url('{server}/emby/Users/{userid}/Items', url_params)

    added_result = downloadUtils.download_url(added_url, suppress=True)
    result = json.loads(added_result)
    log.debug("LATEST_ADDED_ITEM: {0}", result)

    last_added_date = ""
    if result is not None:
        items = result.get("Items", [])
        if len(items) > 0:
            item = items[0]
            last_added_date = item.get("Etag", "")
    log.debug("last_added_date: {0}", last_added_date)

    url_params = {}
    url_params["Recursive"] = True
    url_params["limit"] = 1
    url_params["Fields"] = "DateCreated,Etag"
    url_params["SortBy"] = "DatePlayed"
    url_params["SortOrder"] = "Descending"
    url_params["IncludeItemTypes"] = "Movie,Episode"
    url_params["ImageTypeLimit"] = 0
    url_params["format"] = "json"

    played_url = get_emby_url('{server}/emby/Users/{userid}/Items', url_params)

    played_result = downloadUtils.download_url(played_url, suppress=True)
    result = json.loads(played_result)
    log.debug("LATEST_PLAYED_ITEM: {0}", result)

    last_played_date = ""
    if result is not None:
        items = result.get("Items", [])
        if len(items) > 0:
            item = items[0]
            # last_played_date = item.get("Etag", "")
            user_data = item.get("UserData", None)
            if user_data is not None:
                last_played_date = user_data.get("LastPlayedDate", "")

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

    current_widget_hash = home_window.get_property("embycon_widget_reload")
    log.debug("Current Widget Hash: {0}", current_widget_hash)

    m = hashlib.md5()
    m.update(last_played_date + last_added_date)
    new_widget_hash = m.hexdigest()
    log.debug("New Widget Hash: {0}", new_widget_hash)

    if current_widget_hash != new_widget_hash:
        home_window.set_property("embycon_widget_reload", new_widget_hash)
        log.debug("Setting New Widget Hash: {0}", new_widget_hash) 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 @timer
def get_content(url, params):
    log.debug("== ENTER: getContent ==")

    default_sort = params.get("sort")
    media_type = params.get("media_type", None)
    if not media_type:
        xbmcgui.Dialog().ok(string_load(30135), string_load(30139))

    log.debug("URL: {0}", url)
    log.debug("MediaType: {0}", media_type)
    pluginhandle = int(sys.argv[1])

    settings = xbmcaddon.Addon()
    # determine view type, map it from media type to view type
    view_type = ""
    content_type = ""
    media_type = str(media_type).lower().strip()
    if media_type.startswith("movie"):
        view_type = "Movies"
        content_type = 'movies'
    elif media_type == "musicalbums":
        view_type = "Albums"
        content_type = 'albums'
    elif media_type == "musicartists":
        view_type = "Artists"
        content_type = 'artists'
    elif media_type == "musicartist":
        view_type = "Albums"
        content_type = 'albums'
    elif media_type == "music" or media_type == "audio" or media_type == "musicalbum":
        view_type = "Music"
        content_type = 'songs'
    elif media_type.startswith("boxsets"):
        view_type = "Movies"
        content_type = 'sets'
    elif media_type.startswith("boxset"):
        view_type = "BoxSets"
        content_type = 'movies'
    elif media_type == "tvshows":
        view_type = "Series"
        content_type = 'tvshows'
    elif media_type == "series":
        view_type = "Seasons"
        content_type = 'seasons'
    elif media_type == "season" or media_type == "episodes":
        view_type = "Episodes"
        content_type = 'episodes'
    elif media_type == "playlists":
        view_type = "Playlists"

    log.debug("media_type:{0} content_type:{1} view_type:{2} ", media_type, content_type, view_type)

    # show a progress indicator if needed
    progress = None
    if settings.getSetting('showLoadProgress') == "true":
        progress = xbmcgui.DialogProgress()
        progress.create(string_load(30112))
        progress.update(0, string_load(30113))

    # update url for paging
    start_index = 0
    page_limit = int(settings.getSetting('itemsPerPage'))
    url_prev = None
    url_next = None
    if page_limit > 0 and media_type.lower() in ["movies", "movie", "tvshows"]:
        log.debug("Creating Paging URLS: {0}", url)
        start_index_rex = "startindex=([0-9]{1,5})"
        limit_rex = "&limit=([0-9]{1,5})"
        limit_rex_p = "&Limit={ItemLimit}"

        # add StartIndex and Limit to the url if they are not there already
        # update limit to page limit if it is alreayd there
        if not re.search(start_index_rex, url, flags=re.IGNORECASE):
            url += "&StartIndex=0"

        if not re.search(limit_rex, url, flags=re.IGNORECASE) and not re.search(limit_rex_p, url, flags=re.IGNORECASE):
            url += "&Limit=" + str(page_limit)
        else:
            url = re.sub(limit_rex, '&Limit=' + str(page_limit), url, flags=re.IGNORECASE)
            url = re.sub(limit_rex_p, '&Limit=' + str(page_limit), url, flags=re.IGNORECASE)

        # create NEXT and PREV urls
        start_index_match = re.search(start_index_rex, url, flags=re.IGNORECASE)
        start_index = int(start_index_match.group(1))
        if start_index > 0:
            prev_index = start_index - page_limit
            if prev_index < 0:
                prev_index = 0
            url_prev = re.sub(start_index_rex, 'StartIndex=' + str(prev_index), url, flags=re.IGNORECASE)
        url_next = re.sub(start_index_rex, 'StartIndex=' + str(start_index + page_limit), url, flags=re.IGNORECASE)

        log.debug("Paged URLS - url_current: {0}", url)
        log.debug("Paged URLS - url_prev: {0}", url_prev)
        log.debug("Paged URLS - url_next: {0}", url_next)

    # use the data manager to get the data
    # result = dataManager.GetContent(url)

    # total_records = 0
    # if result is not None and isinstance(result, dict):
    #    total_records = result.get("TotalRecordCount", 0)

    use_cache = params.get("use_cache", "true") == "true"

    dir_items, detected_type, total_records = process_directory(url, progress, params, use_cache)
    if dir_items is None:
        return

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

    # add paging items
    if page_limit > 0 and media_type.lower() in ["movies", "movie", "tvshows"]:
        if url_prev:
            list_item = xbmcgui.ListItem("Prev Page (" + str(start_index - page_limit + 1) + "-" + str(start_index) +
                                         " of " + str(total_records) + ")")
            u = sys.argv[0] + "?url=" + urllib.quote(url_prev) + "&mode=GET_CONTENT&media_type=movies"
            log.debug("ADDING PREV ListItem: {0} - {1}", u, list_item)
            dir_items.insert(0, (u, list_item, True))

        if start_index + page_limit < total_records:
            upper_count = start_index + (page_limit * 2)
            if upper_count > total_records:
                upper_count = total_records
            list_item = xbmcgui.ListItem("Next Page (" + str(start_index + page_limit + 1) + "-" +
                                         str(upper_count) + " of " + str(total_records) + ")")
            u = sys.argv[0] + "?url=" + urllib.quote(url_next) + "&mode=GET_CONTENT&media_type=movies"
            log.debug("ADDING NEXT ListItem: {0} - {1}", u, list_item)
            dir_items.append((u, list_item, True))

    # set the Kodi content type
    if content_type:
        xbmcplugin.setContent(pluginhandle, content_type)
    elif detected_type is not None:
        # if the media type is not set then try to use the detected type
        log.debug("Detected content type: {0}", detected_type)
        if detected_type == "Movie":
            view_type = "Movies"
            content_type = 'movies'
        if detected_type == "Episode":
            view_type = "Episodes"
            content_type = 'episodes'
        xbmcplugin.setContent(pluginhandle, content_type)

    # set the sort items
    if page_limit > 0 and media_type.lower() in ["movies", "movie", "tvshows"]:
        xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_UNSORTED)
    else:
        set_sort(pluginhandle, view_type, default_sort)

    xbmcplugin.addDirectoryItems(pluginhandle, dir_items)
    xbmcplugin.endOfDirectory(pluginhandle, cacheToDisc=False)

    # set the view based on saved value
    view_key = "view-" + content_type
    view_id = settings.getSetting(view_key)
    if view_id:
        log.debug("Setting view for type:{0} to id:{1}", view_key, view_id)
        display_items_notification = {"view_id": view_id}
        send_event_notification("set_view", display_items_notification)
    else:
        log.debug("No view id for view type:{0}", view_key)

    # send display items event
    # display_items_notification = {"view_type": view_type}
    # log.debug("Sending display_items with data {0}", display_items_notification)
    # send_event_notification("display_items", display_items_notification)

    if progress is not None:
        progress.update(100, string_load(30125))
        progress.close()

    return @timer
def process_directory(url, progress, params, use_cache_data=False):
    log.debug("== ENTER: processDirectory ==")

    data_manager = DataManager()
    settings = xbmcaddon.Addon()
    download_utils = DownloadUtils()
    server = download_utils.get_server()

    name_format = params.get("name_format", None)
    name_format_type = None
    if name_format is not None:
        name_format = urllib.unquote(name_format)
        tokens = name_format.split("|")
        if len(tokens) == 2:
            name_format_type = tokens[0]
            name_format = settings.getSetting(tokens[1])
        else:
            name_format_type = None
            name_format = None

    gui_options = {}
    gui_options["server"] = server
    gui_options["name_format"] = name_format
    gui_options["name_format_type"] = name_format_type

    use_cache = settings.getSetting("use_cache") == "true" and use_cache_data
    cache_file, item_list, total_records, cache_thread = data_manager.get_items(url, gui_options, use_cache)

    # flatten single season
    # if there is only one result and it is a season and you have flatten signle season turned on then
    # build a new url, set the content media type and call get content again
    flatten_single_season = settings.getSetting("flatten_single_season") == "true"
    if flatten_single_season and len(item_list) == 1 and item_list[0].item_type == "Season":
        season_id = item_list[0].id
        series_id = item_list[0].series_id
        season_url = ('{server}/emby/Shows/' + series_id +
                      '/Episodes'
                      '?userId={userid}' +
                      '&seasonId=' + season_id +
                      '&IsVirtualUnAired=false' +
                      '&IsMissing=false' +
                      '&Fields=SpecialEpisodeNumbers,{field_filters}' +
                      '&format=json')
        if progress is not None:
            progress.close()
        params["media_type"] = "Episodes"
        get_content(season_url, params)
        return None, None, None

    hide_unwatched_details = settings.getSetting('hide_unwatched_details') == 'true'

    display_options = {}
    display_options["addCounts"] = settings.getSetting("addCounts") == 'true'
    display_options["addResumePercent"] = settings.getSetting("addResumePercent") == 'true'
    display_options["addSubtitleAvailable"] = settings.getSetting("addSubtitleAvailable") == 'true'
    display_options["addUserRatings"] = settings.getSetting("add_user_ratings") == 'true'

    show_empty_folders = settings.getSetting("show_empty_folders") == 'true'

    item_count = len(item_list)
    current_item = 1
    first_season_item = None
    total_unwatched = 0
    total_episodes = 0
    total_watched = 0

    detected_type = None
    dir_items = []

    for item_details in item_list:

        item_details.total_items = item_count

        if progress is not None:
            percent_done = (float(current_item) / float(item_count)) * 100
            progress.update(int(percent_done), string_load(30126) + str(current_item))
            current_item = current_item + 1

        if detected_type is not None:
            if item_details.item_type != detected_type:
                detected_type = "mixed"
        else:
            detected_type = item_details.item_type

        if item_details.item_type == "Season" and first_season_item is None:
            log.debug("Setting First Season to : {0}", item_details.__dict__)
            first_season_item = item_details

        total_unwatched += item_details.unwatched_episodes
        total_episodes += item_details.total_episodes
        total_watched += item_details.watched_episodes

        # if set, for unwatched episodes dont show some of the info
        if hide_unwatched_details and item_details.item_type == "Episode" and item_details.play_count == 0:
            item_details.plot = "[Spoiler Alert]"
            item_details.art["poster"] = item_details.art["tvshow.poster"]
            item_details.art["thumb"] = item_details.art["tvshow.poster"]

        if item_details.is_folder is True:
            if item_details.item_type == "Series":
                u = ('{server}/emby/Shows/' + item_details.id +
                     '/Seasons'
                     '?userId={userid}' +
                     '&Fields={field_filters}' +
                     '&format=json')

            elif item_details.item_type == "Season":
                u = ('{server}/emby/Shows/' + item_details.series_id +
                     '/Episodes'
                     '?userId={userid}' +
                     '&seasonId=' + item_details.id +
                     '&IsVirtualUnAired=false' +
                     '&IsMissing=false' +
                     '&Fields=SpecialEpisodeNumbers,{field_filters}' +
                     '&format=json')

            else:
                u = ('{server}/emby/Users/{userid}/items' +
                     '?ParentId=' + item_details.id +
                     '&IsVirtualUnAired=false' +
                     '&IsMissing=false' +
                     '&Fields={field_filters}' +
                     '&format=json')

            default_sort = item_details.item_type == "Playlist"

            if show_empty_folders or item_details.recursive_item_count != 0:
                gui_item = add_gui_item(u, item_details, display_options, default_sort=default_sort)
                if gui_item:
                    dir_items.append(gui_item)
            else:
                log.debug("Dropping empty folder item : {0}", item_details.__dict__)

        elif item_details.item_type == "MusicArtist":
            u = ('{server}/emby/Users/{userid}/items' +
                 '?ArtistIds=' + item_details.id +
                 '&IncludeItemTypes=MusicAlbum' +
                 '&CollapseBoxSetItems=false' +
                 '&Recursive=true' +
                 '&format=json')
            gui_item = add_gui_item(u, item_details, display_options)
            if gui_item:
                dir_items.append(gui_item)

        else:
            u = item_details.id
            gui_item = add_gui_item(u, item_details, display_options, folder=False)
            if gui_item:
                dir_items.append(gui_item)

    # add the all episodes item
    show_all_episodes = settings.getSetting('show_all_episodes') == 'true'
    if (show_all_episodes
            and first_season_item is not None
            and len(dir_items) > 1
            and first_season_item.series_id is not None):
        series_url = ('{server}/emby/Shows/' + first_season_item.series_id +
                      '/Episodes'
                      '?userId={userid}' +
                      # '&seasonId=' + season_id +
                      '&IsVirtualUnAired=false' +
                      '&IsMissing=false' +
                      '&Fields=SpecialEpisodeNumbers,{field_filters}' +
                      '&format=json')
        played = 0
        overlay = "7"
        if total_unwatched == 0:
            played = 1
            overlay = "6"

        item_details = ItemDetails()

        item_details.id = first_season_item.id
        item_details.name = string_load(30290)
        item_details.art = first_season_item.art
        item_details.play_count = played
        item_details.overlay = overlay
        item_details.name_format = "Episode|episode_name_format"
        item_details.series_name = first_season_item.series_name
        item_details.item_type = "Season"
        item_details.unwatched_episodes = total_unwatched
        item_details.total_episodes = total_episodes
        item_details.watched_episodes = total_watched
        item_details.mode = "GET_CONTENT"

        gui_item = add_gui_item(series_url, item_details, display_options, folder=True)
        if gui_item:
            dir_items.append(gui_item)

    if cache_thread is not None:
        cache_thread.start()

    return dir_items, detected_type, total_records 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 def clone_default_skin():
    xbmc.executebuiltin("Dialog.Close(all,true)")
    xbmc.executebuiltin("ActivateWindow(Home)")

    response = xbmcgui.Dialog().yesno("EmbyCon, Clone Estuary Skin?",
                                      "This will clone the default Estuary Kodi skin and add EmbyCon functionality to it.",
                                      "Once cloned you can switch between skins in the Kodi interface settings.",
                                      "Do you want to continue?")
    if not response:
        return

    clone_skin()
    set_skin_settings()
    update_kodi_settings()

    # xbmc.executebuiltin("ReloadSkin()")
    # xbmc.executebuiltin("ActivateWindow(Home)") def extract_media_info(item):
    media_info = []

    media_sources = item["MediaSources"]
    if media_sources is not None:
        for media_source in media_sources:
            media_info.append("Media Stream (%s)" % (media_source["Name"],))
            media_info.append(" -Type: %s" % (media_source["Type"],))
            media_info.append(" -Protocol: %s" % (media_source["Protocol"],))
            media_info.append(" -Path: %s" % (media_source["Path"],))
            media_info.append(" -IsRemote: %s" % (media_source["IsRemote"],))
            media_info.append(" -Container: %s" % (media_source["Container"],))
            if media_source["BitRate"] is not None:
                media_info.append(" -Bitrate: {:,}".format(media_source["Bitrate"]))
            if media_source["Size"] is not None:
                media_info.append(" -Size: {:,}".format(media_source["Size"]))
            media_info.append(" -DefaultAudioStreamIndex: %s" % (media_source["DefaultAudioStreamIndex"],))

            media_streams = media_source["MediaStreams"]
            if media_streams is not None:
                for mediaStream in media_streams:
                    stream_type = mediaStream["Type"]
                    if stream_type == "Video":
                        media_info.append(" -Video Stream")
                        media_info.append("   -Index: %s" % (mediaStream["Index"],))
                        media_info.append("   -Codec: %s" % (mediaStream["Codec"],))
                        media_info.append("   -Size: %sx%s" % (mediaStream["Width"], mediaStream["Height"]))
                        media_info.append("   -AspectRatio: %s" % (mediaStream["AspectRatio"],))
                        media_info.append("   -ColorSpace: %s" % (mediaStream["ColorSpace"],))
                        media_info.append("   -DisplayTitle: %s" % (mediaStream["DisplayTitle"],))
                        media_info.append("   -IsInterlaced: %s" % (mediaStream["IsInterlaced"],))
                        if mediaStream["BitRate"] is not None:
                            media_info.append("   -BitRate: {:,}".format(mediaStream["BitRate"]))
                        media_info.append("   -BitDepth: %s" % (mediaStream["BitDepth"],))
                        media_info.append("   -AverageFrameRate: %s" % (mediaStream["AverageFrameRate"],))
                        media_info.append("   -RealFrameRate: %s" % (mediaStream["RealFrameRate"],))
                        media_info.append("   -Profile: %s" % (mediaStream["Profile"],))
                        media_info.append("   -Level: %s" % (mediaStream["Level"],))
                        media_info.append("   -PixelFormat: %s" % (mediaStream["PixelFormat"],))
                        media_info.append("   -IsAnamorphic: %s" % (mediaStream["IsAnamorphic"],))

                    if stream_type == "Audio":
                        media_info.append(" -Audio Stream")
                        media_info.append("   -Index: %s" % (mediaStream["Index"],))
                        media_info.append("   -Title: %s" % (mediaStream["DisplayTitle"],))
                        media_info.append("   -Codec: %s" % (mediaStream["Codec"],))
                        media_info.append("   -ChannelLayout: %s" % (mediaStream["ChannelLayout"],))
                        media_info.append("   -Channels: %s" % (mediaStream["Channels"],))
                        if mediaStream["BitRate"] is not None:
                            media_info.append("   -BitRate: {:,}".format(mediaStream["BitRate"]))
                        media_info.append("   -SampleRate: %s" % (mediaStream["SampleRate"],))
                        media_info.append("   -IsDefault: %s" % (mediaStream["IsDefault"],))
                        media_info.append("   -IsForced: %s" % (mediaStream["IsForced"],))
                        media_info.append("   -IsExternal: %s" % (mediaStream["IsExternal"],))
                        media_info.append("   -IsExternal: %s" % (mediaStream["IsExternal"],))

                    if stream_type == "Subtitle":
                        media_info.append(" -Subtitle Stream")
                        media_info.append("   -Index: %s" % (mediaStream["Index"],))
                        media_info.append("   -Codec: %s" % (mediaStream["Codec"],))
                        media_info.append("   -Language: %s" % (mediaStream["Language"],))
                        media_info.append("   -DisplayTitle: %s" % (mediaStream["DisplayTitle"],))
                        media_info.append("   -DisplayLanguage: %s" % (mediaStream["DisplayLanguage"],))
                        media_info.append("   -IsDefault: %s" % (mediaStream["IsDefault"],))
                        media_info.append("   -IsForced: %s" % (mediaStream["IsForced"],))
                        media_info.append("   -IsExternal: %s" % (mediaStream["IsExternal"],))
                        media_info.append("   -IsTextSubtitleStream: %s" % (mediaStream["IsTextSubtitleStream"],))

            media_info.append("")

    return media_info def load_custom_nodes():
    log.debug("load_custom_nodes")
    addon_dir = xbmc.translatePath(xbmcaddon.Addon().getAddonInfo('profile'))
    node_info_path = os.path.join(addon_dir, "custom_nodes.json")
    if xbmcvfs.exists(node_info_path):
        log.debug("custom_nodes.json : Exists")
        with open(node_info_path) as json_file:
            custom_nodes = json.load(json_file)
            log.debug("custom_nodes.json Loaded : {0}", custom_nodes)
            return custom_nodes
    else:
        log.debug("custom_nodes.json : Does not exist ({0})", node_info_path)
        return {}
import urllib
import sys
import os
import time
import cProfile
import pstats
import json
import StringIO
import xbmcplugin
import xbmcgui
import xbmcaddon
import xbmc
from .downloadutils import DownloadUtils, load_user_details
from .utils import get_art, send_event_notification, convert_size
from .kodi_utils import HomeWindow
from .clientinfo import ClientInformation
from .datamanager import DataManager, clear_cached_server_data
from .server_detect import check_server, check_connection_speed
from .simple_logging import SimpleLogging
from .menu_functions import display_main_menu, display_menu, show_movie_alpha_list, show_tvshow_alpha_list, show_genre_list, show_search, show_movie_pages, show_tvshow_pages, get_node_url
from .translation import string_load
from .server_sessions import show_server_sessions
from .action_menu import ActionMenu
from .bitrate_dialog import BitrateDialog
from .safe_delete_dialog import SafeDeleteDialog
from .widgets import get_widget_content, get_widget_content_cast, check_for_new_content
from . import trakttokodi
from .cache_images import CacheArtwork
from .dir_functions import get_content, process_directory
from .tracking import timer
from .skin_cloner import clone_default_skin
from .item_functions import extract_media_info
from .custom_nodes import load_custom_nodes
# Gnu General Public License - see LICENSE.TXT




__addon__ = xbmcaddon.Addon()
__addondir__ = xbmc.translatePath(__addon__.getAddonInfo('profile'))
__cwd__ = __addon__.getAddonInfo('path')
PLUGINPATH = xbmc.translatePath(os.path.join(__cwd__))

log = SimpleLogging(__name__)

kodi_version = int(xbmc.getInfoLabel('System.BuildVersion')[:2])

downloadUtils = DownloadUtils()
dataManager = DataManager()


@timer
def main_entry_point():
    log.debug("===== EmbyCon START =====")

    settings = xbmcaddon.Addon()
    profile_count = int(settings.getSetting('profile_count'))
    pr = None
    if profile_count > 0:
        profile_count = profile_count - 1
        settings.setSetting('profile_count', str(profile_count))
        pr = cProfile.Profile()
        pr.enable()

    log.debug("Running Python: {0}", sys.version_info)
    log.debug("Running EmbyCon: {0}", ClientInformation().get_version())
    log.debug("Kodi BuildVersion: {0}", xbmc.getInfoLabel("System.BuildVersion"))
    log.debug("Kodi Version: {0}", kodi_version)
    log.debug("Script argument data: {0}", sys.argv)

    params = get_params()
    log.debug("Script params: {0}", params)

    request_path = params.get("request_path", None)
    param_url = params.get('url', None)

    if param_url:
        param_url = urllib.unquote(param_url)

    mode = params.get("mode", None)

    if len(params) == 1 and request_path and request_path.find("/library/movies") > -1:
        check_server()
        new_params = {}
        new_params["item_type"] = "Movie"
        new_params["media_type"] = "movies"
        show_content(new_params)
    elif mode == "CHANGE_USER":
        check_server(change_user=True, notify=False)
    elif mode == "CACHE_ARTWORK":
        CacheArtwork().cache_artwork_interactive()
    elif mode == "DETECT_SERVER":
        check_server(force=True, notify=True)
    elif mode == "DETECT_SERVER_USER":
        check_server(force=True, change_user=True, notify=False)
    elif mode == "DETECT_CONNECTION_SPEED":

        check_connection_speed()