def get_repo_resourceaddons(filterstr=""):
    '''helper to retrieve all available resource addons on the kodi repo'''
    result = []
    simplecache = SimpleCache()
    for item in xbmcvfs.listdir("addons://all/kodi.resource.images/")[1]:
        if not filterstr or item.lower().startswith(filterstr.lower()):
            addoninfo = get_repo_addoninfo(item, simplecache)
            if not addoninfo.get("name"):
                addoninfo = {"addonid": item, "name": item, "author": ""}
                addoninfo["thumbnail"] = "http://mirrors.kodi.tv/addons/krypton/%s/icon.png" % item
            addoninfo["path"] = "resource://%s/" % item
            result.append(addoninfo)
    simplecache.close()
    return result
Exemple #2
0
    def __init__(self):
        '''Initialize our Module'''

        self.cache = SimpleCache()
        self.win = xbmcgui.Window(10000)
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.log_msg("Initialized")
Exemple #3
0
 def __init__(self, simplecache=None):
     '''Initialize - optionaly provide simplecache object'''
     if not simplecache:
         from simplecache import SimpleCache
         self.cache = SimpleCache()
     else:
         self.cache = simplecache
 def __init__(self, *args, **kwargs):
     self.cache = SimpleCache()
     self.artutils = kwargs.get("artutils")
     self.win = kwargs.get("win")
     self.kodimonitor = kwargs.get("monitor")
     self.event = threading.Event()
     threading.Thread.__init__(self, *args)
Exemple #5
0
 def __init__(self):
     self.net     = net.Net()
     self.cache   = SimpleCache()
     self.region  = self.getRegion()
     self.filter  = False if self.region == 'US' else True
     self.categoryMenu = self.getCategories()
     self.mediaType = self.getMediaTypes()
     log('__init__, region = ' + self.region)
Exemple #6
0
 def __init__(self, simplecache=None):
     '''Initialize - optionaly provide simplecache object'''
     if not simplecache:
         from simplecache import SimpleCache
         self.cache = SimpleCache()
     else:
         self.cache = simplecache
     addon = xbmcaddon.Addon(id=ADDON_ID)
     self.api_key = addon.getSetting("tmdb_apikey")
     del addon
 def __init__(self, api_key=None):
     '''Initialize our Module'''
     if api_key:
         self.api_key = api_key
     self.cache = SimpleCache()
     self._win = xbmcgui.Window(10000)
     self._addon = xbmcaddon.Addon(ADDON_ID)
     addonversion = self._addon.getAddonInfo('version').decode("utf-8")
     self.cache.global_checksum = "%s%s" % (addonversion, KODI_LANGUAGE)
     self._log_msg("Initialized")
Exemple #8
0
class Newsy(object):
    def __init__(self):
        log('__init__')
        self.cache = SimpleCache()

            
    def openURL(self, url):
        log('openURL, url = ' + str(url))
        try:
            cacheResponse = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
            if not cacheResponse:
                request = urllib2.Request(url)
                request.add_header('User-Agent','Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)')
                response = urllib2.urlopen(request, timeout=TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, response, expiration=datetime.timedelta(hours=6))
            return self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
        except urllib2.URLError, e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
        except socket.timeout, e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
Exemple #9
0
def test_simple_cache():
    cache = SimpleCache(0.1)

    assert cache.get("hamster") == None
    cache.save("yumyum", "hamster")
    assert cache.get("hamster") == "yumyum"
    sleep(0.1)
    assert cache.get("hamster") == None
Exemple #10
0
    def __init__(self, simplecache=None, kodidb=None):
        '''Initialize - optionaly provide SimpleCache and KodiDb object'''

        if not kodidb:
            from kodidb import KodiDb
            self.kodidb = KodiDb()
        else:
            self.kodidb = kodidb

        if not simplecache:
            from simplecache import SimpleCache
            self.cache = SimpleCache()
        else:
            self.cache = simplecache
    def __init__(self):
        self.cache = SimpleCache()
        self.kodi_db = KodiDb()
        self.win = xbmcgui.Window(10000)
        try:
            self.params = dict(urlparse.parse_qsl(sys.argv[2].replace("?", "").lower().decode("utf-8")))
            log_msg("plugin called with parameters: %s" % self.params)
            self.main()
        except Exception as exc:
            log_exception(__name__, exc)
            xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

        # cleanup when done processing
        self.close()
Exemple #12
0
 def __init__(self):
     '''Initialize and load all our helpers'''
     self._studiologos_path = ""
     self.cache = SimpleCache()
     self.addon = xbmcaddon.Addon(ADDON_ID)
     self.kodidb = KodiDb()
     self.omdb = Omdb(self.cache)
     self.tmdb = Tmdb(self.cache)
     self.channellogos = ChannelLogos(self.kodidb)
     self.fanarttv = FanartTv(self.cache)
     self.imdb = Imdb(self.cache)
     self.google = GoogleImages(self.cache)
     self.studiologos = StudioLogos(self.cache)
     self.animatedart = AnimatedArt(self.cache, self.kodidb)
     self.thetvdb = TheTvDb()
     self.musicart = MusicArtwork(self)
     self.pvrart = PvrArtwork(self)
     log_msg("Initialized")
Exemple #13
0
    def __init__(self):
        '''Initialization and main code run'''
        self.win = xbmcgui.Window(10000)
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.kodidb = KodiDb()
        self.cache = SimpleCache()

        self.params = self.get_params()
        log_msg("MainModule called with parameters: %s" % self.params)
        action = self.params.get("action", "")
        # launch module for action provided by this script
        try:
            getattr(self, action)()
        except AttributeError:
            log_exception(__name__, "No such action: %s" % action)
        except Exception as exc:
            log_exception(__name__, exc)
        finally:
            xbmc.executebuiltin("dialog.Close(busydialog)")

        # do cleanup
        self.close()
Exemple #14
0
 def __init__(self):
     log('__init__')
     self.cache = SimpleCache()
     self.ydl = YoutubeDL()
Exemple #15
0
class Tmdb(object):
    """get metadata from tmdb"""
    api_key = None  # public var to be set by the calling addon

    def __init__(self, simplecache=None, api_key=None):
        """Initialize - optionaly provide simplecache object"""
        if not simplecache:
            from simplecache import SimpleCache
            self.cache = SimpleCache()
        else:
            self.cache = simplecache
        addon = xbmcaddon.Addon(id=ADDON_ID)
        # personal api key (preferred over provided api key)
        api_key = addon.getSetting("tmdb_apikey")
        if api_key:
            self.api_key = api_key
        del addon

    def search_movie(self,
                     title,
                     year="",
                     manual_select=False,
                     ignore_cache=False):
        """
            Search tmdb for a specific movie, returns full details of best match
            parameters:
            title: (required) the title of the movie to search for
            year: (optional) the year of the movie to search for (enhances search result if supplied)
            manual_select: (optional) if True will show select dialog with all results
        """
        details = self.select_best_match(self.search_movies(title, year),
                                         manual_select=manual_select)
        if details:
            details = self.get_movie_details(details["id"])
        return details

    @use_cache(30)
    def search_movieset(self, title):
        """search for movieset details providing the title of the set"""
        details = {}
        params = {"query": title, "language": KODI_LANGUAGE}
        result = self.get_data("search/collection", params)
        if result:
            set_id = result[0]["id"]
            details = self.get_movieset_details(set_id)
        return details

    @use_cache(4)
    def search_tvshow(self,
                      title,
                      year="",
                      manual_select=False,
                      ignore_cache=False):
        """
            Search tmdb for a specific movie, returns full details of best match
            parameters:
            title: (required) the title of the movie to search for
            year: (optional) the year of the movie to search for (enhances search result if supplied)
            manual_select: (optional) if True will show select dialog with all results
        """
        details = self.select_best_match(self.search_tvshows(title, year),
                                         manual_select=manual_select)
        if details:
            details = self.get_tvshow_details(details["id"])
        return details

    @use_cache(4)
    def search_video(self,
                     title,
                     prefyear="",
                     preftype="",
                     manual_select=False,
                     ignore_cache=False):
        """
            Search tmdb for a specific entry (can be movie or tvshow), returns full details of best match
            parameters:
            title: (required) the title of the movie/tvshow to search for
            prefyear: (optional) prefer result if year matches
            preftype: (optional) prefer result if type matches
            manual_select: (optional) if True will show select dialog with all results
        """
        results = self.search_videos(title)
        details = self.select_best_match(results,
                                         prefyear=prefyear,
                                         preftype=preftype,
                                         preftitle=title,
                                         manual_select=manual_select)
        if details and details["media_type"] == "movie":
            details = self.get_movie_details(details["id"])
        elif details and "tv" in details["media_type"]:
            details = self.get_tvshow_details(details["id"])
        return details

    @use_cache(4)
    def search_videos(self, title):
        """
            Search tmdb for a specific entry (can be movie or tvshow), parameters:
            title: (required) the title of the movie/tvshow to search for
        """
        results = []
        page = 1
        maxpages = 5
        while page < maxpages:
            params = {"query": title, "language": KODI_LANGUAGE, "page": page}
            subresults = self.get_data("search/multi", params)
            page += 1
            if subresults:
                for item in subresults:
                    if item["media_type"] in ["movie", "tv"]:
                        results.append(item)
            else:
                break
        return results

    @use_cache(4)
    def search_movies(self, title, year=""):
        """
            Search tmdb for a specific movie, returns a list of all closest matches
            parameters:
            title: (required) the title of the movie to search for
            year: (optional) the year of the movie to search for (enhances search result if supplied)
        """
        params = {"query": title, "language": KODI_LANGUAGE}
        if year:
            params["year"] = try_parse_int(year)
        return self.get_data("search/movie", params)

    @use_cache(4)
    def search_tvshows(self, title, year=""):
        """
            Search tmdb for a specific tvshow, returns a list of all closest matches
            parameters:
            title: (required) the title of the tvshow to search for
            year: (optional) the first air date year of the tvshow to search for (enhances search result if supplied)
        """
        params = {"query": title, "language": KODI_LANGUAGE}
        if year:
            params["first_air_date_year"] = try_parse_int(year)
        return self.get_data("search/tv", params)

    def get_actor(self, name):
        """
            Search tmdb for a specific actor/person, returns the best match as kodi compatible dict
            required parameter: name --> the name of the person
        """
        params = {"query": name, "language": KODI_LANGUAGE}
        result = self.get_data("search/person", params)
        if result:
            result = result[0]
            cast_thumb = "https://image.tmdb.org/t/p/original%s" % result[
                "profile_path"] if result["profile_path"] else ""
            item = {
                "name":
                result["name"],
                "thumb":
                cast_thumb,
                "roles": [
                    item["title"] if item.get("title") else item["name"]
                    for item in result["known_for"]
                ]
            }
            return item
        else:
            return {}

    def get_movie_details(self, movie_id):
        """get all moviedetails"""
        params = {
            "append_to_response": "keywords,videos,credits,images",
            "include_image_language": "%s,en" % KODI_LANGUAGE,
            "language": KODI_LANGUAGE
        }
        return self.map_details(self.get_data("movie/%s" % movie_id, params),
                                "movie")

    def get_movieset_details(self, movieset_id):
        """get all moviesetdetails"""
        details = {"art": {}}
        params = {"language": KODI_LANGUAGE}
        result = self.get_data("collection/%s" % movieset_id, params)
        if result:
            details["title"] = result["name"]
            details["plot"] = result["overview"]
            details["tmdb_id"] = result["id"]
            details["art"][
                "poster"] = "https://image.tmdb.org/t/p/original%s" % result[
                    "poster_path"]
            details["art"][
                "fanart"] = "https://image.tmdb.org/t/p/original%s" % result[
                    "backdrop_path"]
            details["totalmovies"] = len(result["parts"])
        return details

    def get_tvshow_details(self, tvshow_id):
        """get all tvshowdetails"""
        params = {
            "append_to_response":
            "keywords,videos,external_ids,credits,images",
            "include_image_language": "%s,en" % KODI_LANGUAGE,
            "language": KODI_LANGUAGE
        }
        return self.map_details(self.get_data("tv/%s" % tvshow_id, params),
                                "tvshow")

    def get_videodetails_by_externalid(self, extid, extid_type):
        """get metadata by external ID (like imdbid)"""
        params = {"external_source": extid_type, "language": KODI_LANGUAGE}
        results = self.get_data("find/%s" % extid, params)
        if results and results["movie_results"]:
            return self.get_movie_details(results["movie_results"][0]["id"])
        elif results and results["tv_results"]:
            return self.get_tvshow_details(results["tv_results"][0]["id"])
        return {}

    def get_data(self, endpoint, params):
        """helper method to get data from tmdb json API"""
        if self.api_key:
            # addon provided or personal api key
            params["api_key"] = self.api_key
            rate_limit = None
            expiration = datetime.timedelta(days=7)
        else:
            # fallback api key (rate limited !)
            params["api_key"] = "80246691939720672db3fc71c74e0ef2"
            # without personal (or addon specific) api key = rate limiting and older info from cache
            rate_limit = ("themoviedb.org", 5)
            expiration = datetime.timedelta(days=60)
        if sys.version_info.major == 3:
            cachestr = "tmdb.%s" % list(params.values())
        else:
            cachestr = "tmdb.%s" % iter(params.values())
        cache = self.cache.get(cachestr)
        if cache:
            # data obtained from cache
            result = cache
        else:
            # no cache, grab data from API
            url = 'https://api.themoviedb.org/3/%s' % endpoint
            result = get_json(url, params, ratelimit=rate_limit)
            # make sure that we have a plot value (if localized value fails, fallback to english)
            if result and "language" in params and "overview" in result:
                if not result["overview"] and params["language"] != "en":
                    params["language"] = "en"
                    result2 = get_json(url, params)
                    if result2 and result2.get("overview"):
                        result = result2
            self.cache.set(url, result, expiration=expiration)
        return result

    def map_details(self, data, media_type):
        """helper method to map the details received from tmdb to kodi compatible formatting"""
        if not data:
            return {}
        details = {}
        details["tmdb_id"] = data["id"]
        details["rating"] = data["vote_average"]
        details["votes"] = data["vote_count"]
        details["rating.tmdb"] = data["vote_average"]
        details["votes.tmdb"] = data["vote_count"]
        details["popularity"] = data["popularity"]
        details["popularity.tmdb"] = data["popularity"]
        details["plot"] = data["overview"]
        details["genre"] = [item["name"] for item in data["genres"]]
        details["homepage"] = data["homepage"]
        details["status"] = data["status"]
        details["cast"] = []
        details["castandrole"] = []
        details["writer"] = []
        details["director"] = []
        details["media_type"] = media_type
        # cast
        if "credits" in data:
            if "cast" in data["credits"]:
                for cast_member in data["credits"]["cast"]:
                    cast_thumb = ""
                    if cast_member["profile_path"]:
                        cast_thumb = "https://image.tmdb.org/t/p/original%s" % cast_member[
                            "profile_path"]
                    details["cast"].append({
                        "name": cast_member["name"],
                        "role": cast_member["character"],
                        "thumbnail": cast_thumb
                    })
                    details["castandrole"].append(
                        (cast_member["name"], cast_member["character"]))
            # crew (including writers and directors)
            if "crew" in data["credits"]:
                for crew_member in data["credits"]["crew"]:
                    cast_thumb = ""
                    if crew_member["profile_path"]:
                        cast_thumb = "https://image.tmdb.org/t/p/original%s" % crew_member[
                            "profile_path"]
                    if crew_member["job"] in ["Author", "Writer"]:
                        details["writer"].append(crew_member["name"])
                    if crew_member["job"] in [
                            "Producer", "Executive Producer"
                    ]:
                        details["director"].append(crew_member["name"])
                    if crew_member["job"] in [
                            "Producer", "Executive Producer", "Author",
                            "Writer"
                    ]:
                        details["cast"].append({
                            "name": crew_member["name"],
                            "role": crew_member["job"],
                            "thumbnail": cast_thumb
                        })
        # artwork
        details["art"] = {}
        if data.get("images"):
            if data["images"].get("backdrops"):
                fanarts = self.get_best_images(data["images"]["backdrops"])
                details["art"]["fanarts"] = fanarts
                details["art"]["fanart"] = fanarts[0] if fanarts else ""
            if data["images"].get("posters"):
                posters = self.get_best_images(data["images"]["posters"])
                details["art"]["posters"] = posters
                details["art"]["poster"] = posters[0] if posters else ""
        if not details["art"].get("poster") and data.get("poster_path"):
            details["art"][
                "poster"] = "https://image.tmdb.org/t/p/original%s" % data[
                    "poster_path"]
        if not details["art"].get("fanart") and data.get("backdrop_path"):
            details["art"][
                "fanart"] = "https://image.tmdb.org/t/p/original%s" % data[
                    "backdrop_path"]
        # movies only
        if media_type == "movie":
            details["title"] = data["title"]
            details["originaltitle"] = data["original_title"]
            if data["belongs_to_collection"]:
                details["set"] = data["belongs_to_collection"].get("name", "")
            if data.get("release_date"):
                details["premiered"] = data["release_date"]
                details["year"] = try_parse_int(
                    data["release_date"].split("-")[0])
            details["tagline"] = data["tagline"]
            if data["runtime"]:
                details["runtime"] = data["runtime"] * 60
            details["imdbnumber"] = data["imdb_id"]
            details["budget"] = data["budget"]
            details["budget.formatted"] = int_with_commas(data["budget"])
            details["revenue"] = data["revenue"]
            details["revenue.formatted"] = int_with_commas(data["revenue"])
            if data.get("production_companies"):
                details["studio"] = [
                    item["name"] for item in data["production_companies"]
                ]
            if data.get("production_countries"):
                details["country"] = [
                    item["name"] for item in data["production_countries"]
                ]
            if data.get("keywords"):
                details["tag"] = [
                    item["name"] for item in data["keywords"]["keywords"]
                ]
        # tvshows only
        if media_type == "tvshow":
            details["title"] = data["name"]
            details["originaltitle"] = data["original_name"]
            if data.get("created_by"):
                details["director"] += [
                    item["name"] for item in data["created_by"]
                ]
            if data.get("episode_run_time"):
                details["runtime"] = data["episode_run_time"][0] * 60
            if data.get("first_air_date"):
                details["premiered"] = data["first_air_date"]
                details["year"] = try_parse_int(
                    data["first_air_date"].split("-")[0])
            if "last_air_date" in data:
                details["lastaired"] = data["last_air_date"]
            if data.get("networks"):
                details["studio"] = [item["name"] for item in data["networks"]]
            if "origin_country" in data:
                details["country"] = data["origin_country"]
            if "number_of_seasons" in data:
                details["Seasons"] = data["number_of_seasons"]
            if "number_of_episodes" in data:
                details["Episodes"] = data["number_of_episodes"]
            if data.get("seasons"):
                tmdboverviewdetails = data["seasons"]
                seasons = []
                for count, item in enumerate(tmdboverviewdetails):
                    seasons.append(item["overview"])
                    details["seasons.formatted.%s" %
                            count] = "%s %s[CR]%s[CR]" % (item["name"],
                                                          item["air_date"],
                                                          item["overview"])
                details["seasons.formatted"] = "[CR]".join(seasons)
            if data.get("external_ids"):
                details["imdbnumber"] = data["external_ids"].get("imdb_id", "")
                details["tvdb_id"] = data["external_ids"].get("tvdb_id", "")
            if "results" in data["keywords"]:
                details["tag"] = [
                    item["name"] for item in data["keywords"]["results"]
                ]
        # trailer
        for video in data["videos"]["results"]:
            if video["site"] == "YouTube" and video["type"] == "Trailer":
                details[
                    "trailer"] = 'plugin://plugin.video.youtube/?action=play_video&videoid=%s' % video[
                        "key"]
                break
        return details

    @staticmethod
    def get_best_images(images):
        """get the best 5 images based on number of likes and the language"""
        for image in images:
            score = 0
            score += image["vote_count"]
            score += image["vote_average"] * 10
            score += image["height"]
            if "iso_639_1" in image:
                if image["iso_639_1"] == KODI_LANGUAGE:
                    score += 1000
            image["score"] = score
            if not image["file_path"].startswith("https"):
                image[
                    "file_path"] = "https://image.tmdb.org/t/p/original%s" % image[
                        "file_path"]
        images = sorted(images, key=itemgetter("score"), reverse=True)
        return [image["file_path"] for image in images]

    @staticmethod
    def select_best_match(results,
                          prefyear="",
                          preftype="",
                          preftitle="",
                          manual_select=False):
        """helper to select best match or let the user manually select the best result from the search"""
        details = {}
        # score results if one or more preferences are given
        if results and (prefyear or preftype or preftitle):
            newdata = []
            preftitle = preftitle.lower()
            for item in results:
                item["score"] = 0
                itemtitle = item["title"] if item.get(
                    "title") else item["name"]
                itemtitle = itemtitle.lower()
                itemorgtitle = item["original_title"] if item.get(
                    "original_title") else item["original_name"]
                itemorgtitle = itemorgtitle.lower()

                # high score if year matches
                if prefyear:
                    if item.get("first_air_date"
                                ) and prefyear in item["first_air_date"]:
                        item["score"] += 800  # matches preferred year
                    if item.get("release_date"
                                ) and prefyear in item["release_date"]:
                        item["score"] += 800  # matches preferred year

                # find exact match on title
                if preftitle and preftitle == itemtitle:
                    item["score"] += 1000  # exact match!
                if preftitle and preftitle == itemorgtitle:
                    item["score"] += 1000  # exact match!

                # match title by replacing some characters
                if preftitle and get_compare_string(
                        preftitle) == get_compare_string(itemtitle):
                    item["score"] += 750
                if preftitle and get_compare_string(
                        preftitle) == get_compare_string(itemorgtitle):
                    item["score"] += 750

                # add SequenceMatcher score to the results
                if preftitle:
                    stringmatchscore = SM(
                        None, preftitle, itemtitle).ratio() + SM(
                            None, preftitle, itemorgtitle).ratio()
                    if stringmatchscore > 1.6:
                        item["score"] += stringmatchscore * 250

                # higher score if result ALSO matches our preferred type or native language
                # (only when we already have a score)
                if item["score"]:
                    if preftype and (item["media_type"] in preftype) or (
                            preftype in item["media_type"]):
                        item["score"] += 250  # matches preferred type
                    if item["original_language"] == KODI_LANGUAGE:
                        item["score"] += 500  # native language!
                    if KODI_LANGUAGE.upper() in item.get("origin_country", []):
                        item["score"] += 500  # native language!
                    if KODI_LANGUAGE in item.get("languages", []):
                        item["score"] += 500  # native language!

                if item["score"] > 500 or manual_select:
                    newdata.append(item)
            results = sorted(newdata, key=itemgetter("score"), reverse=True)

        if results and manual_select:
            # show selectdialog to manually select the item
            results_list = []
            for item in results:
                title = item["name"] if "name" in item else item["title"]
                if item.get("premiered"):
                    year = item["premiered"].split("-")[0]
                else:
                    year = item.get("first_air_date", "").split("-")[0]
                if item["poster_path"]:
                    thumb = "https://image.tmdb.org/t/p/original%s" % item[
                        "poster_path"]
                else:
                    thumb = ""
                label = "%s (%s) - %s" % (title, year, item["media_type"])
                listitem = xbmcgui.ListItem(label=label,
                                            label2=item["overview"])
                listitem.setArt({'icon': thumb})
                results_list.append(listitem)
            if manual_select and results_list:
                dialog = DialogSelect("DialogSelect.xml",
                                      "",
                                      listing=results_list,
                                      window_title="%s - TMDB" %
                                      xbmc.getLocalizedString(283))
                dialog.doModal()
                selected_item = dialog.result
                del dialog
                if selected_item != -1:
                    details = results[selected_item]
                else:
                    results = []

        if not details and results:
            # just grab the first item as best match
            details = results[0]
        return details
Exemple #16
0
class Locast(object):
    def __init__(self, sysARG=sys.argv):
        log('__init__, sysARG = %s' % (sysARG))
        self.sysARG = sysARG
        self.cache = SimpleCache()
        self.token = (REAL_SETTINGS.getSetting('User_Token') or None)
        self.lastDMA = 0
        self.now = datetime.datetime.now()
        self.lat, self.lon = self.setRegion()
        if self.login(REAL_SETTINGS.getSetting('User_Email'),
                      REAL_SETTINGS.getSetting('User_Password')) == False:
            sys.exit()
        else:
            self.city = self.getRegion()

    def reset(self):
        self.__init__()

    def buildMenu(self):
        MAIN_MENU = [(LANGUAGE(30003), (getLive, self.city)),
                     (LANGUAGE(49011), (getLiveFavs, self.city)),
                     (LANGUAGE(30004), (getChannels, self.city))]
        for item in MAIN_MENU:
            self.addDir(*item)

    def getStations(self, city, name='', opt=''):
        log("getStations, city = %s, opt = %s, name = %s" % (city, opt, name))
        stations = self.getEPG(city)
        for station in stations:
            if station['active'] == False: continue
            path = str(station['id'])
            thumb = (station.get('logoUrl', '')
                     or station.get('logo226Url', '') or ICON)
            listings = station['listings']
            label = (station.get('affiliateName', '')
                     or station.get('affiliate', '')
                     or station.get('callSign', '') or station.get('name', ''))
            stnum = re.sub('[^\d\.]+', '', label)
            stname = ''
            favorite = None
            if stnum:
                stname = re.compile('[^a-zA-Z]').sub('', label)
                stlabel = '%s| %s' % (stnum, stname)
                favorite = isFavorite(stnum)
            else:
                stlabel = label
            if opt in ['live', 'favorites']:
                self.buildListings(listings, label, thumb, path, opt)
            elif opt == 'lineup' and (name.lower() == stlabel.lower()):
                self.buildListings(listings, label, thumb, path, opt)
            elif opt == 'play' and (name.lower() == station.get('name',
                                                                '').lower()):
                self.buildListings(listings, label, thumb, path, opt)
            elif opt == 'channels':
                chnum = re.sub('[^\d\.]+', '', label)
                if chnum:
                    chname = re.compile('[^a-zA-Z]').sub('', label)
                    label = '%s| %s' % (chnum, chname)
                else:
                    label = chname
                self.addDir(label,
                            (getLineup, city, urllib.parse.quote(label)),
                            infoList={
                                "favorite": favorite,
                                "chnum": stnum,
                                "chname": stname,
                                "mediatype": "video",
                                "label": label,
                                "title": label
                            },
                            infoArt={
                                "thumb": thumb,
                                "poster": thumb,
                                "fanart": FANART,
                                "icon": ICON,
                                "logo": ICON
                            })
            else:
                continue

    def buildListings(self, listings, chname, chlogo, path, opt=''):
        log('buildListings, chname = %s, opt = %s' % (chname, opt))
        now = datetime.datetime.now()
        for listing in listings:
            try:
                starttime = datetime.datetime.fromtimestamp(
                    int(str(listing['startTime'])[:-3]))
            except:
                continue
            duration = listing.get('duration', 0)
            endtime = starttime + datetime.timedelta(seconds=duration)
            label = listing['title']
            favorite = None
            chnum = -1
            # if listing['isNew']: label = '*%s'%label
            try:
                aired = datetime.datetime.fromtimestamp(
                    int(str(listing['airdate'])[:-3]))
            except:
                aired = starttime
            try:
                type = {'Series': 'episode'}[listing.get('showType', 'Series')]
            except:
                type = 'video'
            plot = (listing.get('description', '')
                    or listing.get('shortDescription', '') or label)
            if now > endtime: continue
            elif opt in ['live', 'favorites', 'play']:
                chnum = re.sub('[^\d\.]+', '', chname)
                if chnum:
                    favorite = isFavorite(chnum)
                    chname = re.compile('[^a-zA-Z]').sub('', chname)
                    chname = '%s| %s' % (chnum, chname)
                    label = '%s : [B] %s[/B]' % (chname, label)
                else:
                    label = chname
                if opt == 'favorites' and not favorite: continue
            elif opt == 'lineup':
                if now >= starttime and now < endtime:
                    label = '%s - [B]%s[/B]' % (
                        starttime.strftime('%I:%M %p').lstrip('0'), label)
                else:
                    label = '%s - %s' % (
                        starttime.strftime('%I:%M %p').lstrip('0'), label)
                    path = 'NEXT_SHOW'

            thumb = (listing.get('preferredImage', '') or chlogo)
            infoLabels = {
                "favorite": favorite,
                "chnum": chnum,
                "chname": chname,
                "mediatype": type,
                "label": label,
                "title": label,
                'duration': duration,
                'plot': plot,
                'genre': listing.get('genres', []),
                "aired": aired.strftime('%Y-%m-%d')
            }
            infoArt = {
                "thumb": thumb,
                "poster": thumb,
                "fanart": FANART,
                "icon": chlogo,
                "logo": chlogo
            }
            infoVideo = {
            }  #todo added more meta from listings, ie mpaa, isNew, video/audio codec
            infoAudio = {
            }  #todo added more meta from listings, ie mpaa, isNew, video/audio codec
            if type == 'episode':
                infoLabels['tvshowtitle'] = listing.get('title', label)
                if listing.get('seasonNumber', None):
                    infoLabels['season'] = listing.get('seasonNumber', 0)
                    infoLabels['episode'] = listing.get('episodeNumber', 0)
                    seaep = '%sx%s' % (
                        str(listing.get('seasonNumber', '')).zfill(2),
                        str(listing.get('episodeNumber', '')).zfill(2))
                    label = '%s - %s %s' % (label, seaep,
                                            listing.get('episodeTitle', ''))
                else:
                    label = '%s %s' % (label, listing.get('episodeTitle', ''))
                infoLabels['title'] = label
                infoLabels['label'] = label
            if opt in ['live', 'favorites']:
                if now >= starttime and now < endtime:
                    return self.addLink(label, (playChannel, path),
                                        infoLabels,
                                        infoArt,
                                        infoVideo,
                                        infoAudio,
                                        total=len(listings))
                else:
                    continue
            if opt == 'play':
                if starttime <= now and endtime > now:
                    infoLabels['duration'] = ((endtime) - now).seconds
                self.addPlaylist(label, path, infoLabels, infoArt, infoVideo,
                                 infoAudio)
            else:
                self.addLink(label, (playChannel, path),
                             infoLabels,
                             infoArt,
                             infoVideo,
                             infoAudio,
                             total=len(listings))

    def setRegion(self):
        try:
            geo_data = json.load(urllib.request.urlopen(GEO_URL))
        except:
            geo_data = {'lat': 0.0, 'lon': 0.0}
            okDialog(LANGUAGE(30025) % (GEO_URL))
        return float('{0:.7f}'.format(geo_data['lat'])), float(
            '{0:.7f}'.format(geo_data['lon']))

    def getURL(self,
               url,
               param={},
               header={'Content-Type': 'application/json'},
               life=datetime.timedelta(minutes=5)):
        log('getURL, url = %s, header = %s' % (url, header))
        cacheresponse = self.cache.get(ADDON_NAME + '.getURL, url = %s.%s.%s' %
                                       (url, param, header))
        if not cacheresponse:
            try:
                req = requests.get(url, param, headers=header)
                try:
                    cacheresponse = req.json()
                except:
                    return {}
                req.close()
                self.cache.set(ADDON_NAME + '.getURL, url = %s.%s.%s' %
                               (url, param, header),
                               json.dumps(cacheresponse),
                               expiration=life)
                return cacheresponse
            except Exception as e:
                log("getURL, Failed! %s" % (e), xbmc.LOGERROR)
                notificationDialog(LANGUAGE(30001))
                return {}
        else:
            return json.loads(cacheresponse)

    def postURL(self,
                url,
                param={},
                header={'Content-Type': 'application/json'},
                life=datetime.timedelta(minutes=5)):
        log('postURL, url = %s, header = %s' % (url, header))
        cacheresponse = self.cache.get(ADDON_NAME +
                                       '.postURL, url = %s.%s.%s' %
                                       (url, param, header))
        cacheresponse = None
        if not cacheresponse:
            try:
                req = requests.post(url, param, headers=header)
                cacheresponse = req.json()
                req.close()
                self.cache.set(ADDON_NAME + '.postURL, url = %s.%s.%s' %
                               (url, param, header),
                               json.dumps(cacheresponse),
                               expiration=life)
                return cacheresponse
            except Exception as e:
                log("postURL, Failed! %s" % (e), xbmc.LOGERROR)
                notificationDialog(LANGUAGE(30001))
                return {}
        else:
            return json.loads(cacheresponse)

    def buildHeader(self):
        header_dict = {}
        header_dict[
            'Accept'] = 'application/json, text/javascript, */*; q=0.01'
        header_dict['Content-Type'] = 'application/json'
        header_dict['Connection'] = 'keep-alive'
        header_dict['Origin'] = BASE_URL
        header_dict['Referer'] = BASE_URL
        header_dict['Authorization'] = "Bearer %s" % self.token
        header_dict[
            'User-Agent'] = 'Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36'
        return header_dict

    def chkUser(self, user):
        state = False
        try:
            self.userdata = self.getURL(BASE_API + '/user/me',
                                        header=self.buildHeader())
        except:
            self.userdata = {}
        if self.userdata.get('email', '').lower() == user.lower(): state = True
        log('chkUser = %s' % (state))
        return state

    def login(self, user, password):
        log('login')
        if len(user) > 0:
            if self.chkUser(user): return True
            data = self.postURL(BASE_API + '/user/login',
                                param='{"username":"******","password":"******"}')
            '''{u'token': u''}'''
            if data and 'token' in data:
                self.token = data['token']
                if REAL_SETTINGS.getSetting('User_Token') != self.token:
                    REAL_SETTINGS.setSetting('User_Token', self.token)
                if self.chkUser(user):
                    try:
                        REAL_SETTINGS.setSetting(
                            'User_Donate',
                            str(self.userdata.get('didDonate', 'False')))
                        REAL_SETTINGS.setSetting(
                            'User_totalDonations',
                            str(self.userdata.get('totalDonations', '0')))
                        REAL_SETTINGS.setSetting(
                            'User_LastLogin',
                            datetime.datetime.fromtimestamp(
                                float(
                                    str(self.userdata.get('lastlogin',
                                                          '')).rstrip('L')) /
                                1000).strftime("%Y-%m-%d %I:%M %p"))
                        REAL_SETTINGS.setSetting(
                            'User_DonateExpire',
                            datetime.datetime.fromtimestamp(
                                float(
                                    str(self.userdata.get(
                                        'donationExpire', '')).rstrip('L')) /
                                1000).strftime("%Y-%m-%d %I:%M %p"))
                    except:
                        pass
                    self.lastDMA = self.userdata.get('lastDmaUsed', '')
                    notificationDialog(
                        LANGUAGE(30021) % (self.userdata.get('name', '')))
                    return True
            elif data.get('message'):
                notificationDialog(data.get('message'))
            else:
                notificationDialog(LANGUAGE(30017))
        else:
            #firstrun wizard
            if yesnoDialog(LANGUAGE(30008),
                           nolabel=LANGUAGE(30009),
                           yeslabel=LANGUAGE(30010)):
                user = inputDialog(LANGUAGE(30006))
                password = inputDialog(LANGUAGE(30007),
                                       opt=xbmcgui.ALPHANUM_HIDE_INPUT)
                REAL_SETTINGS.setSetting('User_Email', user)
                REAL_SETTINGS.setSetting('User_Password', password)
                xbmc.sleep(2000)  #wait for setsetting write
                return self.reset()
            else:
                okDialog(LANGUAGE(30012))
        return False

    def genClientID(self):
        return urllib.parse.quote(''.join(
            random.choice(string.ascii_uppercase + string.ascii_lowercase +
                          string.digits + '=' + '+') for _ in range(24)))

    def getEPG(self, city):
        log("getEPG, city = %s" % city)
        '''[{"id":104,"dma":501,"name":"WCBSDT (WCBS-DT)","callSign":"WCBS","logoUrl":"https://fans.tmsimg.com/h5/NowShowing/28711/s28711_h5_aa.png","active":true,"affiliate":"CBS","affiliateName":"CBS",
             "listings":[{"stationId":104,"startTime":1535410800000,"duration":1800,"isNew":true,"audioProperties":"CC, HD 1080i, HDTV, New, Stereo","videoProperties":"CC, HD 1080i, HDTV, New, Stereo","programId":"EP000191906491","title":"Inside Edition","description":"Primary stories and alternative news.","entityType":"Episode","airdate":1535328000000,"genres":"Newsmagazine","showType":"Series"}]}'''
        now = ('{0:.23s}{1:s}'.format(
            datetime.datetime.now().strftime('%Y-%m-%dT00:00:00'), '-05:00'))
        return self.getURL(BASE_API + '/watch/epg/%s' % (city),
                           param={'start_time': urllib.parse.quote(now)},
                           header=self.buildHeader(),
                           life=datetime.timedelta(minutes=45))

    def getAll(self):
        return self.getURL(BASE_API + '/dma', header=self.buildHeader())

    def getCity(self):
        log("getCity")
        '''{u'active': True, u'DMA': u'501', u'small_url': u'https://s3.us-east-2.amazonaws.com/static.locastnet.org/cities/new-york.jpg', u'large_url': u'https://s3.us-east-2.amazonaws.com/static.locastnet.org/cities/background/new-york.jpg', u'name': u'New York'}'''
        try:
            city = self.getURL(BASE_API + '/watch/dma/%s/%s' %
                               (self.lat, self.lon),
                               header=self.buildHeader())
            if city and 'DMA' not in city: okDisable(city.get('message'))
            else:
                REAL_SETTINGS.setSetting('User_City', str(city['name']))
                return city
        except:
            okDisable(LANGUAGE(30013))

    def getRegion(self):
        log("getRegion")
        try:
            return self.getCity()['DMA']
        except:
            return self.lastDMA if self.lastDMA > 0 else sys.exit()

    def poolList(self, method, items=None, args=None, chunk=25):
        log("poolList")
        results = []
        if ENABLE_POOL:
            pool = ThreadPool(CORES)
            if args is not None:
                results = pool.map(method, zip(items, repeat(args)))
            elif items:
                results = pool.map(method, items)  #, chunksize=chunk)
            pool.close()
            pool.join()
        else:
            if args is not None:
                results = [method((item, args)) for item in items]
            elif items:
                results = [method(item) for item in items]
        return filter(None, results)

    def getChannels(self):
        log('getChannels')
        # https://github.com/add-ons/service.iptv.manager/wiki/JSON-STREAMS-format
        stations = self.getEPG(self.getRegion())
        return list(self.poolList(self.buildStation, stations, 'channel'))

    def getGuide(self):
        log('getGuide')
        # https://github.com/add-ons/service.iptv.manager/wiki/JSON-EPG-format
        stations = self.getEPG(self.getRegion())
        return {
            k: v
            for x in self.poolList(self.buildStation, stations, 'programmes')
            for k, v in x.items()
        }

    def buildStation(self, data):
        station, opt = data
        if station['active'] == False: return None
        label = (station.get('affiliateName', '')
                 or station.get('affiliate', '')
                 or station.get('callSign', '') or station.get('name', ''))
        stnum = re.sub('[^\d\.]+', '', label)
        stname = re.compile('[^a-zA-Z]').sub('', label)
        favorite = isFavorite(stnum)
        channel = {
            "name":
            stname,
            "stream":
            "plugin://%s/play/pvr/%s" % (ADDON_ID, station['id']),
            "id":
            "%s.%s@%s" % (stnum, slugify(stname), slugify(ADDON_NAME)),
            "logo": (station.get('logoUrl', '')
                     or station.get('logo226Url', '') or ICON),
            "preset":
            stnum,
            "group":
            ADDON_NAME,
            "radio":
            False
        }  #,
        # "kodiprops":{"inputstream":"inputstream.adaptive",
        # "inputstream.adaptive.manifest_type":"hls",
        # "inputstream.adaptive.media_renewal_url":"plugin://%s/play/pvr/%s"%(ADDON_ID,station['id']),
        # "inputstream.adaptive.media_renewal_time":"900"}}
        if favorite: channel['group'] = ';'.join([LANGUAGE(49012), ADDON_NAME])
        if REAL_SETTINGS.getSettingBool('Build_Favorites') and not favorite:
            return None
        elif opt == 'channel':
            return channel
        else:
            programmes = {channel['id']: []}
            listings = station.get('listings', [])
            for listing in listings:
                try:
                    starttime = datetime.datetime.fromtimestamp(
                        int(str(listing['startTime'])[:-3])) + UTC_OFFSET
                except:
                    continue
                try:
                    aired = datetime.datetime.fromtimestamp(
                        int(str(listing['airdate'])[:-3]))
                except:
                    aired = starttime
                program = {
                    "start":
                    starttime.strftime(DTFORMAT),
                    "stop":
                    (starttime +
                     datetime.timedelta(seconds=listing.get('duration', 0))
                     ).strftime(DTFORMAT),
                    "title":
                    listing.get('title', channel['name']),
                    "description": (listing.get('description', '')
                                    or listing.get('shortDescription', '')
                                    or xbmc.getLocalizedString(161)),
                    "subtitle":
                    listing.get('episodeTitle', ''),
                    "episode":
                    "S%sE%s" % (str(listing.get('seasonNumber', 0)).zfill(2),
                                str(listing.get('episodeNumber', 0)).zfill(2)),
                    "genre":
                    listing.get('genres', ""),
                    "image": (listing.get('preferredImage', '')
                              or channel['logo']),
                    "date":
                    aired.strftime('%Y-%m-%d'),
                    "credits":
                    "",
                    "stream":
                    ""
                }
                programmes[channel['id']].append(program)
            return programmes

    def resolveURL(self, id, opt):
        log('resolveURL, id = %s, opt = %s' % (id, opt))
        self.listitems = []
        self.playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
        self.playlist.clear()
        '''{u'dma': 501, u'streamUrl': u'https://acdn.locastnet.org/variant/E27GYubZwfUs.m3u8', u'name': u'WNBCDT2', u'sequence': 50, u'stationId': u'44936', u'callSign': u'4.2 COZITV', u'logo226Url': u'https://fans.tmsimg.com/assets/s78851_h3_aa.png', u'logoUrl': u'https://fans.tmsimg.com/assets/s78851_h3_aa.png', u'active': True, u'id': 1574529688491L}'''
        data = self.getURL(BASE_API + '/watch/station/%s/%s/%s' %
                           (id, self.lat, self.lon),
                           header=self.buildHeader(),
                           life=datetime.timedelta(seconds=5))
        url = data.get('streamUrl')
        liz = xbmcgui.ListItem(data.get('name'), path=url)
        liz.setProperty('IsPlayable', 'true')
        liz.setProperty('IsInternetStream', 'true')
        if opt != 'pvr':
            self.getStations(data.get('dma'),
                             name=data.get('name'),
                             opt='play')
            [
                self.playlist.add(url, lz, idx)
                for idx, lz in enumerate(self.listitems)
            ]
            liz = self.listitems.pop(0)
            liz.setPath(path=url)
        return liz

    def playLive(self, id, opt='live'):
        log('playLive, id = %s, opt = %s' % (id, opt))
        if id == 'NEXT_SHOW':
            found = False
            liz = xbmcgui.ListItem(LANGUAGE(30029))
            notificationDialog(LANGUAGE(30029), time=4000)
        else:
            found = True
            liz = self.resolveURL(id, opt)
            if opt != 'pvr' and 'm3u8' in liz.getPath().lower(
            ) and inputstreamhelper.Helper('hls').check_inputstream():
                liz.setProperty('inputstream', 'inputstream.adaptive')
                liz.setProperty('inputstream.adaptive.manifest_type', 'hls')
                # liz.setProperty('inputstream.adaptive.media_renewal_url', 'plugin://%s/play/%s/%s'%(ADDON_ID,opt,id))
                # liz.setProperty('inputstream.adaptive.media_renewal_time', '900')
                #todo debug pvr (IPTV Simple) not playing with inputstream! temp. use kodiprops in m3u?
        xbmcplugin.setResolvedUrl(ROUTER.handle, found, liz)

    def addPlaylist(self,
                    name,
                    path='',
                    infoList={},
                    infoArt={},
                    infoVideo={},
                    infoAudio={},
                    infoType='video'):
        log('addPlaylist, name = %s' % name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        liz.setProperty('IsInternetStream', 'true')
        if infoList: liz.setInfo(type=infoType, infoLabels=infoList)
        else:
            liz.setInfo(type=infoType,
                        infoLabels={
                            "mediatype": infoType,
                            "label": name,
                            "title": name
                        })
        if infoArt: liz.setArt(infoArt)
        else: liz.setArt({'thumb': ICON, 'fanart': FANART})
        if infoVideo: liz.addStreamInfo('video', infoVideo)
        if infoAudio: liz.addStreamInfo('audio', infoAudio)
        self.listitems.append(liz)

    def addLink(self,
                name,
                uri=(''),
                infoList={},
                infoArt={},
                infoVideo={},
                infoAudio={},
                infoType='video',
                total=0):
        log('addLink, name = %s' % name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        liz.setProperty('IsInternetStream', 'true')
        if infoList: liz.setInfo(type=infoType, infoLabels=infoList)
        else:
            liz.setInfo(type=infoType,
                        infoLabels={
                            "mediatype": infoType,
                            "label": name,
                            "title": name
                        })
        if infoArt: liz.setArt(infoArt)
        else: liz.setArt({'thumb': ICON, 'fanart': FANART})
        if infoVideo: liz.addStreamInfo('video', infoVideo)
        if infoAudio: liz.addStreamInfo('audio', infoAudio)
        if infoList.get('favorite', None) is not None:
            liz = self.addContextMenu(liz, infoList)
        xbmcplugin.addDirectoryItem(ROUTER.handle,
                                    ROUTER.url_for(*uri),
                                    liz,
                                    isFolder=False,
                                    totalItems=total)

    def addDir(self,
               name,
               uri=(''),
               infoList={},
               infoArt={},
               infoType='video'):
        log('addDir, name = %s' % name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList: liz.setInfo(type=infoType, infoLabels=infoList)
        else:
            liz.setInfo(type=infoType,
                        infoLabels={
                            "mediatype": infoType,
                            "label": name,
                            "title": name
                        })
        if infoArt: liz.setArt(infoArt)
        else: liz.setArt({'thumb': ICON, 'fanart': FANART})
        if infoList.get('favorite', None) is not None:
            liz = self.addContextMenu(liz, infoList)
        xbmcplugin.addDirectoryItem(ROUTER.handle,
                                    ROUTER.url_for(*uri),
                                    liz,
                                    isFolder=True)

    def addContextMenu(self, liz, infoList={}):
        log('addContextMenu')
        if infoList['favorite']:
            liz.addContextMenuItems([
                (LANGUAGE(49010),
                 'RunScript(special://home/addons/%s/favorites.py, %s)' %
                 (ADDON_ID,
                  urllib.parse.quote(
                      json.dumps({
                          "chnum": infoList.pop('chnum'),
                          "chname": infoList.pop('chname'),
                          "mode": "del"
                      }))))
            ])
        else:
            liz.addContextMenuItems([
                (LANGUAGE(49009),
                 'RunScript(special://home/addons/%s/favorites.py, %s)' %
                 (ADDON_ID,
                  urllib.parse.quote(
                      json.dumps({
                          "chnum": infoList.pop('chnum'),
                          "chname": infoList.pop('chname'),
                          "mode": "add"
                      }))))
            ])
        return liz

    def run(self):
        ROUTER.run()
        xbmcplugin.setContent(ROUTER.handle, CONTENT_TYPE)
        xbmcplugin.addSortMethod(ROUTER.handle,
                                 xbmcplugin.SORT_METHOD_UNSORTED)
        xbmcplugin.addSortMethod(ROUTER.handle, xbmcplugin.SORT_METHOD_NONE)
        xbmcplugin.addSortMethod(ROUTER.handle, xbmcplugin.SORT_METHOD_LABEL)
        xbmcplugin.addSortMethod(ROUTER.handle, xbmcplugin.SORT_METHOD_TITLE)
        xbmcplugin.endOfDirectory(ROUTER.handle, cacheToDisc=DISC_CACHE)
class ListItemMonitor(threading.Thread):
    '''Our main class monitoring the kodi listitems and providing additional information'''
    event = None
    exit = False
    delayed_task_interval = 1795
    listitem_details = {}
    all_window_props = []
    cur_listitem = ""
    last_folder = ""
    last_listitem = ""
    foldercontent = {}
    screensaver_setting = None
    screensaver_disabled = False
    lookup_busy = {}
    enable_extendedart = False
    enable_musicart = False
    enable_animatedart = False
    enable_extrafanart = False
    enable_pvrart = False
    enable_forcedviews = False

    def __init__(self, *args, **kwargs):
        self.cache = SimpleCache()
        self.artutils = kwargs.get("artutils")
        self.win = kwargs.get("win")
        self.kodimonitor = kwargs.get("monitor")
        self.event = threading.Event()
        threading.Thread.__init__(self, *args)

    def stop(self):
        '''called when the thread has to stop working'''
        log_msg("ListItemMonitor - stop called")
        self.exit = True
        self.event.set()

    def run(self):
        '''our main loop monitoring the listitem and folderpath changes'''
        log_msg("ListItemMonitor - started")
        self.get_settings()

        while not self.exit:

            # check screensaver and OSD
            self.check_screensaver()
            self.check_osd()

            # do some background stuff every 30 minutes
            if (self.delayed_task_interval >= 1800) and not self.exit:
                thread.start_new_thread(self.do_background_work, ())
                self.delayed_task_interval = 0

            # skip if any of the artwork context menus is opened
            if self.win.getProperty("SkinHelper.Artwork.ManualLookup"):
                self.reset_win_props()
                self.last_listitem = ""
                self.listitem_details = {}
                self.kodimonitor.waitForAbort(3)
                self.delayed_task_interval += 3

            # skip when modal dialogs are opened (e.g. textviewer in musicinfo dialog) or container scrolling
            elif xbmc.getCondVisibility(
                    "Window.IsActive(DialogSelect.xml) | Window.IsActive(progressdialog) | "
                    "Window.IsActive(contextmenu) | Window.IsActive(busydialog) | Container.Scrolling"):
                self.kodimonitor.waitForAbort(2)
                self.delayed_task_interval += 2
                self.last_listitem = ""

            # media window is opened or widgetcontainer set - start listitem monitoring!
            elif xbmc.getCondVisibility("Window.IsMedia | "
                                        "!IsEmpty(Window(Home).Property(SkinHelper.WidgetContainer))"):
                self.monitor_listitem()
                self.kodimonitor.waitForAbort(0.15)
                self.delayed_task_interval += 0.15

            # flush any remaining window properties
            elif self.all_window_props:
                self.reset_win_props()
                self.win.clearProperty("SkinHelper.ContentHeader")
                self.win.clearProperty("contenttype")
                self.win.clearProperty("curlistitem")
                self.last_listitem = ""

            # other window active - do nothing
            else:
                self.kodimonitor.waitForAbort(1)
                self.delayed_task_interval += 1

    def get_settings(self):
        '''collect our skin settings that control the monitoring'''
        self.enable_extendedart = xbmc.getCondVisibility("Skin.HasSetting(SkinHelper.EnableExtendedArt)") == 1
        self.enable_musicart = xbmc.getCondVisibility("Skin.HasSetting(SkinHelper.EnableMusicArt)") == 1
        self.enable_animatedart = xbmc.getCondVisibility("Skin.HasSetting(SkinHelper.EnableAnimatedPosters)") == 1
        self.enable_extrafanart = xbmc.getCondVisibility("Skin.HasSetting(SkinHelper.EnableExtraFanart)") == 1
        self.enable_pvrart = xbmc.getCondVisibility(
            "Skin.HasSetting(SkinHelper.EnablePVRThumbs) + PVR.HasTVChannels") == 1
        self.enable_forcedviews = xbmc.getCondVisibility("Skin.HasSetting(SkinHelper.ForcedViews.Enabled)") == 1
        studiologos_path = xbmc.getInfoLabel("Skin.String(SkinHelper.StudioLogos.Path)").decode("utf-8")
        if studiologos_path != self.artutils.studiologos_path:
            self.listitem_details = {}
            self.artutils.studiologos_path = studiologos_path
        # set additional window props to control contextmenus as using the skinsetting gives unreliable results
        for skinsetting in ["EnableAnimatedPosters", "EnableMusicArt", "EnablePVRThumbs"]:
            if xbmc.getCondVisibility("Skin.HasSetting(SkinHelper.%s)" % skinsetting):
                self.win.setProperty("SkinHelper.%s" % skinsetting, "enabled")
            else:
                self.win.clearProperty("SkinHelper.%s" % skinsetting)

    def monitor_listitem(self):
        '''Monitor listitem details'''

        cur_folder, cont_prefix = self.get_folderandprefix()
        li_label = xbmc.getInfoLabel("%sListItem.Label" % cont_prefix).decode('utf-8')

        # perform actions if the container path has changed
        if cur_folder != self.last_folder:
            self.reset_win_props()
            self.get_settings()
            self.last_folder = cur_folder
            content_type = self.get_content_type(cur_folder, li_label, cont_prefix)
            # additional actions to perform when we have a valid contenttype and no widget container
            if not cont_prefix and content_type:
                self.set_forcedview(content_type)
                self.set_content_header(content_type)
        else:
            content_type = self.get_content_type(cur_folder, li_label, cont_prefix)

        if self.exit:
            return

        # only perform actions when the listitem has actually changed
        li_title = xbmc.getInfoLabel("%sListItem.Title" % cont_prefix).decode('utf-8')
        li_dbid = xbmc.getInfoLabel(
            "$INFO[%sListItem.DBID]$INFO[%sListItem.Property(DBID)]" %
            (cont_prefix, cont_prefix)).decode('utf-8')
        cur_listitem = "%s--%s--%s--%s--%s" % (cur_folder, li_label, li_title, content_type, li_dbid)

        if cur_listitem and content_type and cur_listitem != self.last_listitem:
            self.last_listitem = cur_listitem
            # clear all window props first
            self.reset_win_props()
            self.set_win_prop(("curlistitem", cur_listitem))
            self.set_forcedview(content_type)
            if not li_label == "..":
                # set listitem details in background thread
                thread.start_new_thread(
                    self.set_listitem_details, (cur_listitem, content_type, cont_prefix))

    def get_folderandprefix(self):
        '''get the current folder and prefix'''
        cur_folder = ""
        cont_prefix = ""
        try:
            widget_container = self.win.getProperty("SkinHelper.WidgetContainer").decode('utf-8')
            if xbmc.getCondVisibility("Window.IsActive(movieinformation)"):
                cont_prefix = ""
                cur_folder = xbmc.getInfoLabel(
                    "movieinfo-$INFO[Container.FolderPath]"
                    "$INFO[Container.NumItems]"
                    "$INFO[Container.Content]").decode('utf-8')
            elif widget_container:
                cont_prefix = "Container(%s)." % widget_container
                cur_folder = xbmc.getInfoLabel(
                    "widget-%s-$INFO[Container(%s).NumItems]-$INFO[Container(%s).ListItemAbsolute(1).Label]" %
                    (widget_container, widget_container, widget_container)).decode('utf-8')
            else:
                cont_prefix = ""
                cur_folder = xbmc.getInfoLabel(
                    "$INFO[Container.FolderPath]$INFO[Container.NumItems]$INFO[Container.Content]").decode(
                    'utf-8')
        except Exception as exc:
            log_exception(__name__, exc)
            cur_folder = ""
            cont_prefix = ""
        return (cur_folder, cont_prefix)

    def get_content_type(self, cur_folder, li_label, cont_prefix):
        '''get contenttype for current folder'''
        content_type = ""
        if cur_folder in self.foldercontent:
            content_type = self.foldercontent[cur_folder]
        elif cur_folder and li_label:
            # always wait for the content_type because some listings can be slow
            for i in range(20):
                content_type = get_current_content_type(cont_prefix)
                if self.exit:
                    return ""
                if content_type:
                    break
                else:
                    xbmc.sleep(250)
            self.foldercontent[cur_folder] = content_type
            self.win.setProperty("contenttype", content_type)
        return content_type

    def check_screensaver(self):
        '''Allow user to disable screensaver on fullscreen music playback'''
        if xbmc.getCondVisibility(
                "Window.IsActive(visualisation) + Skin.HasSetting(SkinHelper.DisableScreenSaverOnFullScreenMusic)"):
            if not self.screensaver_disabled:
                # disable screensaver when fullscreen music active
                self.screensaver_setting = kodi_json('Settings.GetSettingValue', '{"setting":"screensaver.mode"}')
                kodi_json('Settings.SetSettingValue', {"setting": "screensaver.mode", "value": None})
                self.screensaver_disabled = True
                log_msg(
                    "Disabled screensaver while fullscreen music playback - previous setting: %s" %
                    self.screensaver_setting)
        elif self.screensaver_setting and self.screensaver_disabled:
            # enable screensaver again after fullscreen music playback was ended
            kodi_json('Settings.SetSettingValue', {"setting": "screensaver.mode", "value": self.screensaver_setting})
            self.screensaver_disabled = False
            log_msg("fullscreen music playback ended - restoring screensaver: %s" % self.screensaver_setting)

    @staticmethod
    def check_osd():
        '''Allow user to set a default close timeout for the OSD panels'''
        if xbmc.getCondVisibility("[Window.IsActive(videoosd) + Skin.String(SkinHelper.AutoCloseVideoOSD)] | "
                                  "[Window.IsActive(musicosd) + Skin.String(SkinHelper.AutoCloseMusicOSD)]"):
            if xbmc.getCondVisibility("Window.IsActive(videoosd)"):
                seconds = xbmc.getInfoLabel("Skin.String(SkinHelper.AutoCloseVideoOSD)")
                window = "videoosd"
            elif xbmc.getCondVisibility("Window.IsActive(musicosd)"):
                seconds = xbmc.getInfoLabel("Skin.String(SkinHelper.AutoCloseMusicOSD)")
                window = "musicosd"
            else:
                seconds = ""
            if seconds and seconds != "0":
                while xbmc.getCondVisibility("Window.IsActive(%s)" % window):
                    if xbmc.getCondVisibility("System.IdleTime(%s)" % seconds):
                        if xbmc.getCondVisibility("Window.IsActive(%s)" % window):
                            xbmc.executebuiltin("Dialog.Close(%s)" % window)
                    else:
                        xbmc.sleep(500)

    def set_listitem_details(self, cur_listitem, content_type, prefix):
        '''set the window properties based on the current listitem'''
        try:
            if cur_listitem in self.listitem_details:
                # data already in memory
                all_props = self.listitem_details[cur_listitem]
            else:
                # prefer listitem's contenttype over container's contenttype
                dbtype = xbmc.getInfoLabel("%sListItem.DBTYPE" % prefix)
                if not dbtype:
                    dbtype = xbmc.getInfoLabel("%sListItem.Property(DBTYPE)" % prefix)
                if dbtype:
                    content_type = dbtype + "s"

                # collect all details from listitem
                listitem = self.get_listitem_details(content_type, prefix)

                if prefix and cur_listitem == self.last_listitem:
                    # for widgets we immediately set all normal properties as window prop
                    self.set_win_props(prepare_win_props(listitem))

                # if another lookup for the same listitem already in progress... wait for it to complete
                while self.lookup_busy.get(cur_listitem):
                    xbmc.sleep(250)
                    if self.exit:
                        return
                self.lookup_busy[cur_listitem] = True

                # music content
                if content_type in ["albums", "artists", "songs"] and self.enable_musicart:
                    listitem = extend_dict(listitem, self.artutils.get_music_artwork(
                        listitem["artist"], listitem["album"], listitem["title"], listitem["discnumber"]))

                # moviesets
                elif listitem["path"].startswith("videodb://movies/sets/") and listitem["dbid"]:
                    listitem = extend_dict(listitem, self.artutils.get_moviesetdetails(listitem["dbid"]))
                    content_type = "sets"

                # video content
                elif content_type in ["movies", "setmovies", "tvshows", "seasons", "episodes", "musicvideos"]:

                    # get imdb and tvdbid
                    listitem["imdbnumber"], tvdbid = self.artutils.get_imdbtvdb_id(
                        listitem["title"], content_type,
                        listitem["year"], listitem["imdbnumber"], listitem["tvshowtitle"])

                    # generic video properties (studio, streamdetails, omdb, top250)
                    listitem = extend_dict(listitem,
                                           self.get_directors_writers(listitem["director"], listitem["writer"]))
                    if self.enable_extrafanart:
                        if not listitem["filenameandpath"]:
                            listitem["filenameandpath"] = listitem["path"]
                        listitem = extend_dict(listitem, self.artutils.get_extrafanart(listitem["filenameandpath"]))
                    listitem = extend_dict(listitem, self.get_genres(listitem["genre"]))
                    listitem = extend_dict(listitem, self.artutils.get_duration(listitem["duration"]))
                    listitem = extend_dict(listitem, self.artutils.get_studio_logo(listitem["studio"]))
                    listitem = extend_dict(listitem, self.artutils.get_omdb_info(listitem["imdbnumber"]))
                    listitem = extend_dict(
                        listitem, self.get_streamdetails(
                            listitem["dbid"], listitem["path"], content_type))
                    if self.exit:
                        return
                    listitem = extend_dict(listitem, self.artutils.get_top250_rating(listitem["imdbnumber"]))
                    if self.enable_extendedart:
                        if not (listitem["art"]["clearlogo"] or listitem["art"]["landscape"]):
                            listitem = extend_dict(listitem, self.artutils.get_extended_artwork(
                                listitem["imdbnumber"], tvdbid, content_type))

                    if self.exit:
                        return

                    # tvshows-only properties (tvdb)
                    if content_type in ["tvshows", "seasons", "episodes"]:
                        listitem = extend_dict(listitem,
                                               self.artutils.get_tvdb_details(listitem["imdbnumber"], tvdbid))

                    # movies-only properties (tmdb, animated art)
                    if content_type in ["movies", "setmovies"]:
                        listitem = extend_dict(listitem, self.artutils.get_tmdb_details(listitem["imdbnumber"]))
                        if listitem["imdbnumber"] and self.enable_animatedart:
                            listitem = extend_dict(listitem, self.artutils.get_animated_artwork(listitem["imdbnumber"]))

                if self.exit:
                    return

                # monitor listitem props when PVR is active
                elif content_type in ["tvchannels", "tvrecordings", "channels", "recordings", "timers", "tvtimers"]:
                    listitem = self.get_pvr_artwork(listitem, prefix)

                # process all properties
                all_props = prepare_win_props(listitem)
                if content_type not in ["weathers", "systeminfos", "sets"]:
                    self.listitem_details[cur_listitem] = all_props

                self.lookup_busy.pop(cur_listitem, None)

            if cur_listitem == self.last_listitem:
                self.set_win_props(all_props)
        except Exception as exc:
            log_exception(__name__, exc)

    def do_background_work(self):
        '''stuff that's processed in the background'''
        try:
            if self.exit:
                return
            log_msg("Started Background worker...")
            self.set_generic_props()
            self.listitem_details = {}
            self.cache.check_cleanup()
            log_msg("Ended Background worker...")
        except Exception as exc:
            log_exception(__name__, exc)

    def set_generic_props(self):
        '''set some genric window props with item counts'''
        # GET TOTAL ADDONS COUNT
        addons_count = len(kodi_json('Addons.GetAddons'))
        self.win.setProperty("SkinHelper.TotalAddons", "%s" % addons_count)

        addontypes = []
        addontypes.append(("executable", "SkinHelper.TotalProgramAddons"))
        addontypes.append(("video", "SkinHelper.TotalVideoAddons"))
        addontypes.append(("audio", "SkinHelper.TotalAudioAddons"))
        addontypes.append(("image", "SkinHelper.TotalPicturesAddons"))
        for addontype in addontypes:
            media_array = kodi_json('Addons.GetAddons', {"content": addontype[0]})
            self.win.setProperty(addontype[1], str(len(media_array)))

        # GET FAVOURITES COUNT
        favs = kodi_json('Favourites.GetFavourites')
        if favs:
            self.win.setProperty("SkinHelper.TotalFavourites", "%s" % len(favs))

        # GET TV CHANNELS COUNT
        if xbmc.getCondVisibility("Pvr.HasTVChannels"):
            tv_channels = kodi_json('PVR.GetChannels', {"channelgroupid": "alltv"})
            self.win.setProperty("SkinHelper.TotalTVChannels", "%s" % len(tv_channels))

        # GET MOVIE SETS COUNT
        movieset_movies_count = 0
        moviesets = kodi_json('VideoLibrary.GetMovieSets')
        for item in moviesets:
            for item in kodi_json('VideoLibrary.GetMovieSetDetails', {"setid": item["setid"]}):
                movieset_movies_count += 1
        self.win.setProperty("SkinHelper.TotalMovieSets", "%s" % len(moviesets))
        self.win.setProperty("SkinHelper.TotalMoviesInSets", "%s" % movieset_movies_count)

        # GET RADIO CHANNELS COUNT
        if xbmc.getCondVisibility("Pvr.HasRadioChannels"):
            radio_channels = kodi_json('PVR.GetChannels', {"channelgroupid": "allradio"})
            self.win.setProperty("SkinHelper.TotalRadioChannels", "%s" % len(radio_channels))

    def reset_win_props(self):
        '''reset all window props set by the script...'''
        for prop in self.all_window_props:
            self.win.clearProperty(prop)
        self.all_window_props = []

    def set_win_prop(self, prop_tuple):
        '''sets a window property based on the given tuple of key-value'''
        if prop_tuple[1] and not prop_tuple[0] in self.all_window_props:
            self.all_window_props.append(prop_tuple[0])
            self.win.setProperty(prop_tuple[0], prop_tuple[1])

    def set_win_props(self, prop_tuples):
        '''set multiple window properties from list of tuples'''
        process_method_on_list(self.set_win_prop, prop_tuples)

    def set_content_header(self, content_type):
        '''sets a window propery which can be used as headertitle'''
        self.win.clearProperty("SkinHelper.ContentHeader")
        itemscount = xbmc.getInfoLabel("Container.NumItems")
        if itemscount:
            if xbmc.getInfoLabel("Container.ListItemNoWrap(0).Label").startswith(
                    "*") or xbmc.getInfoLabel("Container.ListItemNoWrap(1).Label").startswith("*"):
                itemscount = int(itemscount) - 1

            headerprefix = ""
            if content_type == "movies":
                headerprefix = xbmc.getLocalizedString(36901)
            elif content_type == "tvshows":
                headerprefix = xbmc.getLocalizedString(36903)
            elif content_type == "seasons":
                headerprefix = xbmc.getLocalizedString(36905)
            elif content_type == "episodes":
                headerprefix = xbmc.getLocalizedString(36907)
            elif content_type == "sets":
                headerprefix = xbmc.getLocalizedString(36911)
            elif content_type == "albums":
                headerprefix = xbmc.getLocalizedString(36919)
            elif content_type == "songs":
                headerprefix = xbmc.getLocalizedString(36921)
            elif content_type == "artists":
                headerprefix = xbmc.getLocalizedString(36917)

            if headerprefix:
                self.win.setProperty("SkinHelper.ContentHeader", "%s %s" % (itemscount, headerprefix))

    @staticmethod
    def get_genres(li_genre):
        '''get formatted genre string from actual genre'''
        details = {}
        genres = li_genre.split(" / ")
        details['genres'] = "[CR]".join(genres)
        for count, genre in enumerate(genres):
            details["genre.%s" % count] = genre
        return details

    @staticmethod
    def get_directors_writers(director, writer):
        '''get a formatted string with directors/writers from the actual string'''
        directors = director.split(" / ")
        writers = writer.split(" / ")
        return {
            'Directors': "[CR]".join(directors),
            'Writers': "[CR]".join(writers)}

    @staticmethod
    def get_listitem_details(content_type, prefix):
        '''collect all listitem properties/values we need'''

        # collect all the infolabels we need
        listitem_details = {"art": {}}
        props = ["label", "title", "filenameandpath", "year", "genre", "path", "folderpath",
                 "art(fanart)", "art(poster)", "art(clearlogo)", "art(clearart)", "art(landscape)",
                 "fileextension", "duration", "plot", "plotoutline", "icon", "thumb", "label2",
                 "dbtype", "dbid", "art(thumb)", "art(banner)"
                 ]
        if content_type in ["movies", "tvshows", "seasons", "episodes", "musicvideos", "setmovies"]:
            props += ["art(characterart)", "studio", "tvshowtitle", "premiered", "director", "writer",
                      "firstaired", "videoresolution", "audiocodec", "audiochannels", "videocodec", "videoaspect",
                      "subtitlelanguage", "audiolanguage", "mpaa", "isstereoscopic", "video3dformat",
                      "tagline", "rating", "imdbnumber"]
            if content_type in ["episodes"]:
                props += ["season", "episode", "art(tvshow.landscape)", "art(tvshow.clearlogo)",
                          "art(tvshow.poster)", "art(tvshow.fanart)", "art(tvshow.banner)"]
        elif content_type in ["musicvideos", "artists", "albums", "songs"]:
            props += ["artist", "album", "rating", "albumartist", "discnumber"]
        elif content_type in ["tvchannels", "tvrecordings", "channels", "recordings", "timers", "tvtimers"]:
            props += ["channel", "startdatetime", "datetime", "date", "channelname",
                      "starttime", "startdate", "endtime", "enddate"]
        for prop in props:
            propvalue = xbmc.getInfoLabel('%sListItem.%s' % (prefix, prop)).decode('utf-8')
            if not propvalue or propvalue == "-1":
                propvalue = xbmc.getInfoLabel('%sListItem.Property(%s)' % (prefix, prop)).decode('utf-8')
            if "art(" in prop:
                prop = prop.replace("art(", "").replace(")", "").replace("tvshow.", "")
                propvalue = get_clean_image(propvalue)
                listitem_details["art"][prop] = propvalue
            else:
                listitem_details[prop] = propvalue

        # fix for folderpath
        if not listitem_details.get("path"):
            listitem_details["path"] = listitem_details["folderpath"]

        return listitem_details

    def get_streamdetails(self, li_dbid, li_path, content_type):
        '''get the streamdetails for the current video'''
        details = {}
        if li_dbid and content_type in ["movies", "episodes",
                                        "musicvideos"] and not li_path.startswith("videodb://movies/sets/"):
            details = self.artutils.get_streamdetails(li_dbid, content_type)
        return details

    def set_forcedview(self, content_type):
        '''helper to force the view in certain conditions'''
        if self.enable_forcedviews:
            cur_forced_view = xbmc.getInfoLabel("Skin.String(SkinHelper.ForcedViews.%s)" % content_type)
            if xbmc.getCondVisibility("Control.IsVisible(%s) | IsEmpty(Container.Viewmode)" % cur_forced_view):
                # skip if the view is already visible or if we're not in an actual media window
                return
            if (content_type and cur_forced_view and cur_forced_view != "None" and not
                    xbmc.getCondVisibility("Window.IsActive(MyPvrGuide.xml)")):
                self.win.setProperty("SkinHelper.ForcedView", cur_forced_view)
                count = 0
                while not xbmc.getCondVisibility("Control.HasFocus(%s)" % cur_forced_view):
                    xbmc.sleep(100)
                    xbmc.executebuiltin("Container.SetViewMode(%s)" % cur_forced_view)
                    xbmc.executebuiltin("SetFocus(%s)" % cur_forced_view)
                    count += 1
                    if count == 50:
                        break
            else:
                self.win.clearProperty("SkinHelper.ForcedView")
        else:
            self.win.clearProperty("SkinHelper.ForcedView")

    def get_pvr_artwork(self, listitem, prefix):
        '''get pvr artwork from artwork module'''
        if self.enable_pvrart:
            if xbmc.getCondVisibility("%sListItem.IsFolder" % prefix) and not listitem[
                    "channelname"] and not listitem["title"]:
                listitem["title"] = listitem["label"]
            listitem = extend_dict(
                listitem, self.artutils.get_pvr_artwork(
                    listitem["title"],
                    listitem["channelname"],
                    listitem["genre"]), ["title", "genre", "genres", "thumb"])
        # pvr channellogo
        if listitem["channelname"]:
            listitem["ChannelLogo"] = self.artutils.get_channellogo(listitem["channelname"])
        elif listitem.get("pvrchannel"):
            listitem["ChannelLogo"] = self.artutils.get_channellogo(listitem["pvrchannel"])
        return listitem
Exemple #18
0
class Mubi(object):
    _URL_MUBI = "https://mubi.com"
    _mubi_urls = {
        "login": urljoin(_URL_MUBI, "api/v1/sessions"),
        "films": urljoin(_URL_MUBI, "services/android/films"),
        "film": urljoin(_URL_MUBI, "services/android/films/%s"),
        "set_reel": urljoin(_URL_MUBI, "api/v1/films/%s/viewing/set_reel"),
        "get_url": urljoin(_URL_MUBI, "api/v1/films/%s/reels/%s/secure_url"),
        "startup": urljoin(_URL_MUBI, "services/android/app_startup")
    }

    def __init__(self, username, password):
        self._username = username
        self._password = password
        self._cache_id = "plugin.video.mubi.filminfo.%s"
        self._simplecache = SimpleCache()
        # Need a 20 digit id, hash username to make it predictable
        self._udid = int(hashlib.sha1(username).hexdigest(), 32) % (10**20)
        self._token = None
        self._userid = None
        self._country = None
        self._headers = {
            'client': 'android',
            'client-app': 'mubi',
            'client-version': '4.46',
            'client-device-identifier': str(self._udid)
        }
        self.login()

    def login(self):
        payload = {'email': self._username, 'password': self._password}
        xbmc.log(
            "Logging in with username: %s and udid: %s" %
            (self._username, self._udid), 2)
        r = requests.post(self._mubi_urls["login"],
                          headers=self._headers,
                          data=payload)
        result = (''.join(r.text)).encode('utf-8')
        if r.status_code == 200:
            self._token = json.loads(result)['token']
            self._userid = json.loads(result)['user']['id']
            self._headers['authorization'] = 'Bearer ' + self._token
            xbmc.log(
                "Login Successful with token=%s and userid=%s" %
                (self._token, self._userid), 2)
        else:
            xbmc.log("Login Failed with result: %s" % result, 4)
        self.app_startup()
        return r.status_code

    def app_startup(self):
        payload = {
            'udid': self._udid,
            'token': self._token,
            'client': 'android',
            'client_version': '4.46'
        }
        r = requests.post(self._mubi_urls['startup'] + "?client=android",
                          data=payload)
        result = (''.join(r.text)).encode('utf-8')
        if r.status_code == 200:
            self._country = json.loads(result)['country']
            xbmc.log("Successfully got country as %s" % self._country, 2)
        else:
            xbmc.log("Failed to get country: %s" % result, 4)
        return

    def get_film_page(self, film_id):
        cached = self._simplecache.get(self._cache_id % film_id)
        if cached:
            return json.loads(cached)
        args = "?client=android&country=%s&token=%s&udid=%s&client_version=4.46" % (
            self._country, self._token, self._udid)
        r = requests.get((self._mubi_urls['film'] % str(film_id)) + args)
        if r.status_code != 200:
            xbmc.log(
                "Invalid status code %s getting film info for %s" %
                (r.status_code, film_id), 4)
        self._simplecache.set(self._cache_id % film_id,
                              r.text,
                              expiration=datetime.timedelta(days=32))
        return json.loads(r.text)

    def get_film_metadata(self, film_overview):
        film_id = film_overview['id']
        available_at = dateutil.parser.parse(film_overview['available_at'])
        expires_at = dateutil.parser.parse(film_overview['expires_at'])
        # Check film is valid, has not expired and is not preview
        now = datetime.datetime.now(available_at.tzinfo)
        if available_at > now:
            xbmc.log("Film %s is not yet available" % film_id, 2)
            return None
        elif expires_at < now:
            xbmc.log("Film %s has expired" % film_id, 2)
            return None
        hd = film_overview['hd']
        drm = film_overview['reels'][0]['drm']
        audio_lang = film_overview['reels'][0]['audio_language']
        subtitle_lang = film_overview['reels'][0]['subtitle_language']
        # Build plot field. Place lang info in here since there is nowhere else for it to go
        drm_string = ""  #"Protected by DRM\n" if drm else ""
        lang_string = ("Language: %s" % audio_lang) + (
            (", Subtitles: %s\n" % subtitle_lang) if subtitle_lang else "\n")
        plot_string = "Synopsis: %s\n\nOur take: %s" % (
            film_overview['excerpt'], film_overview['editorial'])
        # Get detailed look at film to get cast info
        film_page = self.get_film_page(film_id)
        cast = [(m['name'], m['credits']) for m in film_page['cast']]
        # Build film metadata object
        metadata = Metadata(
            title=film_overview['title'],
            director=film_overview['directors'],
            year=film_overview['year'],
            duration=film_overview['duration'] * 60,  # This is in seconds
            country=film_overview['country'],
            plot=drm_string + lang_string + plot_string,
            overlay=6 if hd else 0,
            genre=', '.join(film_overview['genres']),
            originaltitle=film_overview['original_title'],
            # Out of 5, kodi uses 10
            rating=film_overview['average_rating'] *
            2 if film_overview['average_rating'] is not None else None,
            votes=film_overview['number_of_ratings'],
            castandrole=cast,
            trailer=film_overview['trailer_url'])
        listview_title = film_overview['title'] + (" [HD]" if hd else "")
        return Film(listview_title, film_id,
                    film_overview['stills']['standard'], metadata)

    def get_now_showing_json(self):
        # Get list of available films
        args = "?client=android&country=%s&token=%s&udid=%s&client_version=4.46" % (
            self._country, self._token, self._udid)
        r = requests.get(self._mubi_urls['films'] + args)
        if r.status_code != 200:
            xbmc.log("Invalid status code %s getting list of films", 4)
        return r.text

    def now_showing(self):
        films = [
            self.get_film_metadata(film)
            for film in json.loads(self.get_now_showing_json())
        ]
        return [f for f in films if f]

    def get_default_reel_id_is_drm(self, film_id):
        reel_id = [(f['reels'][0]['id'], f['reels'][0]['drm'])
                   for f in json.loads(self.get_now_showing_json())
                   if str(f['id']) == str(film_id)]
        if len(reel_id) == 1:
            return reel_id[0]
        elif reel_id:
            xbmc.log(
                "Multiple default_reel's returned for film %s: %s" %
                (film_id, ', '.join(reel_id)), 3)
            return reel_id[0]
        else:
            xbmc.log("Could not find default reel id for film %s" % film_id, 4)
            return None

    def get_play_url(self, film_id):
        (reel_id, is_drm) = self.get_default_reel_id_is_drm(film_id)

        # set reel
        payload = {'reel_id': reel_id, 'sidecar_subtitle_language_id': 20}
        r = requests.put((self._mubi_urls['set_reel'] % str(film_id)),
                         data=payload,
                         headers=self._headers)
        result = (''.join(r.text)).encode('utf-8')
        xbmc.log("Set reel response: %s" % result, 2)

        # get film url
        args = "?country=%s&download=false" % (self._country)
        r = requests.get(
            (self._mubi_urls['get_url'] % (str(film_id), str(reel_id))) + args,
            headers=self._headers)
        result = (''.join(r.text)).encode('utf-8')
        if r.status_code != 200:
            xbmc.log(
                "Could not get secure URL for film %s with reel_id=%s" %
                (film_id, reel_id), 4)
        xbmc.log("Response was: %s" % result, 2)
        url = json.loads(result)["url"]
        # For DRM you will have to find the following info:
        # {"userId": long(result['username']), "sessionId": result['transaction'], "merchant": result['accountCode']}
        # This might need optdata in header however looking in requests during browser negotiation I don't see it
        # https://stackoverflow.com/questions/35792897/http-request-header-field-optdata
        # The best conversation for this is:
        # https://github.com/emilsvennesson/kodi-viaplay/issues/9
        # You can pick this conversation up using Android Packet Capture
        item_result = {
            'url':
            url,
            'is_mpd':
            "mpd" in url,
            'is_drm':
            is_drm,
            'drm_header':
            base64.b64encode('{"userId":' + str(self._userid) +
                             ',"sessionId":"' + self._token +
                             '","merchant":"mubi"}')
        }
        xbmc.log("Got video info as: '%s'" % json.dumps(item_result), 2)
        return item_result
Exemple #19
0
class PlutoTV(object):
    def __init__(self, sysARG):
        log('__init__, sysARG = ' + str(sysARG))
        self.sysARG = sysARG
        self.net = net.Net()
        self.cache = SimpleCache()

    def login(self):
        log('login')
        if USER_EMAIL == LANGUAGE(30009): return  #ignore, using guest login
        if len(USER_EMAIL) > 0:
            header_dict = {}
            header_dict[
                'Accept'] = 'application/json, text/javascript, */*; q=0.01'
            header_dict['Host'] = 'api.pluto.tv'
            header_dict['Connection'] = 'keep-alive'
            header_dict['Referer'] = 'http://pluto.tv/'
            header_dict['Origin'] = 'http://pluto.tv'
            header_dict[
                'User-Agent'] = 'Mozilla/5.0 (Windows NT 6.2; rv:24.0) Gecko/20100101 Firefox/24.0'
            form_data = ({
                'optIn': 'true',
                'password': PASSWORD,
                'synced': 'false',
                'userIdentity': USER_EMAIL
            })
            self.net.set_cookies(COOKIE_JAR)
            try:
                loginlink = json.loads(
                    self.net.http_POST(
                        LOGIN_URL, form_data=form_data,
                        headers=header_dict).content.encode("utf-8").rstrip())
                if loginlink and loginlink['email'].lower(
                ) == USER_EMAIL.lower():
                    notificationDialog(LANGUAGE(30006) %
                                       (loginlink['displayName']),
                                       time=4000)
                    self.net.save_cookies(COOKIE_JAR)
                else:
                    notificationDialog(LANGUAGE(30007), time=4000)
            except Exception as e:
                log('login, failed! ' + str(e), xbmc.LOGERROR)
        else:
            #firstrun wizard
            if yesnoDialog(LANGUAGE(30008),
                           no=LANGUAGE(30009),
                           yes=LANGUAGE(30010)):
                REAL_SETTINGS.setSetting('User_Email',
                                         inputDialog(LANGUAGE(30001)))
                REAL_SETTINGS.setSetting('User_Password',
                                         inputDialog(LANGUAGE(30002)))
            else:
                REAL_SETTINGS.setSetting('User_Email', LANGUAGE(30009))

    def openURL(self, url, life=datetime.timedelta(minutes=15)):
        log('openURL, url = ' + url)
        try:
            header_dict = {}
            header_dict[
                'Accept'] = 'application/json, text/javascript, */*; q=0.01'
            header_dict['Host'] = 'api.pluto.tv'
            header_dict['Connection'] = 'keep-alive'
            header_dict['Referer'] = 'http://pluto.tv/'
            header_dict['Origin'] = 'http://pluto.tv'
            header_dict[
                'User-Agent'] = 'Mozilla/5.0 (Windows NT 6.2; rv:24.0) Gecko/20100101 Firefox/24.0'
            self.net.set_cookies(COOKIE_JAR)
            trans_table = ''.join([chr(i) for i in range(128)] + [' '] * 128)
            cacheResponse = self.cache.get(ADDON_NAME +
                                           '.openURL, url = %s' % url)
            if not cacheResponse:
                try:
                    cacheResponse = self.net.http_GET(
                        url,
                        headers=header_dict).content.encode("utf-8", 'ignore')
                except:
                    cacheResponse = (self.net.http_GET(
                        url,
                        headers=header_dict).content.translate(trans_table)
                                     ).encode("utf-8")
                self.net.save_cookies(COOKIE_JAR)
                self.cache.set(ADDON_NAME + '.openURL, url = %s' % url,
                               cacheResponse,
                               expiration=life)
            if isinstance(cacheResponse, basestring):
                cacheResponse = json.loads(cacheResponse)
            return cacheResponse
        except Exception as e:
            log('openURL, Unable to open url ' + str(e), xbmc.LOGERROR)
            notificationDialog(LANGUAGE(30028), time=4000)
            return {}

    def mainMenu(self):
        log('mainMenu')
        self.login()
        for item in PLUTO_MENU:
            self.addDir(*item)

    def browseMenu(self):
        log('browseMenu')
        categoryMenu = self.getCategories()
        for item in categoryMenu:
            self.addDir(*item)

    def getOndemand(self):
        devid = LANGUAGE(30022) % (REAL_SETTINGS.getSetting("sid"),
                                   REAL_SETTINGS.getSetting("deviceId"))
        return self.openURL(BASE_VOD % (devid),
                            life=datetime.timedelta(hours=4))

    def getVOD(self, epid):
        devid = LANGUAGE(30022) % (REAL_SETTINGS.getSetting("sid"),
                                   REAL_SETTINGS.getSetting("deviceId"))
        return self.openURL(SEAONS_VOD % (epid, devid),
                            life=datetime.timedelta(hours=4))

    def getClips(self, epid):
        return self.openURL(BASE_CLIPS % (epid),
                            life=datetime.timedelta(hours=4))

    def getChannels(self):
        return sorted(self.openURL(BASE_LINEUP,
                                   life=datetime.timedelta(hours=2)),
                      key=lambda i: i['number'])

    def getGuidedata(self):
        tz = str(timezone())
        start = datetime.datetime.now().strftime('%Y-%m-%dT%H:00:00').replace(
            'T', '%20').replace(':00:00', '%3A00%3A00.000' + tz)
        stop = (
            datetime.datetime.now() +
            datetime.timedelta(hours=4)).strftime('%Y-%m-%dT%H:00:00').replace(
                'T', '%20').replace(':00:00', '%3A00%3A00.000' + tz)
        devid = 'sid=%s&deviceId=%s' % (REAL_SETTINGS.getSetting("sid"),
                                        REAL_SETTINGS.getSetting("deviceId"))
        return sorted((self.openURL(BASE_GUIDE % (start, stop, devid),
                                    life=datetime.timedelta(hours=1))),
                      key=lambda i: i['number'])

    def getCategories(self):
        log('getCategories')
        collect = []
        data = self.getChannels()
        for channel in data:
            collect.append(channel['category'])
        counter = collections.Counter(collect)
        for key, value in sorted(counter.iteritems()):
            yield (key, 'categories', 0)

    def getMediaTypes(self):
        mediaType = {}
        categoryMenu = self.getCategories()
        for type in categoryMenu:
            type = type[0]
            if type == 'Movies': mediaType[type] = 'movie'
            elif type == 'TV': mediaType[type] = 'episodes'
            elif type == 'Music + Radio': mediaType[type] = 'musicvideo'
            else: mediaType[type] = 'video'
        return mediaType

    def pagination(self, seq, rowlen):
        for start in xrange(0, len(seq), rowlen):
            yield seq[start:start + rowlen]

    def buildGuide(self, data):
        channel, name, opt = data
        log('buildGuide, name=%s,opt=%s' % (name, opt))
        urls = []
        guidedata = []
        newChannel = {}
        mtype = 'videos'
        chid = channel.get('_id', '')
        chname = channel.get('name', '')
        chnum = channel.get('number', '')
        chplot = (channel.get('description', '') or channel.get('summary', ''))
        chgeo = channel.get('visibility', 'everyone') != 'everyone'
        chcat = (channel.get('category', '') or channel.get('genre', ''))
        chfanart = channel.get('featuredImage', {}).get('path', FANART)
        chthumb = channel.get('thumbnail', {}).get('path', ICON)
        chlogo = channel.get('logo', {}).get('path', ICON)
        ondemand = channel.get('onDemand', 'false') == 'true'
        featured = channel.get('featured', 'false') == 'true'
        favorite = channel.get('favorite', 'false') == 'true'
        timelines = channel.get('timelines', [])

        if name == 'featured' and not featured: return None
        elif name == 'favorite' and not favorite: return None
        elif name == 'categories' and chcat != opt: return None
        elif name == 'lineup' and chid != opt: return None
        elif name == 'live': DISC_CACHE = False

        if name in ['channels', 'categories', 'ondemand', 'season']:
            if name == 'season':
                seasons = (channel.get('seasons', {}))
                vodimages = channel.get('covers', [])
                try:
                    vodlogo = [
                        image.get('url', []) for image in vodimages
                        if image.get('aspectRatio', '') == '1:1'
                    ][0]
                except:
                    vodlogo = ICON
                try:
                    vodfanart = [
                        image.get('url', []) for image in vodimages
                        if image.get('aspectRatio', '') == '16:9'
                    ][0]
                except:
                    vodfanart = FANART
                for season in seasons:
                    mtype = 'episodes'
                    label = 'Season %s' % (season['number'])
                    infoLabels = {
                        "mediatype": mtype,
                        "label": label,
                        "label2": label,
                        "title": chname,
                        "plot": chplot,
                        "code": chid,
                        "genre": [chcat]
                    }
                    infoArt = {
                        "thumb": vodlogo,
                        "poster": vodlogo,
                        "fanart": vodfanart,
                        "icon": vodlogo,
                        "logo": vodlogo,
                        "clearart": chthumb
                    }
                    self.addDir(label, chid, 5, infoLabels, infoArt)
            else:
                if name == 'ondemand':
                    mode = 3
                    label = chname
                else:
                    mode = 1
                    label = '%s| %s' % (chnum, chname)
                infoLabels = {
                    "mediatype": mtype,
                    "label": label,
                    "label2": label,
                    "title": label,
                    "plot": chplot,
                    "code": chid,
                    "genre": [chcat]
                }
                infoArt = {
                    "thumb": chthumb,
                    "poster": chthumb,
                    "fanart": chfanart,
                    "icon": chlogo,
                    "logo": chlogo,
                    "clearart": chthumb
                }
                self.addDir(label, chid, mode, infoLabels, infoArt)
        else:
            newChannel['channelname'] = chname
            newChannel['channelnumber'] = chnum
            newChannel['channellogo'] = chlogo
            newChannel['isfavorite'] = favorite
            urls = channel.get('stitched', {}).get('urls', [])
            if not timelines:
                name = 'ondemand'
                timelines = (channel.get('items', [])
                             or channel.get('episodes', []))

            now = datetime.datetime.now()
            totstart = now
            tz = (timezone() // 100) * 60 * 60

            for item in timelines:
                episode = (item.get('episode', {}) or item)
                series = (episode.get('series', {}) or item)
                urls = (item.get('stitched', {}).get('urls', []) or urls)
                epdur = int(episode.get('duration', '0') or '0') // 1000

                try:
                    start = strpTime(item['start'], '%Y-%m-%dT%H:%M:00.000Z'
                                     ) + datetime.timedelta(seconds=tz)
                    stop = start + datetime.timedelta(seconds=epdur)
                except:
                    start = totstart
                    stop = start + datetime.timedelta(seconds=epdur)
                totstart = stop

                type = series.get('type', '')
                tvtitle = series.get('name', '' or chname)
                title = (item.get('title', ''))
                tvplot = (series.get('description', '')
                          or series.get('summary', '') or chplot)
                tvoutline = (series.get('summary', '')
                             or series.get('description', '') or chplot)
                tvthumb = (series.get('title', {}).get('path', '') or chthumb)
                tvfanart = (series.get('featuredImage', {}).get('path', '')
                            or chfanart)
                epid = episode['_id']
                epnumber = episode.get('number', 0)
                epseason = episode.get('season', 0)
                epname = (episode['name'])
                epplot = (episode.get('description', '') or tvplot or epname)
                epgenre = (episode.get('genre', '') or chcat)
                eptag = episode.get('subGenre', '')
                epmpaa = episode.get('rating', '')

                vodimages = episode.get('covers', [])
                vodposter = vodfanart = vodthumb = vodlogo = ''
                if vodimages:
                    try:
                        vodposter = [
                            image.get('url', []) for image in vodimages
                            if image.get('aspectRatio', '') == '347:500'
                        ][0]
                    except:
                        pass
                    try:
                        vodfanart = [
                            image.get('url', []) for image in vodimages
                            if image.get('aspectRatio', '') == '16:9'
                        ][0]
                    except:
                        pass
                    try:
                        vodthumb = [
                            image.get('url', []) for image in vodimages
                            if image.get('aspectRatio', '') == '4:3'
                        ][0]
                    except:
                        pass
                    try:
                        vodlogo = [
                            image.get('url', []) for image in vodimages
                            if image.get('aspectRatio', '') == '1:1'
                        ][0]
                    except:
                        pass

                chlogo = (vodlogo or chlogo)
                epposter = (episode.get('poster', {}).get('path', '')
                            or vodlogo or vodposter or vodthumb or tvthumb)
                epthumb = (episode.get('thumbnail', {}).get('path', '')
                           or vodlogo or vodthumb or vodposter or tvthumb)
                epfanart = (episode.get('featuredImage', {}).get('path', '')
                            or vodfanart or tvfanart)
                epislive = episode.get('liveBroadcast', 'false') == 'true'

                label = title
                thumb = chthumb
                if type in ['movie', 'film']:
                    mtype = 'movies'
                    thumb = epposter
                elif type in ['tv', 'episode', 'series']:
                    mtype = 'episodes'
                    thumb = epposter
                    if epseason > 0 and epnumber > 0:
                        label = '%sx%s' % (epseason, epnumber)
                        label = '%s - %s' % (label, epname)
                        # else: label  = '%s - %s'%(tvtitle, label)
                    else:
                        label = epname
                    epname = label

                if name == 'live':
                    if stop < now or start > now: continue
                    label = '%s| %s' % (chnum, chname)
                    if type in ['movie', 'film']:
                        mtype = 'movies'
                        thumb = epposter
                        label = '%s :[B]%s[/B]' % (label, title)
                    elif type in ['tv', 'series']:
                        mtype = 'episodes'
                        thumb = epposter
                        label = "%s :[B]%s - %s[/B]" % (label, tvtitle, epname)
                    epname = label

                elif name == 'lineup':
                    if now > stop: continue
                    if now >= start and now < stop:
                        label = '%s - [B]%s[/B]' % (
                            start.strftime('%I:%M %p').lstrip('0'), label)
                    else:
                        label = '%s - %s' % (
                            start.strftime('%I:%M %p').lstrip('0'), label)
                    epname = label

                if len(urls) == 0: continue
                if isinstance(urls, list):
                    urls = [
                        url['url'] for url in urls
                        if url['type'].lower() == 'hls'
                    ][0]

                tmpdata = {
                    "mediatype": mtype,
                    "label": label,
                    "title": label,
                    'duration': epdur,
                    'plot': epplot,
                    'genre': [epgenre],
                    'season': epseason,
                    'episode': epnumber
                }
                tmpdata['starttime'] = time.mktime((start).timetuple())
                tmpdata['url'] = self.sysARG[0] + '?mode=9&name=%s&url=%s' % (
                    title, urls)
                tmpdata['art'] = {
                    "thumb": thumb,
                    "poster": epposter,
                    "fanart": epfanart,
                    "icon": chlogo,
                    "logo": chlogo,
                    "clearart": chthumb
                }
                guidedata.append(tmpdata)

                if name == 'ondemand' and type == "series":
                    mtype = 'seasons'
                    infoLabels = {
                        "mediatype": mtype,
                        "label": label,
                        "label2": label,
                        "title": label,
                        "plot": epplot,
                        "code": chid,
                        "genre": [epgenre]
                    }
                    infoArt = {
                        "thumb": epthumb,
                        "poster": epposter,
                        "fanart": epfanart,
                        "icon": chlogo,
                        "logo": chlogo,
                        "clearart": chthumb
                    }
                    self.addDir(label, epid, 4, infoLabels, infoArt)
                elif name != 'guide':
                    infoLabels = {
                        "mediatype": mtype,
                        "label": label,
                        "label2": label,
                        "tvshowtitle": tvtitle,
                        "title": epname,
                        "plot": epplot,
                        "code": epid,
                        "genre": [epgenre],
                        "duration": epdur,
                        'season': epseason,
                        'episode': epnumber
                    }
                    infoArt = {
                        "thumb": thumb,
                        "poster": epposter,
                        "fanart": epfanart,
                        "icon": chlogo,
                        "logo": chlogo,
                        "clearart": chthumb
                    }
                    self.addLink(title, urls, 9, infoLabels, infoArt)

            CONTENT_TYPE = mtype
            if len(guidedata) > 0:
                newChannel['guidedata'] = guidedata
                return newChannel

    def uEPG(self):
        log('uEPG')
        data = self.getGuidedata()
        return urllib.quote(
            json.dumps(
                list(
                    self.poolList(self.buildGuide,
                                  zip(data, repeat('guide'), repeat(''))))))

    def browseGuide(self, name, opt=None, data=None):
        log('browseGuide, name=%s, opt=%s' % (name, opt))
        if data is None: data = self.getGuidedata()
        if opt == 'categories':
            opt = name
            name = 'categories'
        self.poolList(self.buildGuide,
                      zip(data, repeat(name.lower()), repeat(opt)))

    def browseLineup(self, name, opt=None):
        log('browseLineup, opt=%s' % opt)
        if opt is None: name = 'channels'
        else: name = 'lineup'
        self.browseGuide(name, opt)

    def browseOndemand(self, opt=None):
        log('browseOndemand')
        data = self.getOndemand()['categories']
        if opt is None: name = 'ondemand'
        else: name = 'lineup'
        self.browseGuide(name, opt, data)

    def browseSeason(self, opt=None):
        log('browseSeason')
        data = [self.getVOD(opt)]
        self.browseGuide('season', opt, data)

    def browseEpisodes(self, name, opt=None):
        log('browseEpisodes')
        season = int(name.split('Season ')[1])
        data = [self.getVOD(opt).get('seasons', [])[season - 1]]
        self.browseGuide('episode', opt, data)

    def browseCategories(self):
        log('browseCategories')
        data = list(self.getCategories())
        for item in data:
            self.addDir(*item)

    def playVideo(self, name, url, liz=None):
        if LANGUAGE(30019) not in url:
            url = LANGUAGE(30021) % (url, LANGUAGE(30020) %
                                     (REAL_SETTINGS.getSetting("sid"),
                                      REAL_SETTINGS.getSetting("deviceId")))
        log('playVideo, url = %s' % url)
        if liz is None: liz = xbmcgui.ListItem(name, path=url)
        if 'm3u8' in url.lower() and inputstreamhelper.Helper(
                'hls').check_inputstream() and not DEBUG:
            liz.setProperty('inputstreamaddon', 'inputstream.adaptive')
            liz.setProperty('inputstream.adaptive.manifest_type', 'hls')
        xbmcplugin.setResolvedUrl(int(self.sysARG[1]), True, liz)

    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb': ICON, 'fanart': FANART})
        else: liz.setArt(infoArt)
        u = self.sysARG[0] + "?url=" + urllib.quote(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote(name)
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),
                                    url=u,
                                    listitem=liz,
                                    totalItems=total)

    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb': ICON, 'fanart': FANART})
        else: liz.setArt(infoArt)
        u = self.sysARG[0] + "?url=" + urllib.quote(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote(name)
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),
                                    url=u,
                                    listitem=liz,
                                    isFolder=True)

    def poolList(self, method, items):
        results = []
        if ENABLE_POOL and not DEBUG:
            pool = ThreadPool(CORES)
            results = pool.imap_unordered(method, items, chunksize=25)
            pool.close()
            pool.join()
        else:
            results = [method(item) for item in items]
        results = filter(None, results)
        return results

    def getParams(self):
        return dict(parse_qsl(self.sysARG[2][1:]))

    def run(self):
        params = self.getParams()
        try:
            url = urllib.unquote_plus(params["url"])
        except:
            url = None
        try:
            name = urllib.unquote_plus(params["name"])
        except:
            name = None
        try:
            mode = int(params["mode"])
        except:
            mode = None
        log("Mode: " + str(mode))
        log("URL : " + str(url))
        log("Name: " + str(name))

        if mode == None: self.mainMenu()
        elif mode == 0: self.browseGuide(name, url)
        elif mode == 1: self.browseLineup(name, url)
        elif mode == 2: self.browseCategories()
        elif mode == 3: self.browseOndemand(url)
        elif mode == 4: self.browseSeason(url)
        elif mode == 5: self.browseEpisodes(name, url)
        elif mode == 9: self.playVideo(name, url)
        elif mode == 20:
            xbmc.executebuiltin(
                "RunScript(script.module.uepg,json=%s&skin_path=%s&refresh_path=%s&refresh_interval=%s&row_count=%s&include_hdhr=false)"
                % (self.uEPG(), urllib.quote(ADDON_PATH),
                   urllib.quote(self.sysARG[0] + "?mode=20"), "7200", "5"))

        xbmcplugin.setContent(int(self.sysARG[1]), CONTENT_TYPE)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_UNSORTED)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_NONE)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_LABEL)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_TITLE)
        xbmcplugin.endOfDirectory(int(self.sysARG[1]), cacheToDisc=DISC_CACHE)
Exemple #20
0
class NewsBlender(object):
    def __init__(self):
        self.cache   = SimpleCache()
        self.sources = self.openURL(SOURCES_URL).get('sources','')
        
        
    def openURL(self, url):
        log('openURL, url = ' + url)
        try:
            cacheresponse = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
            if not cacheresponse:
                request = urllib2.Request(url)
                request.add_header('User-Agent','Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)')
                request.add_header('Accept-type', 'application/json')
                response = urllib2.urlopen(request, timeout = TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, response, expiration=datetime.timedelta(hours=1))
            return json.loads(self.cache.get(ADDON_NAME + '.openURL, url = %s'%url))
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
            return ''
         
        
    def buildMenu(self):
        for idx, item in enumerate(MAIN_MENU): self.addDir(item,'',idx)
            
            
    def buildCategory(self):
        category = collections.Counter([x['category'] for x in self.sources])
        for category, value in sorted(category.iteritems()): self.addDir(category.title(),category,4)

        
    def buildCountry(self):
        countries  = collections.Counter([x['country'] for x in self.sources])
        for country, value in sorted(countries.iteritems()): self.addDir(getRegionName(country),country,6)
        
        
    def buildLanguage(self):
        languages  = collections.Counter([x['language'] for x in self.sources])
        for language, value in sorted(languages.iteritems()): self.addDir(getLanguageName(language),language,7)

        
    def buildSource(self, items=None):
        if items is None: items = self.sources
        for source in items:
            label      = source['name']
            thumb      = (LOGO_URL%source['url'] or ICON)
            infoLabels = {"mediatype":"files","label":label,"title":label,"genre":source.get('category','news'),"plot":source.get('description','news')}
            infoArt    = {"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON}
            self.addDir(label, source['id'], 5, infoLabels, infoArt)
    
    
    def browseCategory(self, url):
        self.buildSource(self.openURL(SOURCES_URL + '&category=%s'%url).get('sources',''))
        

    def browseCountry(self, url):
        self.buildSource(self.openURL(SOURCES_URL + '&country=%s'%url).get('sources',''))

        
    def browseLanguage(self, url):
        self.buildSource(self.openURL(SOURCES_URL + '&language=%s'%url).get('sources',''))
            
            
    def browseTop(self, url):
        self.browse(self.newsArticles.get_by_top(url).get('sources',''))
        
        
    def browseLatest(self, url):
        self.browse(self.newsArticles.get_by_latest(url).get('sources',''))
        
        
    def browsePopular(self, url):
        self.browse(self.newsArticles.get_by_popular(url).get('sources',''))
        
        
    def search(self, name, url):
        kb = xbmc.Keyboard('', LANGUAGE(30005)%name)
        xbmc.sleep(1000)
        kb.doModal()
        if kb.isConfirmed():
            url = (EVRYTHING_URL + '&q=%s&sources=%s'%(urllib.quote_plus(kb.getText()),url)).split('|')[0]
            try: self.browseArticles(name, url, self.openURL(url).get('articles',''), False)
            except Exception as e: log('search, failed ' + str(e), xbmc.LOGERROR)

                
    def buildArticles(self, name, url):
        self.browseArticles(name, url, self.openURL(HEADLINE_URL + '&sources=%s'%url).get('articles',''))

        
    def browseArticles(self, name, url, items, search=True):
        tmpList = []
        for idx, item in enumerate(items):
            info = self.getVideo(item['url'])
            if info is None or len(info) == 0: continue
            source = item['source']['name']
            label  = item['title']
            thumb  = item['urlToImage']
            plot   = item['description']
            try: aired = item['publishedAt'].split('T')[0]
            except: aired = (datetime.datetime.now()).strftime('%Y-%m-%d')
            tmpList.append((source, label, thumb, plot, aired, info))
        dlg = busyDialog(0)
        for idx, data in enumerate(tmpList):
            busyDialog(idx * 100 // len(tmpList),dlg)
            try: 
                source, label, thumb, plot, aired, info = data
                url = info[0]['xbmc_url']
                try:
                    if 'subtitles' in info[0]['ytdl_format']: liz.setSubtitles([x['url'] for x in info[0]['ytdl_format']['subtitles'].get('en','') if 'url' in x])
                except: pass
                infoLabels = {"mediatype":"episode","label":label ,"title":label,"duration":info[0]['ytdl_format'].get('duration',0),"aired":aired,"plot":plot,"genre":"News"}
                infoArt    = {"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON}
                self.addLink(label, url, 9, infoLabels, infoArt)
            except: pass
        busyDialog(100,dlg)
        if len(tmpList) == 0: self.addLink((LANGUAGE(30003)%name), "", "")
        elif search: self.addSearch(name, url)
       
    def getVideo(self, url):
        cacheresponse = self.cache.get(ADDON_NAME + '.getVideo, url = %s'%url)
        if not cacheresponse:
            info = getVideoInfo(url,QUALITY,True)
            if info is not None: info = info.streams()
            self.cache.set(ADDON_NAME + '.getVideo, url = %s'%url, json.dumps(info), expiration=datetime.timedelta(days=14))
        return json.loads(self.cache.get(ADDON_NAME + '.getVideo, url = %s'%url))
            
            
    def playVideo(self, name, url, liz=None):
        log('playVideo')
        if liz is None: liz = xbmcgui.ListItem(name, path=url)
        xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)
        
           
    def addSearch(self, name, url):
        self.addDir((LANGUAGE(30004)%name), url, 8)
           
           
    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':LOGO_URL%urllib.quote_plus(name),'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,totalItems=total)


    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART}) #LOGO_URL%urllib.quote_plus(name)
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
class ListItemMonitor(threading.Thread):
    '''Our main class monitoring the kodi listitems and providing additional information'''
    event = None
    exit = False
    delayed_task_interval = 1795
    listitem_details = {}
    all_window_props = {}
    cur_listitem = ""
    last_folder = ""
    last_listitem = ""
    foldercontent = {}
    screensaver_setting = None
    screensaver_disabled = False
    lookup_busy = {}
    enable_extendedart = False
    enable_musicart = False
    enable_animatedart = False
    enable_extrafanart = False
    enable_extraposter = False
    enable_pvrart = False
    enable_forcedviews = False

    def __init__(self, *args, **kwargs):
        self.cache = SimpleCache()
        self.metadatautils = kwargs.get("metadatautils")
        self.win = kwargs.get("win")
        self.kodimonitor = kwargs.get("monitor")
        self.event = threading.Event()
        threading.Thread.__init__(self, *args)

    def stop(self):
        '''called when the thread has to stop working'''
        log_msg("ListItemMonitor - stop called")
        self.exit = True
        self.cache.close()
        self.event.set()
        self.event.clear()
        self.join(1)

    def run(self):
        '''our main loop monitoring the listitem and folderpath changes'''
        log_msg("ListItemMonitor - started")
        self.get_settings()

        while not self.exit:

            # check screensaver and OSD
            self.check_screensaver()
            self.check_osd()

            # do some background stuff every 30 minutes
            if (self.delayed_task_interval >= 1800) and not self.exit:
                thread.start_new_thread(self.do_background_work, ())
                self.delayed_task_interval = 0

            # skip if any of the artwork context menus is opened
            if self.win.getProperty("SkinHelper.Artwork.ManualLookup"):
                self.reset_win_props()
                self.last_listitem = ""
                self.listitem_details = {}
                self.kodimonitor.waitForAbort(3)
                self.delayed_task_interval += 3

            # skip when modal dialogs are opened (e.g. textviewer in musicinfo dialog)
            elif getCondVisibility(
                    "Window.IsActive(DialogSelect.xml) | Window.IsActive(progressdialog) | "
                    "Window.IsActive(contextmenu) | Window.IsActive(busydialog)"
            ):
                self.kodimonitor.waitForAbort(2)
                self.delayed_task_interval += 2
                self.last_listitem = ""

            # skip when container scrolling
            elif getCondVisibility(
                    "Container.OnScrollNext | Container.OnScrollPrevious | Container.Scrolling"
            ):
                self.kodimonitor.waitForAbort(1)
                self.delayed_task_interval += 1
                self.last_listitem = ""

            # media window is opened or widgetcontainer set - start listitem monitoring!
            elif getCondVisibility(
                    "Window.IsMedia | "
                    "!IsEmpty(Window(Home).Property(SkinHelper.WidgetContainer))"
            ):
                self.monitor_listitem()
                self.kodimonitor.waitForAbort(0.15)
                self.delayed_task_interval += 0.15

            # flush any remaining window properties
            elif self.all_window_props:
                self.reset_win_props()
                self.win.clearProperty("SkinHelper.ContentHeader")
                self.win.clearProperty("contenttype")
                self.win.clearProperty("curlistitem")
                self.last_listitem = ""

            # other window active - do nothing
            else:
                self.kodimonitor.waitForAbort(1)
                self.delayed_task_interval += 1

    def get_settings(self):
        '''collect our skin settings that control the monitoring'''
        self.enable_extendedart = getCondVisibility(
            "Skin.HasSetting(SkinHelper.EnableExtendedArt)") == 1
        self.enable_musicart = getCondVisibility(
            "Skin.HasSetting(SkinHelper.EnableMusicArt)") == 1
        self.enable_animatedart = getCondVisibility(
            "Skin.HasSetting(SkinHelper.EnableAnimatedPosters)") == 1
        self.enable_extrafanart = getCondVisibility(
            "Skin.HasSetting(SkinHelper.EnableExtraFanart)") == 1
        self.enable_extraposter = getCondVisibility(
            "Skin.HasSetting(SkinHelper.EnableExtraPoster)") == 1
        self.enable_pvrart = getCondVisibility(
            "Skin.HasSetting(SkinHelper.EnablePVRThumbs) + PVR.HasTVChannels"
        ) == 1
        self.enable_forcedviews = getCondVisibility(
            "Skin.HasSetting(SkinHelper.ForcedViews.Enabled)") == 1
        studiologos_path = xbmc.getInfoLabel(
            "Skin.String(SkinHelper.StudioLogos.Path)")
        if studiologos_path != self.metadatautils.studiologos_path:
            self.listitem_details = {}
            self.metadatautils.studiologos_path = studiologos_path
        # set additional window props to control contextmenus as using the skinsetting gives unreliable results
        for skinsetting in [
                "EnableAnimatedPosters", "EnableMusicArt", "EnablePVRThumbs"
        ]:
            if getCondVisibility("Skin.HasSetting(SkinHelper.%s)" %
                                 skinsetting):
                self.win.setProperty("SkinHelper.%s" % skinsetting, "enabled")
            else:
                self.win.clearProperty("SkinHelper.%s" % skinsetting)

    def monitor_listitem(self):
        '''Monitor listitem details'''

        cur_folder, cont_prefix = self.get_folderandprefix()
        # identify current listitem - prefer parent folder (tvshows, music)
        cur_listitem = try_decode(
            xbmc.getInfoLabel(
                "$INFO[%sListItem.TvshowTitle]$INFO[%sListItem.Artist]$INFO[%sListItem.Album]"
                % (cont_prefix, cont_prefix, cont_prefix)))
        if not cur_listitem:
            # fallback to generic approach
            cur_listitem = try_decode(
                xbmc.getInfoLabel(
                    "$INFO[%sListItem.Label]$INFO[%sListItem.DBID]$INFO[%sListItem.Title]"
                    % (cont_prefix, cont_prefix, cont_prefix)))

        if self.exit:
            return

        # perform actions if the container path has changed
        if cur_folder != self.last_folder and not (
                cur_listitem and cur_listitem == self.last_listitem):
            self.reset_win_props()
            self.get_settings()
            self.last_folder = cur_folder
            self.last_listitem = None
            content_type = self.get_content_type(cur_folder, cur_listitem,
                                                 cont_prefix)
            # additional actions to perform when we have a valid contenttype and no widget container
            if not cont_prefix and content_type:
                self.set_forcedview(content_type)
                self.set_content_header(content_type)
        else:
            content_type = self.get_content_type(cur_folder, cur_listitem,
                                                 cont_prefix)

        if self.exit:
            return

        # only perform actions when the listitem has actually changed
        if cur_listitem != self.last_listitem:
            self.last_listitem = cur_listitem
            self.win.setProperty("curlistitem", cur_listitem)
            if cur_listitem and cur_listitem != "..":
                # set listitem details in background thread
                thread.start_new_thread(
                    self.set_listitem_details,
                    (cur_listitem, content_type, cont_prefix))

    def get_folderandprefix(self):
        '''get the current folder and prefix'''
        cur_folder = ""
        cont_prefix = ""
        try:
            widget_container = try_decode(
                self.win.getProperty("SkinHelper.WidgetContainer"))
            if getCondVisibility("Window.IsActive(movieinformation)"):
                cont_prefix = ""
                cur_folder = try_decode(
                    xbmc.getInfoLabel(
                        "$INFO[Window.Property(xmlfile)]$INFO[Container.FolderPath]"
                        "$INFO[Container.NumItems]$INFO[Container.Content]"))
            elif widget_container:
                cont_prefix = "Container(%s)." % widget_container
                cur_folder = try_decode(
                    xbmc.getInfoLabel(
                        "widget-%s-$INFO[Container(%s).NumItems]-$INFO[Container(%s).ListItemAbsolute(1).Label]"
                        % (widget_container, widget_container,
                           widget_container)))
            else:
                cont_prefix = ""
                cur_folder = try_decode(
                    xbmc.getInfoLabel(
                        "$INFO[Window.Property(xmlfile)]$INFO[Container.FolderPath]$INFO[Container.NumItems]$INFO[Container.Content]"
                    ))
        except Exception as exc:
            log_exception(__name__, exc)
            cur_folder = ""
            cont_prefix = ""
        return (cur_folder, cont_prefix)

    def get_content_type(self, cur_folder, cur_listitem, cont_prefix):
        '''get contenttype for current folder'''
        content_type = ""
        if cur_folder in self.foldercontent:
            content_type = self.foldercontent[cur_folder]
        elif cur_folder and cur_listitem:
            # always wait for the content_type because some listings can be slow
            for i in range(20):
                content_type = get_current_content_type(cont_prefix)
                if self.exit:
                    return ""
                if content_type:
                    break
                else:
                    xbmc.sleep(250)
            self.foldercontent[cur_folder] = content_type
        self.win.setProperty("contenttype", content_type)
        return content_type

    def check_screensaver(self):
        '''Allow user to disable screensaver on fullscreen music playback'''
        if getCondVisibility(
                "Window.IsActive(visualisation) + Skin.HasSetting(SkinHelper.DisableScreenSaverOnFullScreenMusic)"
        ):
            if not self.screensaver_disabled:
                # disable screensaver when fullscreen music active
                self.screensaver_disabled = True
                screensaver_setting = kodi_json(
                    'Settings.GetSettingValue',
                    '{"setting":"screensaver.mode"}')
                if screensaver_setting:
                    self.screensaver_setting = screensaver_setting
                    kodi_json('Settings.SetSettingValue', {
                        "setting": "screensaver.mode",
                        "value": None
                    })
                    log_msg(
                        "Disabled screensaver while fullscreen music playback - previous setting: %s"
                        % self.screensaver_setting, xbmc.LOGNOTICE)
        elif self.screensaver_disabled and self.screensaver_setting:
            # enable screensaver again after fullscreen music playback was ended
            kodi_json('Settings.SetSettingValue', {
                "setting": "screensaver.mode",
                "value": self.screensaver_setting
            })
            self.screensaver_disabled = False
            self.screensaver_setting = None
            log_msg(
                "fullscreen music playback ended - restoring screensaver: %s" %
                self.screensaver_setting, xbmc.LOGNOTICE)

    @staticmethod
    def check_osd():
        '''Allow user to set a default close timeout for the OSD panels'''
        if getCondVisibility(
                "[Window.IsActive(videoosd) + Skin.String(SkinHelper.AutoCloseVideoOSD)] | "
                "[Window.IsActive(musicosd) + Skin.String(SkinHelper.AutoCloseMusicOSD)]"
        ):
            if getCondVisibility("Window.IsActive(videoosd)"):
                seconds = xbmc.getInfoLabel(
                    "Skin.String(SkinHelper.AutoCloseVideoOSD)")
                window = "videoosd"
            elif getCondVisibility("Window.IsActive(musicosd)"):
                seconds = xbmc.getInfoLabel(
                    "Skin.String(SkinHelper.AutoCloseMusicOSD)")
                window = "musicosd"
            else:
                seconds = ""
            if seconds and seconds != "0":
                while getCondVisibility("Window.IsActive(%s)" % window):
                    if getCondVisibility("System.IdleTime(%s)" % seconds):
                        if getCondVisibility("Window.IsActive(%s)" % window):
                            xbmc.executebuiltin("Dialog.Close(%s)" % window)
                    else:
                        xbmc.sleep(500)

    def set_listitem_details(self, cur_listitem, content_type, prefix):
        '''set the window properties based on the current listitem'''
        try:
            if cur_listitem in self.listitem_details:
                # data already in memory
                all_props = self.listitem_details[cur_listitem]
            else:
                # skip if another lookup for the same listitem is already in progress...
                if self.lookup_busy.get(cur_listitem) or self.exit:
                    return
                self.lookup_busy[cur_listitem] = True

                # clear all window props, do this delayed to prevent flickering of the screen
                thread.start_new_thread(self.delayed_flush, (cur_listitem, ))

                # wait if we already have more than 5 items in the queue
                while len(self.lookup_busy) > 5:
                    xbmc.sleep(100)
                    if self.exit or cur_listitem != self.last_listitem:
                        self.lookup_busy.pop(cur_listitem, None)
                        return

                # prefer listitem's contenttype over container's contenttype
                dbtype = xbmc.getInfoLabel("%sListItem.DBTYPE" % prefix)
                if not dbtype:
                    dbtype = xbmc.getInfoLabel("%sListItem.Property(DBTYPE)" %
                                               prefix)
                if dbtype:
                    content_type = dbtype + "s"

                # collect details from listitem
                details = self.get_listitem_details(content_type, prefix)

                if self.exit:
                    return

                # music content
                if content_type in ["albums", "artists", "songs"
                                    ] and self.enable_musicart:
                    details = self.metadatautils.extend_dict(
                        details,
                        self.metadatautils.get_music_artwork(
                            details["artist"], details["album"],
                            details["title"], details["discnumber"]))
                # moviesets
                elif details["path"].startswith(
                        "videodb://movies/sets/") and details["dbid"]:
                    details = self.metadatautils.extend_dict(
                        details,
                        self.metadatautils.get_moviesetdetails(
                            details["title"], details["dbid"]), ["year"])
                    content_type = "sets"
                # video content
                elif content_type in [
                        "movies", "setmovies", "tvshows", "seasons",
                        "episodes", "musicvideos"
                ]:

                    # get imdb and tvdbid
                    details[
                        "imdbnumber"], tvdbid = self.metadatautils.get_imdbtvdb_id(
                            details["title"], content_type, details["year"],
                            details["imdbnumber"], details["tvshowtitle"])

                    if self.exit:
                        return

                    # generic video properties (studio, streamdetails, omdb, top250)
                    details = merge_dict(
                        details,
                        self.get_directors_writers(details["director"],
                                                   details["writer"]))
                    if self.enable_extrafanart:
                        log_msg("skin.helper.service: extrafanart",
                                xbmc.LOGNOTICE)
                        if not details["filenameandpath"]:
                            details["filenameandpath"] = details["path"]
                        if "videodb://" not in details["filenameandpath"]:
                            efa = self.metadatautils.get_extrafanart(
                                details["filenameandpath"])
                            if efa:
                                details["art"] = merge_dict(
                                    details["art"], efa["art"])
                    if self.enable_extraposter:
                        if not details["filenameandpath"]:
                            details["filenameandpath"] = details["path"]
                        if "videodb://" not in details["filenameandpath"]:
                            efa = self.metadatautils.get_extraposter(
                                details["filenameandpath"])
                            if efa:
                                details["art"] = merge_dict(
                                    details["art"], efa["art"])
                    if self.exit:
                        return

                    details = merge_dict(
                        details,
                        self.metadatautils.get_duration(details["duration"]))
                    details = merge_dict(details,
                                         self.get_genres(details["genre"]))
                    details = merge_dict(
                        details,
                        self.metadatautils.get_studio_logo(details["studio"]))
                    details = merge_dict(
                        details,
                        self.metadatautils.get_omdb_info(
                            details["imdbnumber"]))
                    details = merge_dict(
                        details,
                        self.get_streamdetails(details["dbid"],
                                               details["path"], content_type))
                    details = merge_dict(
                        details,
                        self.metadatautils.get_top250_rating(
                            details["imdbnumber"]))

                    if self.exit:
                        return

                    # tvshows-only properties (tvdb)
                    if content_type in ["tvshows", "seasons", "episodes"]:
                        details = merge_dict(
                            details,
                            self.metadatautils.get_tvdb_details(
                                details["imdbnumber"], tvdbid))

                    # movies-only properties (tmdb, animated art)
                    if content_type in ["movies", "setmovies"]:
                        details = merge_dict(
                            details,
                            self.metadatautils.get_tmdb_details(
                                details["imdbnumber"]))
                        if details["imdbnumber"] and self.enable_animatedart:
                            details = self.metadatautils.extend_dict(
                                details,
                                self.metadatautils.get_animated_artwork(
                                    details["imdbnumber"]))

                    if self.exit:
                        return

                    # extended art
                    if self.enable_extendedart:
                        tmdbid = details.get("tmdb_id", "")
                        details = self.metadatautils.extend_dict(
                            details,
                            self.metadatautils.get_extended_artwork(
                                details["imdbnumber"], tvdbid, tmdbid,
                                content_type), [
                                    "posters", "clearlogos", "banners",
                                    "discarts", "cleararts", "characterarts"
                                ])
                # monitor listitem props when PVR is active
                elif content_type in [
                        "tvchannels", "tvrecordings", "channels", "recordings",
                        "timers", "tvtimers"
                ]:
                    details = self.get_pvr_artwork(details, prefix)

                # process all properties
                all_props = prepare_win_props(details)
                if "sets" not in content_type:
                    self.listitem_details[cur_listitem] = all_props

                self.lookup_busy.pop(cur_listitem, None)

            if cur_listitem == self.last_listitem:
                self.set_win_props(all_props)
        except Exception as exc:
            log_exception(__name__, exc)
            self.lookup_busy.pop(cur_listitem, None)

    def delayed_flush(self, cur_listitem):
        '''flushes existing properties when it takes too long to grab the new ones'''
        xbmc.sleep(500)
        if cur_listitem == self.last_listitem and cur_listitem in self.lookup_busy:
            self.reset_win_props()

    def do_background_work(self):
        '''stuff that's processed in the background'''
        try:
            if self.exit:
                return
            log_msg("Started Background worker...")
            self.set_generic_props()
            self.listitem_details = {}
            if self.exit:
                return
            self.cache.check_cleanup()
            log_msg("Ended Background worker...")
        except Exception as exc:
            log_exception(__name__, exc)

    def set_generic_props(self):
        '''set some generic window props with item counts'''
        # GET TOTAL ADDONS COUNT
        addons_count = len(kodi_json('Addons.GetAddons'))
        self.win.setProperty("SkinHelper.TotalAddons", "%s" % addons_count)

        addontypes = []
        addontypes.append(("executable", "SkinHelper.TotalProgramAddons"))
        addontypes.append(("video", "SkinHelper.TotalVideoAddons"))
        addontypes.append(("audio", "SkinHelper.TotalAudioAddons"))
        addontypes.append(("image", "SkinHelper.TotalPicturesAddons"))
        for addontype in addontypes:
            media_array = kodi_json('Addons.GetAddons',
                                    {"content": addontype[0]})
            self.win.setProperty(addontype[1], str(len(media_array)))

        # GET FAVOURITES COUNT
        favs = kodi_json('Favourites.GetFavourites')
        if favs:
            self.win.setProperty("SkinHelper.TotalFavourites",
                                 "%s" % len(favs))

        if self.exit:
            return

        # GET TV CHANNELS COUNT
        if getCondVisibility("Pvr.HasTVChannels"):
            tv_channels = kodi_json('PVR.GetChannels',
                                    {"channelgroupid": "alltv"})
            self.win.setProperty("SkinHelper.TotalTVChannels",
                                 "%s" % len(tv_channels))

        if self.exit:
            return

        # GET MOVIE SETS COUNT
        movieset_movies_count = 0
        moviesets = kodi_json('VideoLibrary.GetMovieSets')
        for item in moviesets:
            for item in kodi_json('VideoLibrary.GetMovieSetDetails',
                                  {"setid": item["setid"]}):
                movieset_movies_count += 1
        self.win.setProperty("SkinHelper.TotalMovieSets",
                             "%s" % len(moviesets))
        self.win.setProperty("SkinHelper.TotalMoviesInSets",
                             "%s" % movieset_movies_count)

        if self.exit:
            return

        # GET RADIO CHANNELS COUNT
        if getCondVisibility("Pvr.HasRadioChannels"):
            radio_channels = kodi_json('PVR.GetChannels',
                                       {"channelgroupid": "allradio"})
            self.win.setProperty("SkinHelper.TotalRadioChannels",
                                 "%s" % len(radio_channels))

    def reset_win_props(self):
        '''reset all window props set by the script...'''
        self.metadatautils.process_method_on_list(
            self.win.clearProperty, iter(list(self.all_window_props.keys())))
        self.all_window_props = {}

    def set_win_prop(self, prop_tuple):
        '''sets a window property based on the given key-value'''
        key = prop_tuple[0]
        value = prop_tuple[1]
        if (key not in self.all_window_props) or (
                key in self.all_window_props
                and self.all_window_props[key] != value):
            self.all_window_props[key] = value
            self.win.setProperty(key, value)

    def set_win_props(self, prop_tuples):
        '''set multiple window properties from list of tuples'''
        self.metadatautils.process_method_on_list(self.set_win_prop,
                                                  prop_tuples)
        # cleanup remaining properties
        new_keys = [item[0] for item in prop_tuples]
        for key, value in list(self.all_window_props.items()):
            if value and key not in new_keys:
                self.all_window_props[key] = ""
                self.win.clearProperty(key)

    def set_content_header(self, content_type):
        '''sets a window propery which can be used as headertitle'''
        self.win.clearProperty("SkinHelper.ContentHeader")
        itemscount = xbmc.getInfoLabel("Container.NumItems")
        if itemscount:
            if xbmc.getInfoLabel(
                    "Container.ListItemNoWrap(0).Label"
            ).startswith("*") or xbmc.getInfoLabel(
                    "Container.ListItemNoWrap(1).Label").startswith("*"):
                itemscount = int(itemscount) - 1
            headerprefix = ""
            if content_type == "movies":
                headerprefix = xbmc.getLocalizedString(36901)
            elif content_type == "tvshows":
                headerprefix = xbmc.getLocalizedString(36903)
            elif content_type == "seasons":
                headerprefix = xbmc.getLocalizedString(36905)
            elif content_type == "episodes":
                headerprefix = xbmc.getLocalizedString(36907)
            elif content_type == "sets":
                headerprefix = xbmc.getLocalizedString(36911)
            elif content_type == "albums":
                headerprefix = xbmc.getLocalizedString(36919)
            elif content_type == "songs":
                headerprefix = xbmc.getLocalizedString(36921)
            elif content_type == "artists":
                headerprefix = xbmc.getLocalizedString(36917)
            if headerprefix:
                self.win.setProperty("SkinHelper.ContentHeader",
                                     "%s %s" % (itemscount, headerprefix))

    @staticmethod
    def get_genres(genres):
        '''get formatted genre string from actual genre'''
        details = {}
        if not isinstance(genres, list):
            genres = genres.split(" / ")
        details['genres'] = "[CR]".join(genres)
        for count, genre in enumerate(genres):
            details["genre.%s" % count] = genre
        return details

    @staticmethod
    def get_directors_writers(director, writer):
        '''get a formatted string with directors/writers from the actual string'''
        directors = director.split(" / ")
        writers = writer.split(" / ")
        return {
            'Directors': "[CR]".join(directors),
            'Writers': "[CR]".join(writers)
        }

    def get_listitem_details(self, content_type, prefix):
        '''collect all listitem properties/values we need'''
        listitem_details = {"art": {}}

        # basic properties
        for prop in ["dbtype", "dbid", "imdbnumber"]:
            propvalue = try_decode(
                xbmc.getInfoLabel('$INFO[%sListItem.%s]' % (prefix, prop)))
            if not propvalue or propvalue == "-1":
                propvalue = try_decode(
                    xbmc.getInfoLabel('$INFO[%sListItem.Property(%s)]' %
                                      (prefix, prop)))
            listitem_details[prop] = propvalue

        # generic properties
        props = [
            "label", "title", "filenameandpath", "year", "genre", "path",
            "folderpath", "duration", "plot", "plotoutline", "label2", "icon",
            "thumb"
        ]
        # properties for media items
        if content_type in [
                "movies", "tvshows", "seasons", "episodes", "musicvideos",
                "setmovies"
        ]:
            props += [
                "studio", "tvshowtitle", "premiered", "director", "writer",
                "firstaired", "tagline", "rating", "season", "episode"
            ]
        # properties for music items
        elif content_type in ["musicvideos", "artists", "albums", "songs"]:
            props += ["artist", "album", "rating", "albumartist", "discnumber"]
        # properties for pvr items
        elif content_type in [
                "tvchannels", "tvrecordings", "channels", "recordings",
                "timers", "tvtimers"
        ]:
            props += ["channel", "channelname"]

        for prop in props:
            if self.exit:
                break
            propvalue = try_decode(
                xbmc.getInfoLabel('$INFO[%sListItem.%s]' % (prefix, prop)))
            listitem_details[prop] = propvalue

        # artwork properties
        artprops = [
            "fanart", "poster", "clearlogo", "clearart", "landscape", "thumb",
            "banner", "discart", "characterart"
        ]
        for prop in artprops:
            if self.exit:
                break
            propvalue = try_decode(
                xbmc.getInfoLabel('$INFO[%sListItem.Art(%s)]' %
                                  (prefix, prop)))
            if not propvalue:
                propvalue = try_decode(
                    xbmc.getInfoLabel('$INFO[%sListItem.Art(tvshow.%s)]' %
                                      (prefix, prop)))
            if propvalue:
                listitem_details["art"][prop] = propvalue

        # fix for folderpath
        if not listitem_details.get(
                "path") and "folderpath" in listitem_details:
            listitem_details["path"] = listitem_details["folderpath"]
        # fix for thumb
        if "thumb" not in listitem_details[
                "art"] and "thumb" in listitem_details:
            listitem_details["art"]["thumb"] = listitem_details["thumb"]
        if "fanart" not in listitem_details[
                "art"] and "fanart" in listitem_details:
            listitem_details["art"]["fanart"] = listitem_details["fanart"]
        return listitem_details

    def get_streamdetails(self, li_dbid, li_path, content_type):
        '''get the streamdetails for the current video'''
        details = {}
        if li_dbid and content_type in [
                "movies", "episodes", "musicvideos"
        ] and not li_path.startswith("videodb://movies/sets/"):
            details = self.metadatautils.get_streamdetails(
                li_dbid, content_type)
        return details

    def set_forcedview(self, content_type):
        '''helper to force the view in certain conditions'''
        if self.enable_forcedviews:
            cur_forced_view = xbmc.getInfoLabel(
                "Skin.String(SkinHelper.ForcedViews.%s)" % content_type)
            if getCondVisibility(
                    "Control.IsVisible(%s) | IsEmpty(Container.Viewmode) | System.HasModalDialog | System.HasVisibleModalDialog"
                    % cur_forced_view):
                # skip if the view is already visible or if we're not in an actual media window
                return
            if (content_type and cur_forced_view and cur_forced_view != "None"
                    and
                    not getCondVisibility("Window.IsActive(MyPvrGuide.xml)")):
                self.win.setProperty("SkinHelper.ForcedView", cur_forced_view)
                count = 0
                while not getCondVisibility(
                        "Control.HasFocus(%s)" % cur_forced_view):
                    xbmc.sleep(100)
                    xbmc.executebuiltin("Container.SetViewMode(%s)" %
                                        cur_forced_view)
                    xbmc.executebuiltin("SetFocus(%s)" % cur_forced_view)
                    count += 1
                    if count == 50 or self.exit:
                        break
            else:
                self.win.clearProperty("SkinHelper.ForcedView")
        else:
            self.win.clearProperty("SkinHelper.ForcedView")

    def get_pvr_artwork(self, listitem, prefix):
        '''get pvr artwork from artwork module'''
        if self.enable_pvrart:
            if getCondVisibility(
                    "%sListItem.IsFolder" % prefix
            ) and not listitem["channelname"] and not listitem["title"]:
                listitem["title"] = listitem["label"]
            listitem = self.metadatautils.extend_dict(
                listitem,
                self.metadatautils.get_pvr_artwork(listitem["title"],
                                                   listitem["channelname"],
                                                   listitem["genre"]),
                ["title", "genre", "genres", "thumb"])
        # pvr channellogo
        if listitem["channelname"]:
            listitem["art"][
                "ChannelLogo"] = self.metadatautils.get_channellogo(
                    listitem["channelname"])
        elif listitem.get("pvrchannel"):
            listitem["art"][
                "ChannelLogo"] = self.metadatautils.get_channellogo(
                    listitem["pvrchannel"])
        return listitem
Exemple #22
0
class AnimatedArt(object):
    '''get animated artwork'''
    ignore_cache = False

    def __init__(self, simplecache=None, kodidb=None):
        '''Initialize - optionaly provide SimpleCache and KodiDb object'''

        if not kodidb:
            from kodidb import KodiDb
            self.kodidb = KodiDb()
        else:
            self.kodidb = kodidb

        if not simplecache:
            from simplecache import SimpleCache
            self.cache = SimpleCache()
        else:
            self.cache = simplecache

    @use_cache(14)
    def get_animated_artwork(self,
                             imdb_id,
                             manual_select=False,
                             ignore_cache=False):
        '''returns all available animated art for the given imdbid/tmdbid'''
        # no cache so grab the results
        result = {
            "animatedposter": self.poster(imdb_id, manual_select),
            "animatedfanart": self.fanart(imdb_id, manual_select),
            "imdb_id": imdb_id
        }
        self.write_kodidb(result)
        log_msg("get_animated_artwork for imdbid: %s - result: %s" %
                (imdb_id, result))
        return result

    def poster(self, imdb_id, manual_select=False):
        '''return preferred animated poster, optionally show selectdialog for manual selection'''
        img = self.select_art(self.posters(imdb_id), manual_select, "poster")
        return self.process_image(img, "poster", imdb_id)

    def fanart(self, imdb_id, manual_select=False):
        '''return preferred animated fanart, optionally show selectdialog for manual selection'''
        img = self.select_art(self.fanarts(imdb_id), manual_select, "fanart")
        return self.process_image(img, "fanart", imdb_id)

    def posters(self, imdb_id):
        '''return all animated posters for the given imdb_id (imdbid can also be tmdbid)'''
        return self.get_art(imdb_id, "posters")

    def fanarts(self, imdb_id):
        '''return animated fanarts for the given imdb_id (imdbid can also be tmdbid)'''
        return self.get_art(imdb_id, "fanarts")

    def get_art(self, imdb_id, art_type):
        '''get the artwork'''
        art_db = self.get_animatedart_db()
        if art_db.get(imdb_id):
            return art_db[imdb_id][art_type]
        return []

    def get_animatedart_db(self):
        '''get the full animated art database as dict with imdbid and tmdbid as key
        uses 7 day cache to prevent overloading the server'''
        # get all animated posters from the online json file
        cache = self.cache.get("animatedartdb")
        if cache:
            return cache
        art_db = {}
        data = get_json('http://www.consiliumb.com/animatedgifs/movies.json',
                        None)
        base_url = data.get("baseURL", "")
        if data and data.get('movies'):
            for item in data['movies']:
                for db_id in ["imdbid", "tmdbid"]:
                    key = item[db_id]
                    art_db[key] = {"posters": [], "fanarts": []}
                    for entry in item['entries']:
                        entry_new = {
                            "contributedby":
                            entry["contributedBy"],
                            "dateadded":
                            entry["dateAdded"],
                            "language":
                            entry["language"],
                            "source":
                            entry["source"],
                            "image":
                            "%s/%s" % (base_url, entry["image"].replace(
                                ".gif", "_original.gif")),
                            "thumb":
                            "%s/%s" % (base_url, entry["image"])
                        }
                        if entry['type'] == 'poster':
                            art_db[key]["posters"].append(entry_new)
                        elif entry['type'] == 'background':
                            art_db[key]["fanarts"].append(entry_new)
            self.cache.set("animatedartdb",
                           art_db,
                           expiration=timedelta(days=7))
        return art_db

    @staticmethod
    def select_art(items, manual_select=False, art_type=""):
        '''select the preferred image from the list'''
        image = None
        if manual_select:
            # show selectdialog to manually select the item
            results_list = []
            # add none and browse entries
            listitem = xbmcgui.ListItem(label=xbmc.getLocalizedString(231),
                                        iconImage="DefaultAddonNone.png")
            results_list.append(listitem)
            listitem = xbmcgui.ListItem(label=xbmc.getLocalizedString(1030),
                                        iconImage="DefaultFolder.png")
            results_list.append(listitem)
            for item in items:
                labels = [
                    item["contributedby"], item["dateadded"], item["language"],
                    item["source"]
                ]
                label = " / ".join(labels)
                listitem = xbmcgui.ListItem(label=label,
                                            iconImage=item["thumb"])
                results_list.append(listitem)
            if manual_select and results_list:
                dialog = DialogSelect("DialogSelect.xml",
                                      "",
                                      listing=results_list,
                                      window_title=art_type)
                dialog.doModal()
                selected_item = dialog.result
                del dialog
                if selected_item == 1:
                    # browse for image
                    dialog = xbmcgui.Dialog()
                    image = dialog.browse(2,
                                          xbmc.getLocalizedString(1030),
                                          'files',
                                          mask='.gif').decode("utf-8")
                    del dialog
                elif selected_item > 1:
                    # user has selected an image from online results
                    image = items[selected_item - 2]["image"]
        elif items:
            # just grab the first item as best match
            image = items[0]["image"]
        return image

    @staticmethod
    def process_image(image_url, art_type, imdb_id):
        '''animated gifs need to be stored locally, otherwise they won't work'''
        # make sure that our local path for the gif images exists
        addon = xbmcaddon.Addon(ADDON_ID)
        gifs_path = "%s/animatedgifs/" % addon.getAddonInfo('profile')
        del addon
        if not xbmcvfs.exists(gifs_path):
            xbmcvfs.mkdirs(gifs_path)
        # only process existing images
        if not image_url or not xbmcvfs.exists(image_url):
            return None
        # copy the image to our local path and return the new path as value
        local_filename = "%s%s_%s.gif" % (gifs_path, imdb_id, art_type)
        if xbmcvfs.exists(local_filename):
            xbmcvfs.delete(local_filename)
        # we don't use xbmcvfs.copy because we want to wait for the action to complete
        img = xbmcvfs.File(image_url)
        img_data = img.readBytes()
        img.close()
        img = xbmcvfs.File(local_filename, 'w')
        img.write(img_data)
        img.close()
        return local_filename

    def write_kodidb(self, artwork):
        '''store the animated artwork in kodi database to access it with ListItem.Art(animatedartX)'''
        kodi_movie = self.kodidb.movie_by_imdbid(artwork["imdb_id"])
        if kodi_movie:
            params = {
                "movieid": kodi_movie["movieid"],
                "art": {
                    "animatedfanart": artwork["animatedfanart"],
                    "animatedposter": artwork["animatedposter"]
                }
            }
            self.kodidb.set_json('VideoLibrary.SetMovieDetails', params)
Exemple #23
0
class MetadataUtils(object):
    '''
        Provides all kind of mediainfo for kodi media, returned as dict with details
    '''
    close_called = False

    def __init__(self):
        '''Initialize and load all our helpers'''
        self._studiologos_path = ""
        self.cache = SimpleCache()
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.kodidb = KodiDb()
        self.omdb = Omdb(self.cache)
        self.tmdb = Tmdb(self.cache)
        self.channellogos = ChannelLogos(self.kodidb)
        self.fanarttv = FanartTv(self.cache)
        self.imdb = Imdb(self.cache)
        self.google = GoogleImages(self.cache)
        self.studiologos = StudioLogos(self.cache)
        self.animatedart = AnimatedArt(self.cache, self.kodidb)
        self.thetvdb = TheTvDb()
        self.musicart = MusicArtwork(self)
        self.pvrart = PvrArtwork(self)
        log_msg("Initialized")

    def close(self):
        '''Cleanup instances'''
        self.close_called = True
        self.cache.close()
        self.addon = None
        del self.addon
        del self.kodidb
        del self.omdb
        del self.tmdb
        del self.channellogos
        del self.fanarttv
        del self.imdb
        del self.google
        del self.studiologos
        del self.animatedart
        del self.thetvdb
        del self.musicart
        del self.pvrart
        log_msg("Exited")

    def __del__(self):
        '''make sure close is called'''
        if not self.close_called:
            self.close()

    @use_cache(14)
    def get_extrafanart(self, file_path):
        '''helper to retrieve the extrafanart path for a kodi media item'''
        from helpers.extrafanart import get_extrafanart
        return get_extrafanart(file_path)

    def get_music_artwork(self,
                          artist,
                          album="",
                          track="",
                          disc="",
                          ignore_cache=False,
                          flush_cache=False):
        '''method to get music artwork for the goven artist/album/song'''
        return self.musicart.get_music_artwork(artist,
                                               album,
                                               track,
                                               disc,
                                               ignore_cache=ignore_cache,
                                               flush_cache=flush_cache)

    def music_artwork_options(self, artist, album="", track="", disc=""):
        '''options for music metadata for specific item'''
        return self.musicart.music_artwork_options(artist, album, track, disc)

    @use_cache(14)
    def get_extended_artwork(self,
                             imdb_id="",
                             tvdb_id="",
                             tmdb_id="",
                             media_type=""):
        '''get extended artwork for the given imdbid or tvdbid'''
        from urllib import quote_plus
        result = {"art": {}}
        if "movie" in media_type and tmdb_id:
            result["art"] = self.fanarttv.movie(tmdb_id)
        elif "movie" in media_type and imdb_id:
            result["art"] = self.fanarttv.movie(imdb_id)
        elif media_type in ["tvshow", "tvshows", "seasons", "episodes"]:
            if not tvdb_id:
                if imdb_id and not imdb_id.startswith("tt"):
                    tvdb_id = imdb_id
                elif imdb_id:
                    tvdb_id = self.thetvdb.get_series_by_imdb_id(imdb_id).get(
                        "tvdb_id")
            if tvdb_id:
                result["art"] = self.fanarttv.tvshow(tvdb_id)
        # add additional art with special path
        for arttype in ["fanarts", "posters", "clearlogos", "banners"]:
            if result["art"].get(arttype):
                result["art"][arttype] = "plugin://script.skin.helper.service/"\
                    "?action=extrafanart&fanarts=%s" % quote_plus(repr(result["art"][arttype]))
        return result

    @use_cache(14)
    def get_tmdb_details(self,
                         imdb_id="",
                         tvdb_id="",
                         title="",
                         year="",
                         media_type="",
                         preftype="",
                         manual_select=False,
                         ignore_cache=False):
        '''returns details from tmdb'''
        result = {}
        if imdb_id:
            result = self.tmdb.get_videodetails_by_externalid(
                imdb_id, "imdb_id")
        elif tvdb_id:
            result = self.tmdb.get_videodetails_by_externalid(
                tvdb_id, "tvdb_id")
        elif title and media_type in ["movies", "setmovies", "movie"]:
            result = self.tmdb.search_movie(title,
                                            year,
                                            manual_select=manual_select)
        elif title and media_type in ["tvshows", "tvshow"]:
            result = self.tmdb.search_tvshow(title,
                                             year,
                                             manual_select=manual_select)
        elif title:
            result = self.tmdb.search_video(title,
                                            year,
                                            preftype=preftype,
                                            manual_select=manual_select)
        if result.get("status"):
            result["status"] = self.translate_string(result["status"])
        if result.get("runtime"):
            result["runtime"] = result["runtime"] / 60
            result.update(self.get_duration(result["runtime"]))
        return result

    def get_moviesetdetails(self, title, set_id):
        '''get a nicely formatted dict of the movieset details which we can for example set as window props'''
        # get details from tmdb
        from helpers.moviesetdetails import get_moviesetdetails
        return get_moviesetdetails(self, title, set_id)

    @use_cache(14)
    def get_streamdetails(self, db_id, media_type, ignore_cache=False):
        '''get a nicely formatted dict of the streamdetails '''
        from helpers.streamdetails import get_streamdetails
        return get_streamdetails(self.kodidb, db_id, media_type)

    def get_pvr_artwork(self,
                        title,
                        channel="",
                        genre="",
                        manual_select=False,
                        ignore_cache=False):
        '''get artwork and mediadetails for PVR entries'''
        return self.pvrart.get_pvr_artwork(title,
                                           channel,
                                           genre,
                                           manual_select=manual_select,
                                           ignore_cache=ignore_cache)

    def pvr_artwork_options(self, title, channel="", genre=""):
        '''options for pvr metadata for specific item'''
        return self.pvrart.pvr_artwork_options(title, channel, genre)

    @use_cache(14)
    def get_channellogo(self, channelname):
        '''get channellogo for the given channel name'''
        return self.channellogos.get_channellogo(channelname)

    def get_studio_logo(self, studio):
        '''get studio logo for the given studio'''
        # dont use cache at this level because of changing logospath
        return self.studiologos.get_studio_logo(studio, self.studiologos_path)

    @property
    def studiologos_path(self):
        '''path to use to lookup studio logos, must be set by the calling addon'''
        return self._studiologos_path

    @studiologos_path.setter
    def studiologos_path(self, value):
        '''path to use to lookup studio logos, must be set by the calling addon'''
        self._studiologos_path = value

    def get_animated_artwork(self,
                             imdb_id,
                             manual_select=False,
                             ignore_cache=False):
        '''get animated artwork, perform extra check if local version still exists'''
        artwork = self.animatedart.get_animated_artwork(
            imdb_id, manual_select=manual_select, ignore_cache=ignore_cache)
        if not (manual_select or ignore_cache):
            refresh_needed = False
            if artwork.get("animatedposter") and not xbmcvfs.exists(
                    artwork["animatedposter"]):
                refresh_needed = True
            if artwork.get("animatedfanart") and not xbmcvfs.exists(
                    artwork["animatedfanart"]):
                refresh_needed = True

        return {"art": artwork}

    @use_cache(14)
    def get_omdb_info(self, imdb_id="", title="", year="", content_type=""):
        '''Get (kodi compatible formatted) metadata from OMDB, including Rotten tomatoes details'''
        title = title.split(" (")[0]  # strip year appended to title
        result = {}
        if imdb_id:
            result = self.omdb.get_details_by_imdbid(imdb_id)
        elif title and content_type in [
                "seasons", "season", "episodes", "episode", "tvshows", "tvshow"
        ]:
            result = self.omdb.get_details_by_title(title, "", "tvshows")
        elif title and year:
            result = self.omdb.get_details_by_title(title, year, content_type)
        if result.get("status"):
            result["status"] = self.translate_string(result["status"])
        if result.get("runtime"):
            result["runtime"] = result["runtime"] / 60
            result.update(self.get_duration(result["runtime"]))
        return result

    @use_cache(7)
    def get_top250_rating(self, imdb_id):
        '''get the position in the IMDB top250 for the given IMDB ID'''
        return self.imdb.get_top250_rating(imdb_id)

    @use_cache(14)
    def get_duration(self, duration):
        '''helper to get a formatted duration'''
        if isinstance(duration, (str, unicode)) and ":" in duration:
            dur_lst = duration.split(":")
            return {
                "Duration": "%s:%s" % (dur_lst[0], dur_lst[1]),
                "Duration.Hours": dur_lst[0],
                "Duration.Minutes": dur_lst[1],
                "Runtime": str((int(dur_lst[0]) * 60) + int(dur_lst[1])),
            }
        else:
            return _get_duration(duration)

    @use_cache(2)
    def get_tvdb_details(self, imdbid="", tvdbid=""):
        '''get metadata from tvdb by providing a tvdbid or tmdbid'''
        result = {}
        self.thetvdb.days_ahead = 365
        if not tvdbid and imdbid and not imdbid.startswith("tt"):
            # assume imdbid is actually a tvdbid...
            tvdbid = imdbid
        if tvdbid:
            result = self.thetvdb.get_series(tvdbid)
        elif imdbid:
            result = self.thetvdb.get_series_by_imdb_id(imdbid)
        if result:
            if result["status"] == "Continuing":
                # include next episode info
                result["nextepisode"] = self.thetvdb.get_nextaired_episode(
                    result["tvdb_id"])
            # include last episode info
            result["lastepisode"] = self.thetvdb.get_last_episode_for_series(
                result["tvdb_id"])
            result["status"] = self.translate_string(result["status"])
            if result.get("runtime"):
                result["runtime"] = result["runtime"] / 60
                result.update(_get_duration(result["runtime"]))
        return result

    @use_cache(14)
    def get_imdbtvdb_id(self,
                        title,
                        content_type,
                        year="",
                        imdbid="",
                        tvshowtitle=""):
        '''try to figure out the imdbnumber and/or tvdbid'''
        tvdbid = ""
        if content_type in ["seasons", "episodes"] or tvshowtitle:
            title = tvshowtitle
            content_type = "tvshows"
        if imdbid and not imdbid.startswith("tt"):
            if content_type in ["tvshows", "seasons", "episodes"]:
                tvdbid = imdbid
                imdbid = ""
        if not imdbid and year:
            imdbid = self.get_omdb_info("", title, year,
                                        content_type).get("imdbnumber", "")
        if not imdbid:
            # repeat without year
            imdbid = self.get_omdb_info("", title, "",
                                        content_type).get("imdbnumber", "")
        # return results
        return (imdbid, tvdbid)

    def translate_string(self, _str):
        '''translate the received english string from the various sources like tvdb, tmbd etc'''
        translation = _str
        _str = _str.lower()
        if "continuing" in _str:
            translation = self.addon.getLocalizedString(32037)
        elif "ended" in _str:
            translation = self.addon.getLocalizedString(32038)
        elif "released" in _str:
            translation = self.addon.getLocalizedString(32040)
        return translation
Exemple #24
0
 def __init__(self, sysARG):
     log('__init__, sysARG = ' + str(sysARG))
     self.sysARG = sysARG
     if self.chkUWP(): return
     self.cache = SimpleCache()
Exemple #25
0
class NBC(object):
    def __init__(self, sysARG):
        log('__init__, sysARG = ' + str(sysARG))
        self.sysARG = sysARG
        if self.chkUWP(): return
        self.cache = SimpleCache()

    def chkUWP(self):
        isUWP = (xbmc.getCondVisibility("system.platform.uwp")
                 or sys.platform == "win10"
                 or re.search(r"[/\\]WindowsApps[/\\]XBMCFoundation\.Kodi_",
                              xbmc.translatePath("special://xbmc/")))
        if isUWP:
            return xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30006),
                                                 ICON, 4000)
        return isUWP

    def openURL(self, url):
        try:
            log('openURL, url = ' + str(url))
            if DEBUG: cacheresponse = None
            else:
                cacheresponse = self.cache.get(ADDON_NAME +
                                               '.openURL, url = %s' % url)
            if not cacheresponse:
                cacheresponse = urllib2.urlopen(urllib2.Request(url),
                                                timeout=TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s' % url,
                               cacheresponse,
                               expiration=datetime.timedelta(minutes=15))
            return cacheresponse
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON,
                                          4000)
            return ''

    def buildMenu(self, items):
        for item in items:
            self.addDir(*item)
        self.addYoutube(LANGUAGE(30004),
                        'plugin://plugin.video.youtube/user/NBC/')

    def browseEpisodes(self, url=None):
        log('browseEpisodes')
        if url is None: url = VIDEO_URL + FILTER % ('type', 'Full%20Episode')
        items = json.loads(self.openURL(url))
        if items and 'data' in items:
            for item in items['data']:
                path = item['attributes']['fullUrl']
                aired = str(item['attributes']['airdate']).split('T')[0]
                duration = int(item['attributes']['runTime'])
                plot = item['attributes']['description']
                title = item['attributes']['title']

                showTitle = ''
                for show in item['attributes']['categories']:
                    if show.startswith('Series'):
                        showTitle = show.split('Series/')[1]
                        break

                try:
                    episodeNumber = int(item['attributes']['episodeNumber'])
                except:
                    episodeNumber = 0
                try:
                    seasonNumber = int(item['attributes']['seasonNumber'])
                except:
                    seasonNumber = 0

                try:
                    thumb = ICON
                    for image in items['included']:
                        if image['id'] == item['relationships']['image'][
                                'data']['id']:
                            thumb = BASE_URL + image['attributes']['path']
                            break
                except:
                    thumb = ICON

                seinfo = ('S' + ('0' if seasonNumber < 10 else '') +
                          str(seasonNumber) + 'E' +
                          ('0' if episodeNumber < 10 else '') +
                          str(episodeNumber))
                label = '%s - %s' % (
                    showTitle, title
                ) if seasonNumber + episodeNumber == 0 else '%s - %s - %s' % (
                    showTitle, seinfo, title)
                infoLabels = {
                    "mediatype": "episodes",
                    "label": label,
                    "title": label,
                    "TVShowTitle": showTitle,
                    "plot": plot,
                    "aired": aired,
                    "duration": duration,
                    "season": seasonNumber,
                    "episode": episodeNumber
                }
                infoArt = {
                    "thumb": thumb,
                    "poster": thumb,
                    "fanart": FANART,
                    "icon": ICON,
                    "logo": ICON
                }
                self.addLink(label, path, 9, infoLabels, infoArt,
                             len(items['data']))

            try:
                next_page = items['links']['next']
            except:
                next_page = None
            if next_page:
                self.addDir('>> Next', next_page, 1)

    def browseShows(self, url=None):
        log('browseShows')
        if url is None: url = SHOWS_URL
        items = json.loads(self.openURL(url))
        if items and 'data' in items:
            for item in items['data']:
                showTitle = item['attributes']['shortTitle']
                plot = (item['attributes']['shortDescription']
                        or showTitle).replace('<p>', '').replace('</p>', '')
                path = VIDEO_URL + FILTER % ('show', item['id'])
                vidID = item['relationships']['aggregates']['data']['id']

                try:
                    thumb = ICON
                    for image in items['included']:
                        if image['id'] == item['relationships']['image'][
                                'data']['id']:
                            thumb = BASE_URL + image['attributes']['path']
                            break
                except:
                    thumb = ICON

                myURL = json.dumps({"url": path, "vidID": vidID})
                infoLabels = {
                    "mediatype": "tvshows",
                    "label": showTitle,
                    "title": showTitle,
                    "TVShowTitle": showTitle,
                    "plot": plot
                }
                infoArt = {
                    "thumb": thumb,
                    "poster": thumb,
                    "fanart": FANART,
                    "icon": ICON,
                    "logo": ICON
                }
                self.addDir(showTitle, myURL, 0, infoLabels, infoArt)

            try:
                next_page = items['links']['next']
            except:
                next_page = None
            if next_page:
                self.addDir('>> Next', next_page, 2)

    def buildShow(self, url):
        log('buildShow')
        myURL = json.loads(url)
        items = json.loads(self.openURL(SHOW_URL % myURL['vidID']))
        if items and 'data' in items:
            for item in items['data']['attributes']['videoTypes']:
                self.browseEpisodes(myURL['url'] + FILTER %
                                    ('type', urllib2.quote(item)))

    @use_cache(28)
    def resolveURL(self, url):
        log('resolveURL')
        return getVideoInfo(url, QUALITY, True).streams()

    def playVideo(self, name, url):
        log('playVideo')
        info = self.resolveURL(url)
        if info is None: return
        url = info[0]['xbmc_url']
        liz = xbmcgui.ListItem(name, path=url)
        if 'm3u8' in url.lower() and inputstreamhelper.Helper(
                'hls').check_inputstream() and not DEBUG:
            liz.setProperty('inputstreamaddon', 'inputstream.adaptive')
            liz.setProperty('inputstream.adaptive.manifest_type', 'hls')
        if 'subtitles' in info[0]['ytdl_format']:
            liz.setSubtitles([
                x['url']
                for x in info[0]['ytdl_format']['subtitles'].get('en', '')
                if 'url' in x
            ])
        xbmcplugin.setResolvedUrl(int(self.sysARG[1]), True, liz)

    def addYoutube(self, name, url):
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label": name, "title": name})
        liz.setArt({'thumb': ICON, 'fanart': FANART})
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),
                                    url=url,
                                    listitem=liz,
                                    isFolder=True)

    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name,
                            "genre": "News"
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb': ICON, 'fanart': FANART})
        else: liz.setArt(infoArt)
        u = self.sysARG[0] + "?url=" + urllib.quote_plus(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),
                                    url=u,
                                    listitem=liz,
                                    totalItems=total)

    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name,
                            "genre": "News"
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb': ICON, 'fanart': FANART})
        else: liz.setArt(infoArt)
        u = self.sysARG[0] + "?url=" + urllib.quote_plus(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),
                                    url=u,
                                    listitem=liz,
                                    isFolder=True)

    def getParams(self):
        return dict(urlparse.parse_qsl(self.sysARG[2][1:]))

    def run(self):
        params = self.getParams()
        try:
            url = urllib.unquote_plus(params["url"])
        except:
            url = None
        try:
            name = urllib.unquote_plus(params["name"])
        except:
            name = None
        try:
            mode = int(params["mode"])
        except:
            mode = None
        log("Mode: " + str(mode))
        log("URL : " + str(url))
        log("Name: " + str(name))

        if mode == None: self.buildMenu(MAIN_MENU)
        elif mode == 0: self.buildShow(url)
        elif mode == 1: self.browseEpisodes(url)
        elif mode == 2: self.browseShows(url)
        elif mode == 9: self.playVideo(name, url)

        xbmcplugin.setContent(int(self.sysARG[1]), CONTENT_TYPE)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_UNSORTED)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_NONE)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_LABEL)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_TITLE)
        xbmcplugin.endOfDirectory(int(self.sysARG[1]), cacheToDisc=True)
Exemple #26
0
class Cheddar(object):
    def __init__(self):
        log('__init__')
        self.cache = SimpleCache()
        
        
    def openURL(self, url):
        try:
            cacheResponce = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
            if not cacheResponce:
                request = urllib2.Request(url)
                request.add_header('User-Agent','Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)')
                response = urllib2.urlopen(request, timeout=TIMEOUT)
                cacheResponce = response.read()
                response.close()
                self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, cacheResponce, expiration=datetime.timedelta(hours=1))
            return cacheResponce
        except urllib2.URLError as e: log("openURL Failed! " + str(e), xbmc.LOGERROR)
        except socket.timeout as e: log("openURL Failed! " + str(e), xbmc.LOGERROR)
        xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
        return ''
        
        
    def buildMenu(self, items):
        log('buildMenu')
        if items == Cheddar_LIVE:
            for item in items: self.addLink(*item)
        else: 
            for item in items: self.addDir(*item)
        if items == Cheddar_MENU: self.addYoutube(LANGUAGE(30033), 'plugin://plugin.video.youtube/channel/UC04KsGq3npibMCE9Td3mVDg/')
        

    def browse(self, link):
        log('browse')
        soup = BeautifulSoup(self.openURL(BASEURL + link), "html.parser")
        latestLink = (soup('div', {'class': 'video_thumb'}))
        for item in latestLink:
            uriLink = item('a', {'class': 'cf'})[0]
            uri = BASEURL + uriLink['href']
            thumb = uriLink('div', {'class': 'vid_img'})[0].find_all('img')[0].get('src')
            airdate, title = uriLink.text.strip().replace('\r','').replace('\t','').split('\n')
            label = title.strip()
            plot  = '%s [CR]Aired: %s'%(label, airdate)
            try: airdate = datetime.datetime.strptime(airdate, "%B %d, %Y")
            except: airdate = datetime.datetime.now()
            airdate = airdate.strftime('%Y-%m-%d')
            infoList = {"mediatype":"episode","label":label,"title":label,"plot":plot,'genre':'News',"studio":"cheddar","aired":airdate}
            infoArt  = {"thumb":thumb,"poster":thumb,"fanart":FANART}
            self.addLink(label, uri, 9, infoList, infoArt)

            
    def playVideo(self, name, url):
        log('playVideo, name = ' + name)
        if url.endswith('m3u8'): 
            liz = xbmcgui.ListItem(name, path=url)
            liz.setProperty('inputstreamaddon','inputstream.adaptive')
            liz.setProperty('inputstream.adaptive.manifest_type','hls') 
        else:
            info = getVideoInfo(url,QUALITY,True)
            if info is None: return
            info = info.streams()
            url  = info[0]['xbmc_url']
            liz  = xbmcgui.ListItem(name, path=url)
            if 'subtitles' in info[0]['ytdl_format']: liz.setSubtitles([x['url'] for x in info[0]['ytdl_format']['subtitles'].get('en','') if 'url' in x])  
        xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)
            
                   
    def addYoutube(self, name, url):
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label":name,"title":name} )
        liz.setArt({'thumb':ICON,'fanart':FANART})
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=url,listitem=liz,isFolder=True)
        
           
    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,totalItems=total)


    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name} )
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
Exemple #27
0
class PlutoTV(object):
    def __init__(self, sysARG):
        log('__init__, sysARG = ' + str(sysARG))
        self.sysARG  = sysARG
        self.net     = net.Net()
        self.cache   = SimpleCache()
        self.region  = self.getRegion()
        self.filter  = False if self.region == 'US' else True
        self.categoryMenu = self.getCategories()
        self.mediaType = self.getMediaTypes()
        log('__init__, region = ' + self.region)
        
        
    def getRegion(self):
        return (self.openURL(REGION_URL, life=datetime.timedelta(hours=12)).get('countryCode','') or 'US')
        
        
    def login(self):
        log('login')
        #ignore guest login
        if USER_EMAIL == LANGUAGE(30009): return
        if len(USER_EMAIL) > 0:
            header_dict               = {}
            header_dict['Accept']     = 'application/json, text/javascript, */*; q=0.01'
            header_dict['Host']       = 'api.pluto.tv'
            header_dict['Connection'] = 'keep-alive'
            header_dict['Referer']    = 'http://pluto.tv/'
            header_dict['Origin']     = 'http://pluto.tv'
            header_dict['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.2; rv:24.0) Gecko/20100101 Firefox/24.0'
            
            try: xbmcvfs.rmdir(COOKIE_JAR)
            except: pass
            if xbmcvfs.exists(COOKIE_JAR) == False:
                try:
                    xbmcvfs.mkdirs(SETTINGS_LOC)
                    f = xbmcvfs.File(COOKIE_JAR, 'w')
                    f.close()
                except: log('login, Unable to create the storage directory', xbmc.LOGERROR)
            
            form_data = ({'optIn': 'true', 'password': PASSWORD,'synced': 'false', 'userIdentity': USER_EMAIL})
            self.net.set_cookies(COOKIE_JAR)
            try:
                loginlink = json.loads(self.net.http_POST(LOGIN_URL, form_data=form_data, headers=header_dict).content.encode("utf-8").rstrip())
                if loginlink and loginlink['email'].lower() == USER_EMAIL.lower():
                    xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30006) + loginlink['displayName'], ICON, 4000)
                    self.net.save_cookies(COOKIE_JAR)
                else: xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30007), ICON, 4000)
            except Exception as e: log('login, Unable to create the storage directory ' + str(e), xbmc.LOGERROR)
        else:
            #firstrun wizard
            if yesnoDialog(LANGUAGE(30008),no=LANGUAGE(30009), yes=LANGUAGE(30010)):
                REAL_SETTINGS.setSetting('User_Email',inputDialog(LANGUAGE(30001)))
                REAL_SETTINGS.setSetting('User_Password',inputDialog(LANGUAGE(30002)))
            else: REAL_SETTINGS.setSetting('User_Email',LANGUAGE(30009))
            xbmc.executebuiltin('RunScript("' + ADDON_PATH + '/country.py' + '")')
            
            
    def openURL(self, url, life=datetime.timedelta(minutes=15)):
        log('openURL, url = ' + url)
        try:
            header_dict               = {}
            header_dict['Accept']     = 'application/json, text/javascript, */*; q=0.01'
            header_dict['Host']       = 'api.pluto.tv'
            header_dict['Connection'] = 'keep-alive'
            header_dict['Referer']    = 'http://pluto.tv/'
            header_dict['Origin']     = 'http://pluto.tv'
            header_dict['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.2; rv:24.0) Gecko/20100101 Firefox/24.0'
            self.net.set_cookies(COOKIE_JAR)
            trans_table   = ''.join( [chr(i) for i in range(128)] + [' '] * 128 )
            cacheResponse = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
            if not cacheResponse:
                try: cacheResponse = self.net.http_GET(url, headers=header_dict).content.encode("utf-8", 'ignore')
                except: cacheResponse = (self.net.http_GET(url, headers=header_dict).content.translate(trans_table)).encode("utf-8")
                self.net.save_cookies(COOKIE_JAR)
                self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, cacheResponse, expiration=life)
            if isinstance(cacheResponse, basestring): cacheResponse = json.loads(cacheResponse)
            return cacheResponse
        except Exception as e:
            log('openURL, Unable to open url ' + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, 'Unable to Connect, Check User Credentials', ICON, 4000)
            return {}
            

    def mainMenu(self):
        log('mainMenu')
        self.login()
        for item in PLUTO_MENU: self.addDir(*item)
            
            
    def browseMenu(self):
        log('browseMenu')
        for item in self.categoryMenu: self.addDir(*item)

           
    def getCategories(self):
        log('getCategories')
        collect= []
        lineup = []
        data = self.openURL(BASE_LINEUP)
        for channel in data: collect.append(channel['category'])
        counter = collections.Counter(collect)
        for key, value in sorted(counter.iteritems()): lineup.append(("%s"%(key)  , BASE_LINEUP, 2))
        lineup.insert(0,(LANGUAGE(30016), BASE_LINEUP, 2))
        lineup.insert(2,(LANGUAGE(30014), BASE_LINEUP, 2))
        return lineup
        
        
    def getMediaTypes(self):
        mediaType = {}
        for type in self.categoryMenu:
            type = type[0]
            if type == 'Movies': mediaType[type] = 'movie'
            elif type == 'TV': mediaType[type] = 'episodes'
            elif type == 'Music + Radio': mediaType[type] = 'musicvideo'
            else: mediaType[type] = 'video'
        return mediaType
            
            
    def browse(self, chname, url):
        log('browse, chname = ' + chname)
        geowarn = False
        data = (self.openURL(url))
        for channel in data:
            id      = channel['_id']
            cat     = channel['category']
            number  = channel['number']
            region  = channel['regionFilter']['include']
            exclude = channel['regionFilter']['exclude']
            name    = channel['name']
            plot    = channel['description']
            feat    = (channel.get('featured','') or 0) == -1
     
            if self.filter == True and (self.region in exclude or self.region not in region):
                if geowarn == False:
                    geowarn = True
                    xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30004), ICON, 4000)
                continue
            
            thumb = ICON
            if 'thumbnail' in channel: thumb = (channel['thumbnail'].get('path',ICON) or ICON)
            land = FANART
            if 'featuredImage' in channel: land = (channel['featuredImage'].get('path',FANART) or FANART)
            logo = ICON
            if 'logo' in channel: logo   = (channel['logo']['path'] or ICON)
            if chname == "All Channels":
                title = "%s - %s: %s" % (cat, number, name)
                infoLabels ={"mediatype":self.mediaType[cat],"label":title ,"title":title  ,"plot":plot, "code":number, "genre":cat, "imdbnumber":id}
                infoArt    ={"thumb":thumb,"poster":thumb,"fanart":land,"icon":logo,"logo":logo}
                self.addDir(title, id, 8, infoLabels, infoArt)
            elif chname == "Featured" and feat == True:
                title = "%s - %s: %s" % (cat, number, name)
                infoLabels ={"mediatype":self.mediaType[cat],"label":title ,"title":title  ,"plot":plot, "code":number, "genre":cat, "imdbnumber":id}
                infoArt    ={"thumb":thumb,"poster":thumb,"fanart":land,"icon":logo,"logo":logo}
                self.addDir(title, id, 8, infoLabels, infoArt)
            elif chname.lower() == cat.lower():
                title = "%s: %s" % (number, name)
                infoLabels ={"mediatype":self.mediaType[cat],"label":title ,"title":title  ,"plot":plot, "code":number, "genre":cat, "imdbnumber":id}
                infoArt    ={"thumb":thumb,"poster":thumb,"fanart":land,"icon":logo,"logo":logo}
                self.addDir(title, id, 8, infoLabels, infoArt)
            
            
    def pagination(self, seq, rowlen):
        for start in xrange(0, len(seq), rowlen): yield seq[start:start+rowlen]

            
    def browseGuide(self, start=0, end=14):
        log('browseGuide')
        geowarn = False
        start   = 0 if start == BASE_LINEUP else int(start)
        data    = list(self.pagination((self.openURL(BASE_LINEUP)), end))
        start   = 0 if start >= len(data) else start
        link    = self.getGuidedata()
        if start == 0 and end == 14: self.addDir(LANGUAGE(30014), '', 10)
        for channel in data[start]:
            chid    = channel['_id']
            chcat   = channel['category']
            chnum   = channel['number']
            region  = channel['regionFilter']['include']
            exclude = channel['regionFilter']['exclude']
            chname  = channel['name']
            chplot  = channel['description']
            chthumb = ICON
            if 'thumbnail' in channel: chthumb = ((channel['thumbnail'].get('path','')).replace(' ','%20') or ICON)
            print chnum, chthumb
            feat = (channel.get('featured','') or 0) == -1
            if self.filter == True and (self.region in exclude or self.region not in region):
                if geowarn == False:
                    geowarn = True
                    xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30004), ICON, 4000)
                continue

            item = link[chid]
            if len(item) == 0: continue
            item      = item[0]
            epid      = (item['episode']['_id'])
            epname    = item['episode']['name']
            epplot    = (item['episode'].get('description',epname) or epname)
            epgenre   = (item['episode'].get('genre',chcat) or chcat)
            epdur     = int(item['episode'].get('duration','0') or '0') // 1000
            live      = item['episode']['liveBroadcast']
            thumb     = chthumb #(item['episode']['thumbnail']['path'] or chthumb) #site doesn't update missing episode thumbs
            title     = "%s: %s - %s" % (chnum, chname, epname)
            if any(k.lower().startswith(title.lower()) for k in IGNORE_KEYS): continue
            infoLabels ={"mediatype":self.mediaType[chcat],"label":title ,"title":title  ,"plot":epplot, "code":epid, "genre":epgenre, "imdbnumber":chid, "duration":epdur}
            infoArt    ={"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON}
            self.addLink(title, chid, 9, infoLabels, infoArt, end)
        start += 1
        if end == 14: self.addDir(LANGUAGE(30015), '%s'%(start), 0)
    
    
    def playChannel(self, name, url):
        log('playChannel')
        origurl  = url
        if PTVL_RUN: self.playContent(name, url)
        link = self.getGuidedata()
        item = link[origurl][0]
        id = item['episode']['_id']
        ch_start = datetime.datetime.fromtimestamp(time.mktime(time.strptime((item["start"].split('.')[0]), "%Y-%m-%dT%H:%M:%S")))
        ch_timediff = (datetime.datetime.now() - ch_start).seconds
        dur_sum  = 0
        playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
        playlist.clear()
        xbmc.sleep(100)
        for idx, field in enumerate(self.openURL(BASE_CLIPS %(id))):
            url       = (field['url'] or field['code'])
            name      = field['name']
            thumb     = (field['thumbnail'] or ICON)
            provider  = field['provider']
            url       = self.resolveURL(provider, url)
            dur       = int(field['duration'] or '0') // 1000
            dur_start = dur_sum
            dur_sum  += dur
            liz=xbmcgui.ListItem(name, path=url)
            infoList = {"mediatype":"video","label":name,"title":name,"duration":dur}
            infoArt  = {"thumb":thumb,"poster":thumb,"icon":ICON,"fanart":FANART}
            liz.setInfo(type="Video", infoLabels=infoList)
            liz.setArt(infoArt)
            liz.setProperty("IsPlayable","true")
            liz.setProperty("IsInternetStream",str(field['liveBroadcast']).lower())
            if 'm3u8' in url.lower() and inputstreamhelper.Helper('hls').check_inputstream():
                liz.setProperty('inputstreamaddon','inputstream.adaptive')
                liz.setProperty('inputstream.adaptive.manifest_type','hls')
            if dur_start < ch_timediff and dur_sum > ch_timediff:
                vid_offset = ch_timediff - dur_start
                liz.setProperty('ResumeTime', str(vid_offset))
            playlist.add(url, liz, idx)
            if idx == 0: xbmcplugin.setResolvedUrl(int(self.sysARG[1]), True, liz)
     
     
    def playContent(self, name, url):
        log('playContent')
        origurl = url
        link = self.getGuidedata()
        try: item = link[origurl][0]
        except Exception as e: return log('playContent, failed! ' + str(e) + ', origurl = ' + str(link.get(origurl,[EMPTY])), xbmc.LOGERROR)
        id = item['episode']['_id']
        ch_start = datetime.datetime.fromtimestamp(time.mktime(time.strptime((item["start"].split('.')[0]), "%Y-%m-%dT%H:%M:%S")))
        ch_timediff = (datetime.datetime.now() - ch_start).seconds
        data = (self.openURL(BASE_CLIPS %(id)))
        dur_sum  = 0
        for idx, field in enumerate(data):
            url       = (field['url'] or field['code'])
            name      = field['name']
            thumb     = (field['thumbnail'] or ICON)
            provider  = (field['provider']  or None)
            url       = urllib.quote(json.dumps({"provider":provider,"url":url}))
            dur       = int(field['duration'] or '0') // 1000
            dur_start = dur_sum
            dur_sum  += dur
            if any(k.lower().startswith(name.lower()) for k in IGNORE_KEYS): continue
            infoList = {"mediatype":"video","label":name,"title":name,"duration":dur}
            infoArt  = {"thumb":thumb,"poster":thumb,"icon":ICON,"fanart":FANART}
            if PTVL_RUN: self.playVideo(name, url)
            else: self.addLink(name, url, 7, infoList, infoArt, len(data))
            
           
    @use_cache(1)
    def resolveURL(self, provider, url):
        log('resolveURL, provider = ' + str(provider) + ', url = ' + url)
        if provider == 'jwplatform' or 'm3u8' in url.lower() or url is None: return url
        elif provider == 'youtube':
            url = url.replace('feature=player_embedded&','')
            if len(re.findall('http[s]?://www.youtube.com/watch', url)) > 0: return YTURL + url.split('/watch?v=')[1]
            elif len(re.findall('http[s]?://youtu.be/', url)) > 0: return YTURL + url.split('/youtu.be/')[1]
        elif provider == 'vimeo':
            if len(re.findall('http[s]?://vimeo.com/', url)) > 0: return VMURL + url.split('/vimeo.com/')[1]
        else:
            info = None
            if isUWP() == False: 
                from YDStreamExtractor import getVideoInfo
                info = getVideoInfo(url,3,True)
            if info is None: return YTURL + 'W6FjQgmtt0k'
            info = info.streams()
            return info[0]['xbmc_url']

            
    def playVideo(self, name, url, liz=None):
        log('playVideo')
        url = json.loads(urllib.unquote(url))
        provider = url['provider']
        url = url['url']
        if liz is None: liz = xbmcgui.ListItem(name, path=self.resolveURL(provider, url))
        if 'm3u8' in url.lower() and inputstreamhelper.Helper('hls').check_inputstream():
            liz.setProperty('inputstreamaddon','inputstream.adaptive')
            liz.setProperty('inputstream.adaptive.manifest_type','hls')
        xbmcplugin.setResolvedUrl(int(self.sysARG[1]), True, liz)

           
    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true') 
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=self.sysARG[0]+"?url="+urllib.quote(u)+"&mode="+str(mode)+"&name="+urllib.quote(name)
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),url=u,listitem=liz,totalItems=total)


    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name} )
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=self.sysARG[0]+"?url="+urllib.quote(u)+"&mode="+str(mode)+"&name="+urllib.quote(name)
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),url=u,listitem=liz,isFolder=True)


    def poolList(self, method, items):
        results = []
        if ENABLE_POOL:
            pool = ThreadPool(cpu_count())
            results = pool.imap_unordered(method, items)
            pool.close()
            pool.join()
        else: results = [method(item) for item in items]
        results = filter(None, results)
        return results
        
        
    def getGuidedata(self):
        return (self.openURL(BASE_GUIDE % (datetime.datetime.now().strftime('%Y-%m-%dT%H:00:00'),(datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%dT%H:00:00')), life=datetime.timedelta(hours=6)))
        
        
    @buildChannels({'refresh_path':urllib.quote(json.dumps("plugin://%s?mode=20"%ADDON_ID)),'refresh_interval':"7200"})
    def uEPG(self):
        log('uEPG')
        #support for uEPG universal epg framework module available from the Kodi repository. https://github.com/Lunatixz/KODI_Addons/tree/master/script.module.uepg
        data      = (self.openURL(BASE_LINEUP))
        self.link = self.getGuidedata()
        return [self.buildGuide(channel) for channel in data]
        
        
    def buildGuide(self, channel):
        chthumb    = ''
        chlogo     = ''
        chid       = channel['_id']
        chcat      = channel['category']
        chnum      = channel['number']
        region     = channel['regionFilter']['include']
        exclude    = channel['regionFilter']['exclude']
        chname     = channel['name']
        chplot     = channel['description']
        isFavorite = False #(channel.get('featured','') or 0) == -1
        if self.filter == True and (self.region in exclude or self.region not in region): return
        if 'thumbnail' in channel: chthumb = (channel['thumbnail'].get('path','') or '')
        if 'logo' in channel: chlogo = (channel['logo'].get('path','') or '')
        log('buildGuide, channel = ' + str(chnum))
            
        newChannel = {}
        guidedata  = []
        newChannel['channelname']   = chname
        newChannel['channelnumber'] = chnum
        newChannel['channellogo']   = chlogo
        newChannel['isfavorite']    = isFavorite
        for i in range(len(self.link.get(chid,[]))):
            item      = self.link[chid][i]
            epname    = item['episode']['name']
            epid      = (item['episode']['_id'])
            epplot    = (item['episode'].get('description',epname) or epname)
            epgenre   = (item['episode'].get('genre',chcat)        or chcat)
            epsubgenre= (item['episode'].get('subGenre','')        or '')
            genre     = '%s + %s'%(epgenre, epsubgenre) if len(epsubgenre) > 0 else epgenre
            epdur     = int(item['episode'].get('duration','0') or '0') // 1000
            live      = item['episode']['liveBroadcast'] == "true"
            thumb     = chthumb
            poster    = (item['episode'].get('thumbnail','').get('path',chthumb) or chthumb)
            clips     = self.link[chid]
            
            if len(clips) == 0: return
            tmpdata = {}
            clips   = clips[0]
            id      = clips['episode']['_id']
            data    = (self.openURL(BASE_CLIPS %(id)))
            for field in data:
                url       = (field['url'] or field['code'])
                name      = field['name']
                thumb     = (field['thumbnail'] or ICON)
                provider  = (field['provider']  or None)
                url       = urllib.quote(json.dumps({"provider":provider,"url":url}))
                dur       = int(field['duration'] or '0') // 1000
                title     = "%s: %s" %(chname, epname)
                if any(k.lower().startswith(title.lower()) for k in IGNORE_KEYS): return
                tmpdata = {"mediatype":self.mediaType[chcat],"label":title,"title":chname,"originaltitle":epname,"plot":epplot, "code":epid, "genre":chcat, "imdbnumber":chid, "duration":dur}
                tmpdata['starttime'] = int(time.mktime(time.strptime((item["start"].split('.')[0]), "%Y-%m-%dT%H:%M:%S")))
                tmpdata['url']       = self.sysARG[0]+'?mode=7&name=%s&url=%s'%(title,url)
                tmpdata['art']       = {"thumb":thumb,"clearart":poster,"fanart":FANART,"icon":chthumb,"clearlogo":chlogo}
                guidedata.append(tmpdata)
        newChannel['guidedata'] = guidedata
        return newChannel
     

    def getParams(self):
        return dict(urlparse.parse_qsl(self.sysARG[2][1:]))

            
    def run(self):  
        params=self.getParams()
        try: url=urllib.unquote_plus(params["url"])
        except: url=None
        try: name=urllib.unquote_plus(params["name"])
        except: name=None
        try: mode=int(params["mode"])
        except: mode=None
        log("Mode: "+str(mode))
        log("URL : "+str(url))
        log("Name: "+str(name))

        if mode==None:   self.mainMenu()
        elif mode == 0:  self.browseGuide(url)
        elif mode == 1:  self.browseMenu()
        elif mode == 2:  self.browse(name, url)
        elif mode == 7:  self.playVideo(name, url)
        elif mode == 8:  self.playContent(name, url)
        elif mode == 9:  self.playChannel(name, url)
        elif mode == 10: self.browseGuide(end=5000)
        elif mode == 20: self.uEPG()
        # elif mode == 20: xbmc.executebuiltin("RunScript(script.module.uepg,json=%s&skin_path=%s&refresh_path=%s&refresh_interval=%s&row_count=%s)"%(urllib.quote(json.dumps(list(self.uEPG()))),urllib.quote(json.dumps(ADDON_PATH)),urllib.quote(json.dumps(self.sysARG[0]+"?mode=20")),"7200","5"))

        xbmcplugin.setContent(int(self.sysARG[1])    , CONTENT_TYPE)
        xbmcplugin.addSortMethod(int(self.sysARG[1]) , xbmcplugin.SORT_METHOD_UNSORTED)
        xbmcplugin.addSortMethod(int(self.sysARG[1]) , xbmcplugin.SORT_METHOD_NONE)
        xbmcplugin.addSortMethod(int(self.sysARG[1]) , xbmcplugin.SORT_METHOD_LABEL)
        xbmcplugin.addSortMethod(int(self.sysARG[1]) , xbmcplugin.SORT_METHOD_TITLE)
        xbmcplugin.endOfDirectory(int(self.sysARG[1]), cacheToDisc=False)
Exemple #28
0
class Tmdb(object):
    '''get metadata from tmdb'''
    api_key = None

    def __init__(self, simplecache=None):
        '''Initialize - optionaly provide simplecache object'''
        if not simplecache:
            from simplecache import SimpleCache
            self.cache = SimpleCache()
        else:
            self.cache = simplecache
        addon = xbmcaddon.Addon(id=ADDON_ID)
        self.api_key = addon.getSetting("tmdb_apikey")
        del addon

    def search_movie(self, title, year="", manual_select=False):
        '''
            Search tmdb for a specific movie, returns full details of best match
            parameters:
            title: (required) the title of the movie to search for
            year: (optional) the year of the movie to search for (enhances search result if supplied)
            manual_select: (optional) if True will show select dialog with all results
        '''
        details = self.select_best_match(self.search_movies(title, year), manual_select=manual_select)
        if details:
            details = self.get_movie_details(details["id"])
        return details

    @use_cache(30)
    def search_movieset(self, title):
        '''search for movieset details providing the title of the set'''
        details = {}
        params = {"query": title, "language": KODI_LANGUAGE}
        result = self.get_data("search/collection", params)
        if result:
            set_id = result[0]["id"]
            details = self.get_movieset_details(set_id)
        return details

    @use_cache(4)
    def search_tvshow(self, title, year="", manual_select=False):
        '''
            Search tmdb for a specific movie, returns full details of best match
            parameters:
            title: (required) the title of the movie to search for
            year: (optional) the year of the movie to search for (enhances search result if supplied)
            manual_select: (optional) if True will show select dialog with all results
        '''
        details = self.select_best_match(self.search_tvshows(title, year), manual_select=manual_select)
        if details:
            details = self.get_tvshow_details(details["id"])
        return details

    @use_cache(4)
    def search_video(self, title, prefyear="", preftype="", manual_select=False):
        '''
            Search tmdb for a specific entry (can be movie or tvshow), returns full details of best match
            parameters:
            title: (required) the title of the movie/tvshow to search for
            prefyear: (optional) prefer result if year matches
            preftype: (optional) prefer result if type matches
            manual_select: (optional) if True will show select dialog with all results
        '''
        results = self.search_videos(title)
        details = self.select_best_match(results, prefyear=prefyear, preftype=preftype,
                                         preftitle=title, manual_select=manual_select)
        if details and details["media_type"] == "movie":
            details = self.get_movie_details(details["id"])
        elif details and "tv" in details["media_type"]:
            details = self.get_tvshow_details(details["id"])
        return details

    @use_cache(4)
    def search_videos(self, title):
        '''
            Search tmdb for a specific entry (can be movie or tvshow), parameters:
            title: (required) the title of the movie/tvshow to search for
        '''
        results = []
        page = 1
        maxpages = 5
        while page < maxpages:
            params = {"query": title, "language": KODI_LANGUAGE, "page": page}
            subresults = self.get_data("search/multi", params)
            page += 1
            if subresults:
                for item in subresults:
                    if item["media_type"] in ["movie", "tv"]:
                        results.append(item)
            else:
                break
        return results

    @use_cache(4)
    def search_movies(self, title, year=""):
        '''
            Search tmdb for a specific movie, returns a list of all closest matches
            parameters:
            title: (required) the title of the movie to search for
            year: (optional) the year of the movie to search for (enhances search result if supplied)
        '''
        params = {"query": title, "language": KODI_LANGUAGE}
        if year:
            params["year"] = try_parse_int(year)
        return self.get_data("search/movie", params)

    @use_cache(4)
    def search_tvshows(self, title, year=""):
        '''
            Search tmdb for a specific tvshow, returns a list of all closest matches
            parameters:
            title: (required) the title of the tvshow to search for
            year: (optional) the first air date year of the tvshow to search for (enhances search result if supplied)
        '''
        params = {"query": title, "language": KODI_LANGUAGE}
        if year:
            params["first_air_date_year"] = try_parse_int(year)
        return self.get_data("search/tv", params)

    def get_actor(self, name):
        '''
            Search tmdb for a specific actor/person, returns the best match as kodi compatible dict
            required parameter: name --> the name of the person
        '''
        params = {"query": name, "language": KODI_LANGUAGE}
        result = self.get_data("search/person", params)
        if result:
            result = result[0]
            cast_thumb = "http://image.tmdb.org/t/p/original%s" % result[
                "profile_path"] if result["profile_path"] else ""
            item = {"name": result["name"],
                    "thumb": cast_thumb,
                    "roles": [item["title"] if item.get("title") else item["name"] for item in result["known_for"]]}
            return item
        else:
            return {}

    def get_movie_details(self, movie_id):
        '''get all moviedetails'''
        params = {
            "append_to_response": "keywords,videos,credits,images",
            "include_image_language": "%s,en" % KODI_LANGUAGE,
            "language": KODI_LANGUAGE
        }
        return self.map_details(self.get_data("movie/%s" % movie_id, params), "movie")

    def get_movieset_details(self, movieset_id):
        '''get all moviesetdetails'''
        details = {"art": {}}
        params = {"language": KODI_LANGUAGE}
        result = self.get_data("collection/%s" % movieset_id, params)
        if result:
            details["title"] = result["name"]
            details["plot"] = result["overview"]
            details["tmdb_id"] = result["id"]
            details["art"]["poster"] = "http://image.tmdb.org/t/p/original%s" % result["poster_path"]
            details["art"]["fanart"] = "http://image.tmdb.org/t/p/original%s" % result["backdrop_path"]
            details["totalmovies"] = len(result["parts"])
        return details

    def get_tvshow_details(self, tvshow_id):
        '''get all tvshowdetails'''
        params = {
            "append_to_response": "keywords,videos,external_ids,credits,images",
            "include_image_language": "%s,en" % KODI_LANGUAGE,
            "language": KODI_LANGUAGE
        }
        return self.map_details(self.get_data("tv/%s" % tvshow_id, params), "tvshow")

    def get_videodetails_by_externalid(self, extid, extid_type):
        '''get metadata by external ID (like imdbid)'''
        params = {"external_source": extid_type, "language": KODI_LANGUAGE}
        results = self.get_data("find/%s" % extid, params)
        if results and results["movie_results"]:
            return self.get_movie_details(results["movie_results"][0]["id"])
        elif results and results["tv_results"]:
            return self.get_tvshow_details(results["tv_results"][0]["id"])
        return {}

    def get_data(self, endpoint, params):
        '''helper method to get data from tmdb json API'''
        if self.api_key:
            params["api_key"] = self.api_key
            rate_limit = None
            expiration = datetime.timedelta(days=7)
        else:
            params["api_key"] = "ae06df54334aa653354e9a010f4b81cb"
            # without personal api key = rate limiting and older info from cache
            rate_limit = ("themoviedb.org",10)
            expiration = datetime.timedelta(days=60)
        cachestr = "tmdb.%s" % params.itervalues()
        cache = self.cache.get(cachestr)
        if cache:
            # data obtained from cache
            result = cache
        else:
            # no cache, grab data from API
            url = u'http://api.themoviedb.org/3/%s' % endpoint
            result = get_json(url, params)
            # make sure that we have a plot value (if localized value fails, fallback to english)
            if result and "language" in params and "overview" in result:
                if not result["overview"] and params["language"] != "en":
                    params["language"] = "en"
                    result2 = get_json(url, params)
                    if result2 and result2.get("overview"):
                        result = result2
            self.cache.set(url, result, expiration=expiration)
        return result

    def map_details(self, data, media_type):
        '''helper method to map the details received from tmdb to kodi compatible formatting'''
        if not data:
            return {}
        details = {}
        details["tmdb_id"] = data["id"]
        details["rating"] = data["vote_average"]
        details["votes"] = data["vote_count"]
        details["rating.tmdb"] = data["vote_average"]
        details["votes.tmdb"] = data["vote_count"]
        details["popularity"] = data["popularity"]
        details["popularity.tmdb"] = data["popularity"]
        details["plot"] = data["overview"]
        details["genre"] = [item["name"] for item in data["genres"]]
        details["homepage"] = data["homepage"]
        details["status"] = data["status"]
        details["cast"] = []
        details["castandrole"] = []
        details["writer"] = []
        details["director"] = []
        details["media_type"] = media_type
        # cast
        if "credits" in data:
            if "cast" in data["credits"]:
                for cast_member in data["credits"]["cast"]:
                    cast_thumb = ""
                    if cast_member["profile_path"]:
                        cast_thumb = "http://image.tmdb.org/t/p/original%s" % cast_member["profile_path"]
                    details["cast"].append({"name": cast_member["name"], "role": cast_member["character"],
                                            "thumbnail": cast_thumb})
                    details["castandrole"].append((cast_member["name"], cast_member["character"]))
            # crew (including writers and directors)
            if "crew" in data["credits"]:
                for crew_member in data["credits"]["crew"]:
                    cast_thumb = ""
                    if crew_member["profile_path"]:
                        cast_thumb = "http://image.tmdb.org/t/p/original%s" % crew_member["profile_path"]
                    if crew_member["job"] in ["Author", "Writer"]:
                        details["writer"].append(crew_member["name"])
                    if crew_member["job"] in ["Producer", "Executive Producer"]:
                        details["director"].append(crew_member["name"])
                    if crew_member["job"] in ["Producer", "Executive Producer", "Author", "Writer"]:
                        details["cast"].append({"name": crew_member["name"], "role": crew_member["job"],
                                                "thumbnail": cast_thumb})
        # artwork
        details["art"] = {}
        if data.get("images"):
            if data["images"].get("backdrops"):
                fanarts = self.get_best_images(data["images"]["backdrops"])
                details["art"]["fanarts"] = fanarts
                details["art"]["fanart"] = fanarts[0] if fanarts else ""
            if data["images"].get("posters"):
                posters = self.get_best_images(data["images"]["posters"])
                details["art"]["posters"] = posters
                details["art"]["poster"] = posters[0] if posters else ""
        if not details["art"].get("poster") and data.get("poster_path"):
            details["art"]["poster"] = "http://image.tmdb.org/t/p/original%s" % data["poster_path"]
        if not details["art"].get("fanart") and data.get("backdrop_path"):
            details["art"]["fanart"] = "http://image.tmdb.org/t/p/original%s" % data["backdrop_path"]
        # movies only
        if media_type == "movie":
            details["title"] = data["title"]
            details["originaltitle"] = data["original_title"]
            if data["belongs_to_collection"]:
                details["set"] = data["belongs_to_collection"].get("name", "")
            if data.get("release_date"):
                details["premiered"] = data["release_date"]
                details["year"] = try_parse_int(data["release_date"].split("-")[0])
            details["tagline"] = data["tagline"]
            if data["runtime"]:
                details["runtime"] = data["runtime"] * 60
            details["imdbnumber"] = data["imdb_id"]
            details["budget"] = data["budget"]
            details["budget.formatted"] = int_with_commas(data["budget"])
            details["revenue"] = data["revenue"]
            details["revenue.formatted"] = int_with_commas(data["revenue"])
            if data.get("production_companies"):
                details["studio"] = [item["name"] for item in data["production_companies"]]
            if data.get("production_countries"):
                details["country"] = [item["name"] for item in data["production_countries"]]
            if data.get("keywords"):
                details["tag"] = [item["name"] for item in data["keywords"]["keywords"]]
        # tvshows only
        if media_type == "tvshow":
            details["title"] = data["name"]
            details["originaltitle"] = data["original_name"]
            if data.get("created_by"):
                details["director"] += [item["name"] for item in data["created_by"]]
            if data.get("episode_run_time"):
                details["runtime"] = data["episode_run_time"][0] * 60
            if data.get("first_air_date"):
                details["premiered"] = data["first_air_date"]
                details["year"] = try_parse_int(data["first_air_date"].split("-")[0])
            if "last_air_date" in data:
                details["lastaired"] = data["last_air_date"]
            if data.get("networks"):
                details["studio"] = [item["name"] for item in data["networks"]]
            if "origin_country" in data:
                details["country"] = data["origin_country"]
            if data.get("external_ids"):
                details["imdbnumber"] = data["external_ids"].get("imdb_id", "")
                details["tvdb_id"] = data["external_ids"].get("tvdb_id", "")
            if "results" in data["keywords"]:
                details["tag"] = [item["name"] for item in data["keywords"]["results"]]
        # trailer
        for video in data["videos"]["results"]:
            if video["site"] == "YouTube" and video["type"] == "Trailer":
                details["trailer"] = 'plugin://plugin.video.youtube/?action=play_video&videoid=%s' % video["key"]
                break
        return details

    @staticmethod
    def get_best_images(images):
        '''get the best 5 images based on number of likes and the language'''
        for image in images:
            score = 0
            score += image["vote_count"]
            score += image["vote_average"] * 10
            score += image["height"]
            if "iso_639_1" in image:
                if image["iso_639_1"] == KODI_LANGUAGE:
                    score += 1000
            image["score"] = score
            if not image["file_path"].startswith("http"):
                image["file_path"] = "http://image.tmdb.org/t/p/original%s" % image["file_path"]
        images = sorted(images, key=itemgetter("score"), reverse=True)
        return [image["file_path"] for image in images]

    @staticmethod
    def select_best_match(results, prefyear="", preftype="", preftitle="", manual_select=False):
        '''helper to select best match or let the user manually select the best result from the search'''
        details = {}
        # score results if one or more preferences are given
        if results and (prefyear or preftype or preftitle):
            newdata = []
            preftitle = preftitle.lower()
            for item in results:
                item["score"] = 0
                itemtitle = item["title"] if item.get("title") else item["name"]
                itemtitle = itemtitle.lower()
                itemorgtitle = item["original_title"] if item.get("original_title") else item["original_name"]
                itemorgtitle = itemorgtitle.lower()

                # high score if year matches
                if prefyear:
                    if item.get("first_air_date") and prefyear in item["first_air_date"]:
                        item["score"] += 800  # matches preferred year
                    if item.get("release_date") and prefyear in item["release_date"]:
                        item["score"] += 800  # matches preferred year

                # find exact match on title
                if preftitle and preftitle == itemtitle:
                    item["score"] += 1000  # exact match!
                if preftitle and preftitle == itemorgtitle:
                    item["score"] += 1000  # exact match!

                # match title by replacing some characters
                if preftitle and get_compare_string(preftitle) == get_compare_string(itemtitle):
                    item["score"] += 750
                if preftitle and get_compare_string(preftitle) == get_compare_string(itemorgtitle):
                    item["score"] += 750

                # add SequenceMatcher score to the results
                if preftitle:
                    stringmatchscore = SM(None, preftitle, itemtitle).ratio(
                    ) + SM(None, preftitle, itemorgtitle).ratio()
                    if stringmatchscore > 1.6:
                        item["score"] += stringmatchscore * 250

                # higher score if result ALSO matches our preferred type or native language
                # (only when we already have a score)
                if item["score"]:
                    if preftype and (item["media_type"] in preftype) or (preftype in item["media_type"]):
                        item["score"] += 250  # matches preferred type
                    if item["original_language"] == KODI_LANGUAGE:
                        item["score"] += 500  # native language!
                    if KODI_LANGUAGE.upper() in item.get("origin_country", []):
                        item["score"] += 500  # native language!
                    if KODI_LANGUAGE in item.get("languages", []):
                        item["score"] += 500  # native language!

                if item["score"] > 500 or manual_select:
                    newdata.append(item)
            results = sorted(newdata, key=itemgetter("score"), reverse=True)

        if results and manual_select:
            # show selectdialog to manually select the item
            results_list = []
            for item in results:
                title = item["name"] if "name" in item else item["title"]
                if item.get("premiered"):
                    year = item["premiered"].split("-")[0]
                else:
                    year = item.get("first_air_date", "").split("-")[0]
                if item["poster_path"]:
                    thumb = "http://image.tmdb.org/t/p/original%s" % item["poster_path"]
                else:
                    thumb = ""
                label = "%s (%s) - %s" % (title, year, item["media_type"])
                listitem = xbmcgui.ListItem(label=label, iconImage=thumb, label2=item["overview"])
                results_list.append(listitem)
            if manual_select and results_list:
                dialog = DialogSelect("DialogSelect.xml", "", listing=results_list, window_title="%s - TMDB"
                                      % xbmc.getLocalizedString(283))
                dialog.doModal()
                selected_item = dialog.result
                del dialog
                if selected_item != -1:
                    details = results[selected_item]
                else:
                    results = []

        if not details and results:
            # just grab the first item as best match
            details = results[0]
        return details
Exemple #29
0
 def __init__(self):
     log('__init__')
     self.cache = SimpleCache()
Exemple #30
0
 def __init__(self):
     log('__init__')
     self.cache     = SimpleCache()
     self.stateMenu = self.getStates()
class PluginContent:
    '''Hidden plugin entry point providing some helper features'''
    params = {}
    win = None

    def __init__(self):
        self.cache = SimpleCache()
        self.mutils = MetadataUtils()
        self.win = xbmcgui.Window(10000)
        try:
            self.params = dict(
                urlparse.parse_qsl(sys.argv[2].replace(
                    '?', '').lower().decode("utf-8")))
            log_msg("plugin called with parameters: %s" % self.params)
            self.main()
        except Exception as exc:
            log_exception(__name__, exc)
            xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

        # cleanup when done processing
        self.close()

    def close(self):
        '''Cleanup Kodi Cpython instances'''
        self.cache.close()
        self.mutils.close()
        del self.mutils
        del self.win

    def main(self):
        '''main action, load correct function'''
        action = self.params.get("action", "")
        if self.win.getProperty("SkinHelperShutdownRequested"):
            # do not proceed if kodi wants to exit
            log_msg(
                "%s --> Not forfilling request: Kodi is exiting" % __name__,
                xbmc.LOGWARNING)
            xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
        else:
            try:
                if hasattr(self.__class__, action):
                    # launch module for action provided by this plugin
                    getattr(self, action)()
                else:
                    # legacy (widget) path called !!!
                    self.load_widget()
            except Exception as exc:
                log_exception(__name__, exc)

    def load_widget(self):
        '''legacy entrypoint called (widgets are moved to seperate addon), start redirect...'''
        action = self.params.get("action", "")
        newaddon = "script.skin.helper.widgets"
        log_msg(
            "Deprecated method: %s. Please reassign your widgets to get rid of this message. -"
            "This automatic redirect will be removed in the future" % (action),
            xbmc.LOGWARNING)
        paramstring = ""
        for key, value in self.params.iteritems():
            paramstring += ",%s=%s" % (key, value)
        if getCondVisibility("System.HasAddon(%s)" % newaddon):
            # TEMP !!! for backwards compatability reasons only - to be removed in the near future!!
            import imp
            addon = xbmcaddon.Addon(newaddon)
            addon_path = addon.getAddonInfo('path').decode("utf-8")
            imp.load_source('plugin', os.path.join(addon_path, "plugin.py"))
            from plugin import main
            main.Main()
            del addon
        else:
            # trigger install of the addon
            if KODI_VERSION > 16:
                xbmc.executebuiltin("InstallAddon(%s)" % newaddon)
            else:
                xbmc.executebuiltin("RunPlugin(plugin://%s)" % newaddon)

    def playchannel(self):
        '''play channel from widget helper'''
        params = {"item": {"channelid": int(self.params["channelid"])}}
        self.mutils.kodidb.set_json("Player.Open", params)

    def playrecording(self):
        '''retrieve the recording and play to get resume working'''
        recording = self.mutils.kodidb.recording(self.params["recordingid"])
        params = {"item": {"recordingid": recording["recordingid"]}}
        self.mutils.kodidb.set_json("Player.Open", params)
        # manually seek because passing resume to the player json cmd doesn't seem to work
        if recording["resume"].get("position"):
            for i in range(50):
                if getCondVisibility("Player.HasVideo"):
                    break
                xbmc.sleep(50)
            xbmc.Player().seekTime(recording["resume"].get("position"))

    def launch(self):
        '''launch any builtin action using a plugin listitem'''
        if "runscript" in self.params["path"]:
            self.params["path"] = self.params["path"].replace("?", ",")
        xbmc.executebuiltin(self.params["path"])

    def playalbum(self):
        '''helper to play an entire album'''
        xbmc.executeJSONRPC(
            '{ "jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "albumid": %d } }, "id": 1 }'
            % int(self.params["albumid"]))

    def smartshortcuts(self):
        '''called from skinshortcuts to retrieve listing of all smart shortcuts'''
        import skinshortcuts
        skinshortcuts.get_smartshortcuts(self.params.get("path", ""))

    @staticmethod
    def backgrounds():
        '''called from skinshortcuts to retrieve listing of all backgrounds'''
        import skinshortcuts
        skinshortcuts.get_backgrounds()

    def widgets(self):
        '''called from skinshortcuts to retrieve listing of all widgetss'''
        import skinshortcuts
        skinshortcuts.get_widgets(self.params.get("path", ""),
                                  self.params.get("sublevel", ""))

    def resourceimages(self):
        '''retrieve listing of specific resource addon images'''
        from resourceaddons import get_resourceimages
        addontype = self.params.get("addontype", "")
        for item in get_resourceimages(addontype, True):
            listitem = xbmcgui.ListItem(item[0],
                                        label2=item[2],
                                        path=item[1],
                                        iconImage=item[3])
            xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                        url=item[1],
                                        listitem=listitem,
                                        isFolder=False)
        xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

    def extrafanart(self):
        '''helper to display extrafanart in multiimage control in the skin'''
        fanarts = eval(self.params["fanarts"])
        # process extrafanarts
        for count, item in enumerate(fanarts):
            listitem = xbmcgui.ListItem("fanart%s" % count, path=item)
            listitem.setProperty('mimetype', 'image/jpeg')
            xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                        url=item,
                                        listitem=listitem)
        xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

    def extraposter(self):
        '''helper to display extraposter in multiimage control in the skin'''
        posters = eval(self.params["posters"])
        # process extraposters
        for count, item in enumerate(posters):
            listitem = xbmcgui.ListItem("poster%s" % count, path=item)
            listitem.setProperty('mimetype', 'image/jpeg')
            xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                        url=item,
                                        listitem=listitem)
        xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

    def genrebackground(self):
        '''helper to display images for a specific genre in multiimage control in the skin'''
        genre = self.params.get("genre").split(".")[0]
        arttype = self.params.get("arttype", "fanart")
        randomize = self.params.get("random", "false") == "true"
        mediatype = self.params.get("mediatype", "movies")
        if genre and genre != "..":
            filters = [{"operator": "is", "field": "genre", "value": genre}]
            if randomize:
                sort = {"method": "random", "order": "descending"}
            else:
                sort = {"method": "sorttitle", "order": "ascending"}
            items = getattr(self.mutils.kodidb, mediatype)(sort=sort,
                                                           filters=filters,
                                                           limits=(0, 50))
            for item in items:
                image = self.mutils.get_clean_image(item["art"].get(
                    arttype, ""))
                if image:
                    image = self.mutils.get_clean_image(item["art"][arttype])
                    listitem = xbmcgui.ListItem(image, path=image)
                    listitem.setProperty('mimetype', 'image/jpeg')
                    xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                                url=image,
                                                listitem=listitem)
        xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

    def getcastmedia(self):
        '''helper to display get all media for a specific actor'''
        name = self.params.get("name")
        if name:
            all_items = self.mutils.kodidb.castmedia(name)
            all_items = self.mutils.process_method_on_list(
                self.mutils.kodidb.prepare_listitem, all_items)
            all_items = self.mutils.process_method_on_list(
                self.mutils.kodidb.create_listitem, all_items)
            xbmcplugin.addDirectoryItems(int(sys.argv[1]), all_items,
                                         len(all_items))
        xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

    def getcast(self):
        '''helper to get all cast for a given media item'''
        db_id = None
        all_cast = []
        all_cast_names = list()
        cache_str = ""
        download_thumbs = self.params.get("downloadthumbs", "") == "true"
        extended_cast_action = self.params.get("castaction",
                                               "") == "extendedinfo"
        movie = self.params.get("movie")
        tvshow = self.params.get("tvshow")
        episode = self.params.get("episode")
        movieset = self.params.get("movieset")

        try:  # try to parse db_id
            if movieset:
                cache_str = "movieset.castcache-%s-%s" % (
                    self.params["movieset"], download_thumbs)
                db_id = int(movieset)
            elif tvshow:
                cache_str = "tvshow.castcache-%s-%s" % (self.params["tvshow"],
                                                        download_thumbs)
                db_id = int(tvshow)
            elif movie:
                cache_str = "movie.castcache-%s-%s" % (self.params["movie"],
                                                       download_thumbs)
                db_id = int(movie)
            elif episode:
                cache_str = "episode.castcache-%s-%s" % (
                    self.params["episode"], download_thumbs)
                db_id = int(episode)
        except Exception:
            pass

        cachedata = self.cache.get(cache_str)
        if cachedata:
            # get data from cache
            all_cast = cachedata
        else:
            # retrieve data from json api...
            if movie and db_id:
                all_cast = self.mutils.kodidb.movie(db_id)["cast"]
            elif movie and not db_id:
                filters = [{
                    "operator": "is",
                    "field": "title",
                    "value": movie
                }]
                result = self.mutils.kodidb.movies(filters=filters)
                all_cast = result[0]["cast"] if result else []
            elif tvshow and db_id:
                all_cast = self.mutils.kodidb.tvshow(db_id)["cast"]
            elif tvshow and not db_id:
                filters = [{
                    "operator": "is",
                    "field": "title",
                    "value": tvshow
                }]
                result = self.mutils.kodidb.tvshows(filters=filters)
                all_cast = result[0]["cast"] if result else []
            elif episode and db_id:
                all_cast = self.mutils.kodidb.episode(db_id)["cast"]
            elif episode and not db_id:
                filters = [{
                    "operator": "is",
                    "field": "title",
                    "value": episode
                }]
                result = self.mutils.kodidb.episodes(filters=filters)
                all_cast = result[0]["cast"] if result else []
            elif movieset:
                if not db_id:
                    for item in self.mutils.kodidb.moviesets():
                        if item["title"].lower() == movieset.lower():
                            db_id = item["setid"]
                if db_id:
                    json_result = self.mutils.kodidb.movieset(
                        db_id, include_set_movies_fields=["cast"])
                    if "movies" in json_result:
                        for movie in json_result['movies']:
                            all_cast += movie['cast']

            # optional: download missing actor thumbs
            if all_cast and download_thumbs:
                for cast in all_cast:
                    if cast.get("thumbnail"):
                        cast["thumbnail"] = self.mutils.get_clean_image(
                            cast.get("thumbnail"))
                    if not cast.get("thumbnail"):
                        artwork = self.mutils.tmdb.get_actor(cast["name"])
                        cast["thumbnail"] = artwork.get("thumb", "")
            # lookup tmdb if item is requested that is not in local db
            if not all_cast:
                tmdbdetails = {}
                if movie and not db_id:
                    tmdbdetails = self.mutils.tmdb.search_movie(movie)
                elif tvshow and not db_id:
                    tmdbdetails = self.mutils.tmdb.search_tvshow(tvshow)
                if tmdbdetails.get("cast"):
                    all_cast = tmdbdetails["cast"]
            # save to cache
            self.cache.set(cache_str, all_cast)

        # process listing with the results...
        for cast in all_cast:
            if cast.get("name") not in all_cast_names:
                liz = xbmcgui.ListItem(label=cast.get("name"),
                                       label2=cast.get("role"),
                                       iconImage=cast.get("thumbnail"))
                if extended_cast_action:
                    url = "RunScript(script.extendedinfo,info=extendedactorinfo,name=%s)" % cast.get(
                        "name")
                    url = "plugin://script.skin.helper.service/?action=launch&path=%s" % url
                    is_folder = False
                else:
                    url = "RunScript(script.skin.helper.service,action=getcastmedia,name=%s)" % cast.get(
                        "name")
                    url = "plugin://script.skin.helper.service/?action=launch&path=%s" % urlencode(
                        url)
                    is_folder = False
                all_cast_names.append(cast.get("name"))
                liz.setThumbnailImage(cast.get("thumbnail"))
                xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                            url=url,
                                            listitem=liz,
                                            isFolder=is_folder)
        xbmcplugin.endOfDirectory(int(sys.argv[1]))

    @staticmethod
    def alphabet():
        '''display an alphabet scrollbar in listings'''
        all_letters = []
        if xbmc.getInfoLabel("Container.NumItems"):
            for i in range(int(xbmc.getInfoLabel("Container.NumItems"))):
                all_letters.append(
                    xbmc.getInfoLabel("Listitem(%s).SortLetter" % i).upper())
            start_number = ""
            for number in ["2", "3", "4", "5", "6", "7", "8", "9"]:
                if number in all_letters:
                    start_number = number
                    break
            for letter in [
                    start_number, "A", "B", "C", "D", "E", "F", "G", "H", "I",
                    "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
                    "V", "W", "X", "Y", "Z"
            ]:
                if letter == start_number:
                    label = "#"
                else:
                    label = letter
                listitem = xbmcgui.ListItem(label=label)
                if letter not in all_letters:
                    lipath = "noop"
                    listitem.setProperty("NotAvailable", "true")
                else:
                    lipath = "plugin://script.skin.helper.service/?action=alphabetletter&letter=%s" % letter
                xbmcplugin.addDirectoryItem(int(sys.argv[1]),
                                            lipath,
                                            listitem,
                                            isFolder=False)
        xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

    def alphabetletter(self):
        '''used with the alphabet scrollbar to jump to a letter'''
        if KODI_VERSION > 16:
            xbmcplugin.setResolvedUrl(handle=int(sys.argv[1]),
                                      succeeded=False,
                                      listitem=xbmcgui.ListItem())
        letter = self.params.get("letter", "").upper()
        jumpcmd = ""
        if letter in ["A", "B", "C", "2"]:
            jumpcmd = "2"
        elif letter in ["D", "E", "F", "3"]:
            jumpcmd = "3"
        elif letter in ["G", "H", "I", "4"]:
            jumpcmd = "4"
        elif letter in ["J", "K", "L", "5"]:
            jumpcmd = "5"
        elif letter in ["M", "N", "O", "6"]:
            jumpcmd = "6"
        elif letter in ["P", "Q", "R", "S", "7"]:
            jumpcmd = "7"
        elif letter in ["T", "U", "V", "8"]:
            jumpcmd = "8"
        elif letter in ["W", "X", "Y", "Z", "9"]:
            jumpcmd = "9"
        if jumpcmd:
            xbmc.executebuiltin("SetFocus(50)")
            for i in range(40):
                xbmc.executeJSONRPC(
                    '{ "jsonrpc": "2.0", "method": "Input.ExecuteAction",\
                    "params": { "action": "jumpsms%s" }, "id": 1 }' %
                    (jumpcmd))
                xbmc.sleep(50)
                if xbmc.getInfoLabel("ListItem.Sortletter").upper() == letter:
                    break
class KodiDb(object):
    '''various methods and helpers to get data from kodi json api'''
    def __init__(self, simplecache=None):
        '''Initialize - optionaly provide simplecache object'''
        if not simplecache:
            from simplecache import SimpleCache
            self.cache = SimpleCache()
        else:
            self.cache = simplecache

    def movie(self, db_id):
        '''get moviedetails from kodi db'''
        return self.get_json("VideoLibrary.GetMovieDetails",
                             returntype="moviedetails",
                             fields=FIELDS_MOVIES,
                             optparam=("movieid", try_parse_int(db_id)))

    def movies(self, sort=None, filters=None, limits=None, filtertype=None):
        '''get moviedetails from kodi db'''
        return self.get_json("VideoLibrary.GetMovies",
                             sort=sort,
                             filters=filters,
                             fields=FIELDS_MOVIES,
                             limits=limits,
                             returntype="movies",
                             filtertype=filtertype)

    def movie_by_imdbid(self, imdb_id):
        '''gets a movie from kodidb by imdbid.'''
        # apparently you can't filter on imdb so we have to do this the complicated way
        if KODI_VERSION > 16:
            # from Kodi 17 we have a uniqueid field instead of imdbnumber
            all_items = self.cache.get("kodidb.all_movies_uniqueids")
            if not all_items:
                all_items = self.get_json('VideoLibrary.GetMovies',
                                          fields=["uniqueid"],
                                          returntype="movies")
                self.cache.set("kodidb.all_movies_uniqueids",
                               all_items,
                               expiration=datetime.timedelta(minutes=15))

            for item in all_items:
                for item2 in item["uniqueid"].values():
                    if item2 == imdb_id:
                        return self.movie(item["movieid"])
        else:
            all_items = self.get_json('VideoLibrary.GetMovies',
                                      fields=["imdbnumber"],
                                      returntype="movies")
            for item in all_items:
                if item["imdbnumber"] == imdb_id:
                    return self.movie(item["movieid"])
        return {}

    def tvshow(self, db_id):
        '''get tvshow from kodi db'''
        tvshow = self.get_json("VideoLibrary.GetTvShowDetails",
                               returntype="tvshowdetails",
                               fields=FIELDS_TVSHOWS,
                               optparam=("tvshowid", try_parse_int(db_id)))
        return self.tvshow_watchedcounts(tvshow)

    def tvshows(self, sort=None, filters=None, limits=None, filtertype=None):
        '''get tvshows from kodi db'''
        tvshows = self.get_json("VideoLibrary.GetTvShows",
                                sort=sort,
                                filters=filters,
                                fields=FIELDS_TVSHOWS,
                                limits=limits,
                                returntype="tvshows",
                                filtertype=filtertype)
        # append watched counters
        for tvshow in tvshows:
            tvshow = self.tvshow_watchedcounts(tvshow)
        return tvshows

    def tvshow_by_imdbid(self, imdb_id):
        '''gets a tvshow from kodidb by imdbid (or tvdbid).'''
        # apparently you can't filter on imdb so we have to do this the complicated way
        if KODI_VERSION > 16:
            # from Kodi 17 we have a uniqueid field instead of imdbnumber
            all_items = self.get_json('VideoLibrary.GetTvShows',
                                      fields=["uniqueid"],
                                      returntype="tvshows")
            for item in all_items:
                for item2 in item["uniqueid"].values():
                    if item2 == imdb_id:
                        return self.tvshow(item["tvshowid"])
        else:
            # pre-kodi 17 approach
            all_items = self.get_json('VideoLibrary.GetTvShows',
                                      fields=["imdbnumber"],
                                      returntype="tvshows")
            for item in all_items:
                if item["imdbnumber"] == imdb_id:
                    return self.tvshow(item["tvshowid"])
        return {}

    def episode(self, db_id):
        '''get episode from kodi db'''
        return self.get_json("VideoLibrary.GetEpisodeDetails",
                             returntype="episodedetails",
                             fields=FIELDS_EPISODES,
                             optparam=("episodeid", try_parse_int(db_id)))

    def episodes(self,
                 sort=None,
                 filters=None,
                 limits=None,
                 filtertype=None,
                 tvshowid=None,
                 fields=FIELDS_EPISODES):
        '''get episodes from kodi db'''
        if tvshowid:
            params = ("tvshowid", try_parse_int(tvshowid))
        else:
            params = None
        return self.get_json("VideoLibrary.GetEpisodes",
                             sort=sort,
                             filters=filters,
                             fields=fields,
                             limits=limits,
                             returntype="episodes",
                             filtertype=filtertype,
                             optparam=params)

    def musicvideo(self, db_id):
        '''get musicvideo from kodi db'''
        return self.get_json("VideoLibrary.GetMusicVideoDetails",
                             returntype="musicvideodetails",
                             fields=FIELDS_MUSICVIDEOS,
                             optparam=("musicvideoid", try_parse_int(db_id)))

    def musicvideos(self,
                    sort=None,
                    filters=None,
                    limits=None,
                    filtertype=None):
        '''get musicvideos from kodi db'''
        return self.get_json("VideoLibrary.GetMusicVideos",
                             sort=sort,
                             filters=filters,
                             fields=FIELDS_MUSICVIDEOS,
                             limits=limits,
                             returntype="musicvideos",
                             filtertype=filtertype)

    def movieset(self, db_id, include_set_movies_fields=""):
        '''get movieset from kodi db'''
        if include_set_movies_fields:
            optparams = [("setid", try_parse_int(db_id)),
                         ("movies", {
                             "properties": include_set_movies_fields
                         })]
        else:
            optparams = ("setid", try_parse_int(db_id))
        return self.get_json("VideoLibrary.GetMovieSetDetails",
                             returntype="",
                             fields=["title", "art", "playcount"],
                             optparam=optparams)

    def moviesets(self, sort=None, limits=None, include_set_movies=False):
        '''get moviesetdetails from kodi db'''
        if include_set_movies:
            optparam = ("movies", {"properties": FIELDS_MOVIES})
        else:
            optparam = None
        return self.get_json("VideoLibrary.GetMovieSets",
                             sort=sort,
                             fields=["title", "art", "playcount"],
                             limits=limits,
                             returntype="",
                             optparam=optparam)

    def files(self, vfspath, sort=None, limits=None):
        '''gets all items in a kodi vfs path'''
        return self.get_json("Files.GetDirectory",
                             returntype="",
                             optparam=("directory", vfspath),
                             fields=FIELDS_FILES,
                             sort=sort,
                             limits=limits)

    def genres(self, media_type):
        '''return all genres for the given media type (movie/tvshow/musicvideo)'''
        return self.get_json("VideoLibrary.GetGenres",
                             fields=["thumbnail", "title"],
                             returntype="genres",
                             optparam=("type", media_type))

    def song(self, db_id):
        '''get songdetails from kodi db'''
        return self.get_json("AudioLibrary.GetSongDetails",
                             returntype="songdetails",
                             fields=FIELDS_SONGS,
                             optparam=("songid", try_parse_int(db_id)))

    def songs(self, sort=None, filters=None, limits=None, filtertype=None):
        '''get songs from kodi db'''
        return self.get_json("AudioLibrary.GetSongs",
                             sort=sort,
                             filters=filters,
                             fields=FIELDS_SONGS,
                             limits=limits,
                             returntype="songs",
                             filtertype=filtertype)

    def album(self, db_id):
        '''get albumdetails from kodi db'''
        album = self.get_json("AudioLibrary.GetAlbumDetails",
                              returntype="albumdetails",
                              fields=FIELDS_ALBUMS,
                              optparam=("albumid", try_parse_int(db_id)))
        # override type as the kodi json api is returning the album type instead of mediatype
        album["type"] = "album"
        return album

    def albums(self, sort=None, filters=None, limits=None, filtertype=None):
        '''get albums from kodi db'''
        albums = self.get_json("AudioLibrary.GetAlbums",
                               sort=sort,
                               filters=filters,
                               fields=FIELDS_ALBUMS,
                               limits=limits,
                               returntype="albums",
                               filtertype=filtertype)
        # override type as the kodi json api is returning the album type instead of mediatype
        for album in albums:
            album["type"] = "album"
        return albums

    def artist(self, db_id):
        '''get artistdetails from kodi db'''
        return self.get_json("AudioLibrary.GetArtistDetails",
                             returntype="artistdetails",
                             fields=FIELDS_ARTISTS,
                             optparam=("artistid", try_parse_int(db_id)))

    def artists(self, sort=None, filters=None, limits=None, filtertype=None):
        '''get artists from kodi db'''
        return self.get_json("AudioLibrary.GetArtists",
                             sort=sort,
                             filters=filters,
                             fields=FIELDS_ARTISTS,
                             limits=limits,
                             returntype="artists",
                             filtertype=filtertype)

    def recording(self, db_id):
        '''get pvr recording from kodi db'''
        return self.get_json("PVR.GetRecordingDetails",
                             returntype="recordingdetails",
                             fields=FIELDS_RECORDINGS,
                             optparam=("recordingid", try_parse_int(db_id)))

    def recordings(self, limits=None):
        '''get pvr recordings from kodi db'''
        return self.get_json("PVR.GetRecordings",
                             fields=FIELDS_RECORDINGS,
                             limits=limits,
                             returntype="recordings")

    def channel(self, db_id):
        '''get pvr channel from kodi db'''
        return self.get_json("PVR.GetChannelDetails",
                             returntype="channeldetails",
                             fields=FIELDS_CHANNELS,
                             optparam=("channelid", try_parse_int(db_id)))

    def channels(self, limits=None, channelgroupid="alltv"):
        '''get pvr channels from kodi db'''
        return self.get_json("PVR.GetChannels",
                             fields=FIELDS_CHANNELS,
                             limits=limits,
                             returntype="channels",
                             optparam=("channelgroupid", channelgroupid))

    def channelgroups(self, limits=None, channeltype="tv"):
        '''get pvr channelgroups from kodi db'''
        return self.get_json("PVR.GetChannelGroups",
                             fields=[],
                             limits=limits,
                             returntype="channelgroups",
                             optparam=("channeltype", channeltype))

    def timers(self, limits=None):
        '''get pvr recordings from kodi db'''
        fields = [
            "title", "endtime", "starttime", "channelid", "summary", "file"
        ]
        return self.get_json("PVR.GetTimers",
                             fields=fields,
                             limits=limits,
                             returntype="timers")

    def favourites(self):
        '''get kodi favourites'''
        items = self.get_favourites_from_file()
        if not items:
            fields = ["path", "thumbnail", "window", "windowparameter"]
            optparams = ("type", None)
            items = self.get_json("Favourites.GetFavourites",
                                  fields=fields,
                                  optparam=optparams)
        return items

    def castmedia(self, actorname):
        '''helper to display all media (movies/shows) for a specific actor'''
        # use db counts as simple checksum
        all_items = []
        filters = [{
            "operator": "contains",
            "field": "actor",
            "value": actorname
        }]
        all_items = self.movies(filters=filters)
        for item in self.tvshows(filters=filters):
            item["file"] = "videodb://tvshows/titles/%s" % item["tvshowid"]
            item["isFolder"] = True
            all_items.append(item)
        return all_items

    def actors(self):
        '''return all actors'''
        all_items = []
        all_actors = []
        result = self.files("videodb://movies/actors")
        result += self.files("videodb://tvshows/actors")
        for item in result:
            if not item["label"] in all_actors:
                all_actors.append(item["label"])
                item["type"] = "actor"
                item["isFolder"] = True
                if not item["art"].get("thumb"):
                    item["art"]["thumb"] = "DefaultActor.png"
                all_items.append(item)
        return sorted(all_items, key=itemgetter("label"))

    @staticmethod
    def set_json(jsonmethod, params):
        '''method to set info in the kodi json api'''
        kodi_json = {}
        kodi_json["jsonrpc"] = "2.0"
        kodi_json["method"] = jsonmethod
        kodi_json["params"] = params
        kodi_json["id"] = 1
        json_response = xbmc.executeJSONRPC(try_encode(json.dumps(kodi_json)))
        return json.loads(json_response.decode('utf-8', 'replace'))

    @staticmethod
    def get_json(jsonmethod,
                 sort=None,
                 filters=None,
                 fields=None,
                 limits=None,
                 returntype=None,
                 optparam=None,
                 filtertype=None):
        '''method to get details from the kodi json api'''
        kodi_json = {}
        kodi_json["jsonrpc"] = "2.0"
        kodi_json["method"] = jsonmethod
        kodi_json["params"] = {}
        if optparam:
            if isinstance(optparam, list):
                for param in optparam:
                    kodi_json["params"][param[0]] = param[1]
            else:
                kodi_json["params"][optparam[0]] = optparam[1]
        kodi_json["id"] = 1
        if sort:
            kodi_json["params"]["sort"] = sort
        if filters:
            if not filtertype:
                filtertype = "and"
            if len(filters) > 1:
                kodi_json["params"]["filter"] = {filtertype: filters}
            else:
                kodi_json["params"]["filter"] = filters[0]
        if fields:
            kodi_json["params"]["properties"] = fields
        if limits:
            kodi_json["params"]["limits"] = {
                "start": limits[0],
                "end": limits[1]
            }
        json_response = xbmc.executeJSONRPC(try_encode(json.dumps(kodi_json)))
        json_object = json.loads(json_response.decode('utf-8', 'replace'))
        # set the default returntype to prevent errors
        if "details" in jsonmethod.lower():
            result = {}
        else:
            result = []
        if 'result' in json_object:
            if returntype and returntype in json_object['result']:
                # returntype specified, return immediately
                result = json_object['result'][returntype]
            else:
                # no returntype specified, we'll have to look for it
                for key, value in json_object['result'].iteritems():
                    if not key == "limits" and (isinstance(value, list)
                                                or isinstance(value, dict)):
                        result = value
        else:
            log_msg(json_response)
            log_msg(kodi_json)
        return result

    @staticmethod
    def get_favourites_from_file():
        '''json method for favourites doesn't return all items (such as android apps) so retrieve them from file'''
        allfavourites = []
        try:
            from xml.dom.minidom import parse
            favourites_path = xbmc.translatePath(
                'special://profile/favourites.xml').decode("utf-8")
            if xbmcvfs.exists(favourites_path):
                doc = parse(favourites_path)
                result = doc.documentElement.getElementsByTagName('favourite')
                for fav in result:
                    action = fav.childNodes[0].nodeValue
                    action = action.replace('"', '')
                    label = fav.attributes['name'].nodeValue
                    try:
                        thumb = fav.attributes['thumb'].nodeValue
                    except Exception:
                        thumb = ""
                    window = ""
                    windowparameter = ""
                    action_type = "unknown"
                    if action.startswith("StartAndroidActivity"):
                        action_type = "androidapp"
                    elif action.startswith("ActivateWindow"):
                        action_type = "window"
                        actionparts = action.replace("ActivateWindow(",
                                                     "").replace(
                                                         ",return)",
                                                         "").split(",")
                        window = actionparts[0]
                        if len(actionparts) > 1:
                            windowparameter = actionparts[1]
                    elif action.startswith("PlayMedia"):
                        action_type = "media"
                        action = action.replace("PlayMedia(", "")[:-1]
                    allfavourites.append({
                        "label": label,
                        "path": action,
                        "thumbnail": thumb,
                        "window": window,
                        "windowparameter": windowparameter,
                        "type": action_type
                    })
        except Exception as exc:
            log_exception(__name__, exc)
        return allfavourites

    @staticmethod
    def create_listitem(item, as_tuple=True, offscreen=True):
        '''helper to create a kodi listitem from kodi compatible dict with mediainfo'''
        try:
            if KODI_VERSION > 17:
                liz = xbmcgui.ListItem(label=item.get("label", ""),
                                       label2=item.get("label2", ""),
                                       path=item['file'],
                                       offscreen=offscreen)
            else:
                liz = xbmcgui.ListItem(label=item.get("label", ""),
                                       label2=item.get("label2", ""),
                                       path=item['file'])

            # only set isPlayable prop if really needed
            if item.get("isFolder", False):
                liz.setProperty('IsPlayable', 'false')
            elif "plugin://script.skin.helper" not in item['file']:
                liz.setProperty('IsPlayable', 'true')

            nodetype = "Video"
            if item["type"] in ["song", "album", "artist"]:
                nodetype = "Music"

            # extra properties
            for key, value in item["extraproperties"].iteritems():
                liz.setProperty(key, value)

            # video infolabels
            if nodetype == "Video":
                infolabels = {
                    "title": item.get("title"),
                    "size": item.get("size"),
                    "genre": item.get("genre"),
                    "year": item.get("year"),
                    "top250": item.get("top250"),
                    "tracknumber": item.get("tracknumber"),
                    "rating": item.get("rating"),
                    "playcount": item.get("playcount"),
                    "overlay": item.get("overlay"),
                    "cast": item.get("cast"),
                    "castandrole": item.get("castandrole"),
                    "director": item.get("director"),
                    "mpaa": item.get("mpaa"),
                    "plot": item.get("plot"),
                    "plotoutline": item.get("plotoutline"),
                    "originaltitle": item.get("originaltitle"),
                    "sorttitle": item.get("sorttitle"),
                    "duration": item.get("duration"),
                    "studio": item.get("studio"),
                    "tagline": item.get("tagline"),
                    "writer": item.get("writer"),
                    "tvshowtitle": item.get("tvshowtitle"),
                    "premiered": item.get("premiered"),
                    "status": item.get("status"),
                    "code": item.get("imdbnumber"),
                    "imdbnumber": item.get("imdbnumber"),
                    "aired": item.get("aired"),
                    "credits": item.get("credits"),
                    "album": item.get("album"),
                    "artist": item.get("artist"),
                    "votes": item.get("votes"),
                    "trailer": item.get("trailer")
                }
                if item["type"] == "episode":
                    infolabels["season"] = item["season"]
                    infolabels["episode"] = item["episode"]

                # streamdetails
                if item.get("streamdetails"):
                    liz.addStreamInfo("video",
                                      item["streamdetails"].get("video", {}))
                    liz.addStreamInfo("audio",
                                      item["streamdetails"].get("audio", {}))
                    liz.addStreamInfo(
                        "subtitle", item["streamdetails"].get("subtitle", {}))

                if "dateadded" in item:
                    infolabels["dateadded"] = item["dateadded"]
                if "date" in item:
                    infolabels["date"] = item["date"]

            # music infolabels
            else:
                infolabels = {
                    "title": item.get("title"),
                    "size": item.get("size"),
                    "genre": item.get("genre"),
                    "year": item.get("year"),
                    "tracknumber": item.get("track"),
                    "album": item.get("album"),
                    "artist": " / ".join(item.get('artist')),
                    "rating": str(item.get("rating", 0)),
                    "lyrics": item.get("lyrics"),
                    "playcount": item.get("playcount")
                }
                if "date" in item:
                    infolabels["date"] = item["date"]
                if "duration" in item:
                    infolabels["duration"] = item["duration"]
                if "lastplayed" in item:
                    infolabels["lastplayed"] = item["lastplayed"]

            # setting the dbtype and dbid is supported from kodi krypton and up
            if KODI_VERSION > 16 and item["type"] not in [
                    "recording", "channel", "favourite"
            ]:
                infolabels["mediatype"] = item["type"]
                # setting the dbid on music items is not supported ?
                if nodetype == "Video" and "DBID" in item["extraproperties"]:
                    infolabels["dbid"] = item["extraproperties"]["DBID"]

            if "lastplayed" in item:
                infolabels["lastplayed"] = item["lastplayed"]

            # assign the infolabels
            liz.setInfo(type=nodetype, infoLabels=infolabels)

            # artwork
            liz.setArt(item.get("art", {}))
            if "icon" in item:
                liz.setIconImage(item['icon'])
            if "thumbnail" in item:
                liz.setThumbnailImage(item['thumbnail'])

            # contextmenu
            if item["type"] in ["episode", "season"
                                ] and "season" in item and "tvshowid" in item:
                # add series and season level to widgets
                if "contextmenu" not in item:
                    item["contextmenu"] = []
                item["contextmenu"] += [
                    (xbmc.getLocalizedString(20364),
                     "ActivateWindow(Video,videodb://tvshows/titles/%s/,return)"
                     % (item["tvshowid"])),
                    (xbmc.getLocalizedString(20373),
                     "ActivateWindow(Video,videodb://tvshows/titles/%s/%s/,return)"
                     % (item["tvshowid"], item["season"]))
                ]
            if "contextmenu" in item:
                liz.addContextMenuItems(item["contextmenu"])

            if as_tuple:
                return (item["file"], liz, item.get("isFolder", False))
            else:
                return liz
        except Exception as exc:
            log_exception(__name__, exc)
            log_msg(item)
            return None

    @staticmethod
    def prepare_listitem(item):
        '''helper to convert kodi output from json api to compatible format for listitems'''
        try:
            # fix values returned from json to be used as listitem values
            properties = item.get("extraproperties", {})

            # set type
            for idvar in [('episode', 'DefaultTVShows.png'),
                          ('tvshow', 'DefaultTVShows.png'),
                          ('movie', 'DefaultMovies.png'),
                          ('song', 'DefaultAudio.png'),
                          ('album', 'DefaultAudio.png'),
                          ('artist', 'DefaultArtist.png'),
                          ('musicvideo', 'DefaultMusicVideos.png'),
                          ('recording', 'DefaultTVShows.png'),
                          ('channel', 'DefaultAddonPVRClient.png')]:
                dbid = item.get(idvar[0] + "id")
                if dbid:
                    properties["DBID"] = str(dbid)
                    if not item.get("type"):
                        item["type"] = idvar[0]
                    if not item.get("icon"):
                        item["icon"] = idvar[1]
                    break

            # general properties
            if "genre" in item and isinstance(item['genre'], list):
                item["genre"] = " / ".join(item['genre'])
            if "studio" in item and isinstance(item['studio'], list):
                item["studio"] = " / ".join(item['studio'])
            if "writer" in item and isinstance(item['writer'], list):
                item["writer"] = " / ".join(item['writer'])
            if 'director' in item and isinstance(item['director'], list):
                item["director"] = " / ".join(item['director'])
            if 'artist' in item and not isinstance(item['artist'], list):
                item["artist"] = [item['artist']]
            if 'artist' not in item:
                item["artist"] = []
            if item['type'] == "album" and 'album' not in item and 'label' in item:
                item['album'] = item['label']
            if "duration" not in item and "runtime" in item:
                if (item["runtime"] / 60) > 300:
                    item["duration"] = item["runtime"] / 60
                else:
                    item["duration"] = item["runtime"]
            if "plot" not in item and "comment" in item:
                item["plot"] = item["comment"]
            if "tvshowtitle" not in item and "showtitle" in item:
                item["tvshowtitle"] = item["showtitle"]
            if "premiered" not in item and "firstaired" in item:
                item["premiered"] = item["firstaired"]
            if "firstaired" in item and "aired" not in item:
                item["aired"] = item["firstaired"]
            if "imdbnumber" not in properties and "imdbnumber" in item:
                properties["imdbnumber"] = item["imdbnumber"]
            if "imdbnumber" not in properties and "uniqueid" in item:
                for value in item["uniqueid"].values():
                    if value.startswith("tt"):
                        properties["imdbnumber"] = value

            properties["dbtype"] = item["type"]
            properties["DBTYPE"] = item["type"]
            properties["type"] = item["type"]
            properties["path"] = item.get("file")

            # cast
            list_cast = []
            list_castandrole = []
            item["cast_org"] = item.get("cast", [])
            if "cast" in item and isinstance(item["cast"], list):
                for castmember in item["cast"]:
                    if isinstance(castmember, dict):
                        list_cast.append(castmember.get("name", ""))
                        list_castandrole.append(
                            (castmember["name"], castmember["role"]))
                    else:
                        list_cast.append(castmember)
                        list_castandrole.append((castmember, ""))

            item["cast"] = list_cast
            item["castandrole"] = list_castandrole

            if "season" in item and "episode" in item:
                properties["episodeno"] = "s%se%s" % (item.get("season"),
                                                      item.get("episode"))
            if "resume" in item:
                properties["resumetime"] = str(item['resume']['position'])
                properties["totaltime"] = str(item['resume']['total'])
                properties['StartOffset'] = str(item['resume']['position'])

            # streamdetails
            if "streamdetails" in item:
                streamdetails = item["streamdetails"]
                audiostreams = streamdetails.get('audio', [])
                videostreams = streamdetails.get('video', [])
                subtitles = streamdetails.get('subtitle', [])
                if len(videostreams) > 0:
                    stream = videostreams[0]
                    height = stream.get("height", "")
                    width = stream.get("width", "")
                    if height and width:
                        resolution = ""
                        if width <= 720 and height <= 480:
                            resolution = "480"
                        elif width <= 768 and height <= 576:
                            resolution = "576"
                        elif width <= 960 and height <= 544:
                            resolution = "540"
                        elif width <= 1280 and height <= 720:
                            resolution = "720"
                        elif width <= 1920 and height <= 1080:
                            resolution = "1080"
                        elif width * height >= 6000000:
                            resolution = "4K"
                        properties["VideoResolution"] = resolution
                    if stream.get("codec", ""):
                        properties["VideoCodec"] = str(stream["codec"])
                    if stream.get("aspect", ""):
                        properties["VideoAspect"] = str(
                            round(stream["aspect"], 2))
                    item["streamdetails"]["video"] = stream

                # grab details of first audio stream
                if len(audiostreams) > 0:
                    stream = audiostreams[0]
                    properties["AudioCodec"] = stream.get('codec', '')
                    properties["AudioChannels"] = str(
                        stream.get('channels', ''))
                    properties["AudioLanguage"] = stream.get('language', '')
                    item["streamdetails"]["audio"] = stream

                # grab details of first subtitle
                if len(subtitles) > 0:
                    properties["SubtitleLanguage"] = subtitles[0].get(
                        'language', '')
                    item["streamdetails"]["subtitle"] = subtitles[0]
            else:
                item["streamdetails"] = {}
                item["streamdetails"]["video"] = {
                    'duration': item.get('duration', 0)
                }

            # additional music properties
            if 'album_description' in item:
                properties["Album_Description"] = item.get('album_description')

            # pvr properties
            if "starttime" in item:
                # convert utc time to local time
                item["starttime"] = localdate_from_utc_string(
                    item["starttime"])
                item["endtime"] = localdate_from_utc_string(item["endtime"])
                # set some localized versions of the time and date as additional properties
                startdate, starttime = localized_date_time(item['starttime'])
                enddate, endtime = localized_date_time(item['endtime'])
                properties["StartTime"] = starttime
                properties["StartDate"] = startdate
                properties["EndTime"] = endtime
                properties["EndDate"] = enddate
                properties["Date"] = "%s %s-%s" % (startdate, starttime,
                                                   endtime)
                properties["StartDateTime"] = "%s %s" % (startdate, starttime)
                properties["EndDateTime"] = "%s %s" % (enddate, endtime)
                # set date to startdate
                item["date"] = arrow.get(
                    item["starttime"]).format("DD.MM.YYYY")
            if "channellogo" in item:
                properties["channellogo"] = item["channellogo"]
                properties["channelicon"] = item["channellogo"]
            if "episodename" in item:
                properties["episodename"] = item["episodename"]
            if "channel" in item:
                properties["channel"] = item["channel"]
                properties["channelname"] = item["channel"]
                item["label2"] = item["title"]

            # artwork
            art = item.get("art", {})
            if item["type"] in ["episode", "season"]:
                if not art.get("fanart") and art.get("season.fanart"):
                    art["fanart"] = art["season.fanart"]
                if not art.get("poster") and art.get("season.poster"):
                    art["poster"] = art["season.poster"]
                if not art.get("landscape") and art.get("season.landscape"):
                    art["poster"] = art["season.landscape"]
                if not art.get("fanart") and art.get("tvshow.fanart"):
                    art["fanart"] = art.get("tvshow.fanart")
                if not art.get("poster") and art.get("tvshow.poster"):
                    art["poster"] = art.get("tvshow.poster")
                if not art.get("clearlogo") and art.get("tvshow.clearlogo"):
                    art["clearlogo"] = art.get("tvshow.clearlogo")
                if not art.get("banner") and art.get("tvshow.banner"):
                    art["banner"] = art.get("tvshow.banner")
                if not art.get("landscape") and art.get("tvshow.landscape"):
                    art["landscape"] = art.get("tvshow.landscape")
            if not art.get("fanart") and item.get('fanart'):
                art["fanart"] = item.get('fanart')
            if not art.get("thumb") and item.get('thumbnail'):
                art["thumb"] = get_clean_image(item.get('thumbnail'))
            if not art.get("thumb") and art.get('poster'):
                art["thumb"] = get_clean_image(art.get('poster'))
            if not art.get("thumb") and item.get('icon'):
                art["thumb"] = get_clean_image(item.get('icon'))
            if not item.get("thumbnail") and art.get('thumb'):
                item["thumbnail"] = art["thumb"]

            # clean art
            for key, value in art.iteritems():
                if not isinstance(value, (str, unicode)):
                    art[key] = ""
                elif value:
                    art[key] = get_clean_image(value)
            item["art"] = art

            item["extraproperties"] = properties

            if "file" not in item:
                log_msg("Item is missing file path ! --> %s" % item["label"],
                        xbmc.LOGWARNING)
                item["file"] = ""

            # return the result
            return item

        except Exception as exc:
            log_exception(__name__, exc)
            log_msg(item)
            return None

    @staticmethod
    def tvshow_watchedcounts(tvshow):
        '''append watched counts to tvshow details'''
        tvshow["extraproperties"] = {
            "totalseasons": str(tvshow["season"]),
            "totalepisodes": str(tvshow["episode"]),
            "watchedepisodes": str(tvshow["watchedepisodes"]),
            "unwatchedepisodes":
            str(tvshow["episode"] - tvshow["watchedepisodes"])
        }
        return tvshow
Exemple #33
0
 def __init__(self):
     self.cache   = SimpleCache()
     self.sources = self.openURL(SOURCES_URL).get('sources','')
IMAGE_PATH = os.path.join(ADDONPATH, 'resources', 'skins', 'Default', 'media')

# Onli load master menu
BASE_URL = 'menu'
EPG_MENU = 'tablet=1'
LIVETV_PATH = 'menu/livetv_alternative'
SITE_LOGIN_PAGE = SITE_PATH + 'user/signin'
SITE_LOGOUT_PAGE = SITE_PATH + 'logout'

# VIEW #
WIDTH = 1280
HEIGHT = 720
TIMEBAR_HEIGHT = int(float(WIDTH / 32))
TV_LOGO_WIDTH = (HEIGHT - TIMEBAR_HEIGHT) / CHANNELS_PER_PAGE

CACHE = SimpleCache()
# dialog 					= xbmcgui.Dialog()

##########################################################################################
##									INFO OBJECT 										##
##########################################################################################


class ControlAndInfo(object):
    def __init__(self, control, info):
        self.control = control
        if 'title' in info: self.title = info['title'].encode('utf-8')
        if 'is_visible' in info: self.is_visible = info['is_visible']
        if 'url' in info: self.url = info['url']
        if 'pos' in info: self.pos = info['pos']
        if 'sec_controls' in info: self.sec_controls = info['sec_controls']
Exemple #35
0
class CBS(object):
    def __init__(self):
        log('__init__')
        self.cache = SimpleCache()

    def openURL(self, url):
        log('openURL, url = ' + str(url))
        try:
            cacheResponse = self.cache.get(ADDON_NAME +
                                           '.openURL, url = %s' % url)
            if not cacheResponse:
                request = urllib2.Request(url)
                cacheResponse = urllib2.urlopen(request,
                                                timeout=TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s' % url,
                               cacheResponse,
                               expiration=datetime.timedelta(hours=1))
            return cacheResponse
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
        xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
        return ''

    def buildMenu(self, items):
        for item in items:
            self.addDir(*item)
        self.addYoutube("Youtube", 'plugin://plugin.video.youtube/user/CBS/')

    def browseLatest(self, page=0):
        items = json.loads(self.openURL(LATEST_JSON % page))
        if 'result' not in items: return
        for item in items['result']['data']:
            if item['status'] != "AVAILABLE": continue
            seasonNumber = 0
            episodeNumber = 0
            label = uni(item.get('title') or item['label'])
            plot = uni((item.get('description', '') or label))
            try:
                aired = item['airdate_iso'].split('T')[0]
            except:
                aired = datetime.datetime.now().strftime('%Y-%m-%d')
            thumb = item['thumbUrl']
            url = item['url']
            if not url.startswith('http://'):
                url = (BASE_URL + '%s' % url).lstrip('/')
            seasonNumber = (int(
                filter(str.isdigit, str(item.get('season_number',
                                                 seasonNumber)))))
            episodeNumber = (int(
                filter(str.isdigit,
                       str(item.get('episode_number', episodeNumber)))))
            seinfo = ('S' + ('0' if seasonNumber < 10 else '') +
                      str(seasonNumber) + 'E' +
                      ('0' if episodeNumber < 10 else '') + str(episodeNumber))
            label = '%s' % (
                label) if seasonNumber + episodeNumber == 0 else '%s - %s' % (
                    label, seinfo)
            infoLabels = {
                "mediatype": "episode",
                "label": label,
                "title": label,
                "TVShowTitle": label,
                "plot": plot,
                "aired": aired,
                "duration": item.get('duration_raw', 0)
            }
            infoArt = {
                "thumb": thumb,
                "poster": thumb,
                "fanart": FANART,
                "icon": ICON,
                "logo": ICON
            }
            self.addLink(label, url, 9, infoLabels, infoArt, len(items))
        self.addDir('>> Next', str(page + 1), 6)

    def browseEpisodes(self, url):
        log('browseEpisodes')
        items = json.loads(self.openURL(url))['result']['data']
        for item in items:
            if 'status' in item and item['status'].lower() != 'available':
                continue
            title = uni(
                item.get('title', '') or item.get('label', '')
                or item.get('episode_title', ''))
            vidType = item['type']
            thumb = (item['thumb'].get('large', '')
                     or item['thumb'].get('small', '') or ICON)
            aired = str(
                item['airdate_iso']).split('T')[0]  #str(item['airdate'])
            showTitle = uni(item['series_title'])
            runtime = item['duration'].split(':')
            if len(runtime) == 3:
                h, m, s = runtime
                duration = int(h) * 3600 + int(m) * 60 + int(s)
            else:
                m, s = runtime
                duration = int(m) * 60 + int(s)
            seasonNumber = int(item.get('season_number', '0') or '0')
            episodeNumber = int(item.get('episode_number', '0') or '0')
            url = item['url']
            if not url.startswith('http://'):
                url = (BASE_URL + '%s' % url).lstrip('/')
            seinfo = ('S' + ('0' if seasonNumber < 10 else '') +
                      str(seasonNumber) + 'E' +
                      ('0' if episodeNumber < 10 else '') + str(episodeNumber))
            label = '%s - %s' % (
                showTitle, title
            ) if seasonNumber + episodeNumber == 0 else '%s - %s - %s' % (
                showTitle, seinfo, title)
            plot = uni(item.get('description', label))
            infoLabels = {
                "mediatype": "episode",
                "label": label,
                "title": label,
                "TVShowTitle": showTitle,
                "plot": plot,
                "aired": aired,
                "duration": duration,
                "season": seasonNumber,
                "episode": episodeNumber
            }
            infoArt = {
                "thumb": thumb,
                "poster": thumb,
                "fanart": FANART,
                "icon": ICON,
                "logo": ICON
            }
            self.addLink(label, url, 9, infoLabels, infoArt, len(items))

    def browseCategory(self, url):
        log('browseCategory')
        items = json.loads(url)
        url = items['url']
        thumb = items['thumb']
        response = self.openURL(url).replace('\n',
                                             '').replace('\r',
                                                         '').replace('\t', '')
        seasons = re.search(
            '<select class="dropdown__filter__fake">(.*?)</select>', response)
        if seasons:
            items = re.findall(r'<option value="(.*?)".+?>(.*?)</option>',
                               seasons.group(1), re.DOTALL)
            if items:
                CONTENT_TYPE = 'tvshows'
                for item in items:
                    try:
                        seasonURL = SHOW_URL % (url, item[0])
                        title = item[1].strip()
                        infoLabels = {
                            "mediatype": "tvshow",
                            "label": title,
                            "title": title,
                            "TVShowTitle": title
                        }
                        infoArt = {
                            "thumb": thumb,
                            "poster": thumb,
                            "fanart": FANART,
                            "icon": ICON,
                            "logo": ICON
                        }
                        self.addDir(title, seasonURL, 5, infoLabels, infoArt)
                    except:
                        continue
        else:
            seasonURL = SHOW_URL % (url, '')
            title = "Full Episodes"
            infoLabels = {
                "mediatype": "tvshow",
                "label": title,
                "title": title,
                "TVShowTitle": title
            }
            infoArt = {
                "thumb": thumb,
                "poster": thumb,
                "fanart": FANART,
                "icon": ICON,
                "logo": ICON
            }
            self.addDir(title, seasonURL, 5, infoLabels, infoArt)

    def browseShows(self, url=None):
        log('browseShows')
        soup = BeautifulSoup(self.openURL(SHOWS_URL), "html.parser")
        shows = soup('article', {'class': 'show-browse-item'})
        for idx, show in enumerate(shows):
            title = uni(show.get_text()).replace("\n", "")
            if 'previews' in title.lower() or 'premieres' in title.lower():
                continue
            url = shows[idx].a['href']
            if not url.startswith('http://'):
                url = (BASE_URL + url).lstrip('/')
            if not url.endswith('/video/'): url = '%s/video/' % url.rstrip('/')
            thumb = shows[idx].img['data-src']
            url = json.dumps({'url': url, 'thumb': thumb})
            infoLabels = {
                "mediatype": "episode",
                "label": title,
                "title": title,
                "TVShowTitle": title
            }
            infoArt = {
                "thumb": thumb,
                "poster": thumb,
                "fanart": FANART,
                "icon": ICON,
                "logo": ICON
            }
            self.addDir(title, url, 3, infoLabels, infoArt)

    def playVideo(self, name, url, liz=None):
        log('playVideo')
        info = getVideoInfo(url, QUALITY, True)
        if info is None: return
        info = info.streams()
        url = info[0]['xbmc_url']
        liz = xbmcgui.ListItem(name, path=url)
        if 'subtitles' in info[0]['ytdl_format']:
            liz.setSubtitles([
                x['url']
                for x in info[0]['ytdl_format']['subtitles'].get('en', '')
                if 'url' in x
            ])
        xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)

    def addYoutube(self, name, url):
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label": name, "title": name})
        liz.setArt({'thumb': ICON, 'fanart': FANART})
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                    url=url,
                                    listitem=liz,
                                    isFolder=True)

    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb': ICON, 'fanart': FANART})
        else: liz.setArt(infoArt)
        u = sys.argv[0] + "?url=" + urllib.quote_plus(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                    url=u,
                                    listitem=liz,
                                    totalItems=total)

    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb': ICON, 'fanart': FANART})
        else: liz.setArt(infoArt)
        u = sys.argv[0] + "?url=" + urllib.quote_plus(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                    url=u,
                                    listitem=liz,
                                    isFolder=True)
Exemple #36
0
class Installer(object):
    def __init__(self):
        self.cache = SimpleCache()
        if self.chkUWP(): return
        self.killKodi = threading.Timer(2.0, self.killME)
        self.lastURL = (REAL_SETTINGS.getSetting("LastURL")
                        or self.buildMain())
        self.lastPath = REAL_SETTINGS.getSetting("LastPath")
        self.selectDialog(self.lastURL)

    def chkUWP(self):
        isUWP = (xbmc.getCondVisibility("system.platform.uwp")
                 or sys.platform == "win10"
                 or re.search(r"[/\\]WindowsApps[/\\]XBMCFoundation\.Kodi_",
                              xbmc.translatePath("special://xbmc/")))
        if isUWP: return self.disable()
        return isUWP

    def disable(self):
        xbmcgui.Dialog().notification(ADDON_NAME, VERSION, ICON, 8000)
        if not xbmcgui.Dialog().yesno(ADDON_NAME, LANGUAGE(30009),
                                      LANGUAGE(30012)):
            return True
        xbmc.executeJSONRPC(
            '{"jsonrpc": "2.0", "method":"Addons.SetAddonEnabled","params":{"addonid":"%s","enabled":false}, "id": 1}'
            % (ADDON_ID))
        xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30011), ICON, 4000)
        return True

    def openURL(self, url):
        if url is None: return
        log('openURL, url = ' + str(url))
        try:
            cacheResponce = self.cache.get(ADDON_NAME +
                                           '.openURL, url = %s' % url)
            if not cacheResponce:
                request = urllib2.Request(url)
                cacheResponce = urllib2.urlopen(request,
                                                timeout=TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s' % url,
                               cacheResponce,
                               expiration=datetime.timedelta(minutes=5))
            return BeautifulSoup(cacheResponce, "html.parser")
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON,
                                          4000)
            return None

    def getItems(self, soup):
        try:  #folders
            items = (soup.find_all('tr'))
            del items[0]
        except:  #files
            items = (soup.find_all('a'))
        return [x.get_text() for x in items if x.get_text() is not None]

    def buildMain(self):
        tmpLST = []
        for idx, item in enumerate(BUILD_OPT):
            tmpLST.append(xbmcgui.ListItem(item.title(), BUILD_DEC[idx], ICON))
        select = xbmcgui.Dialog().select(ADDON_NAME,
                                         tmpLST,
                                         preselect=-1,
                                         useDetails=True)
        if select < 0: return  #return on cancel.
        return WIND_URL % (BUILD_OPT[select].lower().replace('//',
                                                             '/'), PLATFORM)

    def buildItems(self, url):
        soup = self.openURL(url)
        if soup is None: return
        for item in self.getItems(soup):
            try:  #folders
                if 'uwp' in item.lower(): continue  #ignore UWP builds
                label, label2 = re.compile("(.*?)/-(.*)").match(item).groups()
                if label == PLATFORM: label2 = LANGUAGE(30014) % PLATFORM
                else: label2 = ''  #Don't use time-stamp for folders
                yield (xbmcgui.ListItem(label.strip(), label2.strip(), ICON))
            except:  #files
                label, label2 = re.compile("(.*?)\s(.*)").match(item).groups()
                if label.endswith('.exe'):
                    yield (xbmcgui.ListItem(label.strip(), label2.strip(),
                                            ICON))

    def setLastPath(self, url, path):
        REAL_SETTINGS.setSetting("LastURL", url)
        REAL_SETTINGS.setSetting("LastPath", path)

    def okDialog(self, str1, str2='', str3='', header=ADDON_NAME):
        xbmcgui.Dialog().ok(header, str1, str2, str3)

    def selectDialog(self, url, bypass=False):
        log('selectDialog, url = ' + str(url))
        newURL = url
        while not xbmc.Monitor().abortRequested():
            items = list(self.buildItems(url))
            if len(items) == 0: break
            elif len(items) == 2 and not bypass and items[0].getLabel(
            ).startswith('Parent directory'
                         ) and not items[1].getLabel().startswith('.exe'):
                select = 1  #If one folder bypass selection.
            else:
                label = url.replace(BASE_URL, './').replace('//', '/')
                select = xbmcgui.Dialog().select(label,
                                                 items,
                                                 preselect=-1,
                                                 useDetails=True)
                if select < 0: return  #return on cancel.
            label = items[select].getLabel()
            newURL = url + items[select].getLabel()
            preURL = url.rsplit('/', 2)[0] + '/'

            if newURL.endswith('.exe'):
                dest = xbmc.translatePath(os.path.join(SETTINGS_LOC, label))
                self.setLastPath(url, dest)
                return self.downloadEXE(newURL, dest)
            elif label.startswith('Parent directory') and "windows" in preURL:
                return self.selectDialog(preURL, True)
            elif label.startswith(
                    'Parent directory') and "windows" not in preURL:
                return self.selectDialog(self.buildMain(), False)
            url = newURL + '/'

    def fileExists(self, dest):
        if xbmcvfs.exists(dest):
            if not xbmcgui.Dialog().yesno(ADDON_NAME,
                                          LANGUAGE(30004),
                                          dest.rsplit('/', 1)[-1],
                                          nolabel=LANGUAGE(30005),
                                          yeslabel=LANGUAGE(30006)):
                return False
        elif CLEAN and xbmcvfs.exists(self.lastPath):
            self.deleteEXE(self.lastPath)
        return False

    def deleteEXE(self, path):
        count = 0
        #some file systems don't release the file lock instantly.
        while not xbmc.Monitor().abortRequested() and count < 3:
            count += 1
            if xbmc.Monitor().waitForAbort(1): return
            try:
                if xbmcvfs.delete(path): return
            except:
                pass

    def downloadEXE(self, url, dest):
        if self.fileExists(dest): return self.installEXE(dest)
        start_time = time.time()
        dia = xbmcgui.DialogProgress()
        dia.create(ADDON_NAME, LANGUAGE(30002))
        try:
            urllib.urlretrieve(
                url.rstrip('/'), dest,
                lambda nb, bs, fs: self.pbhook(nb, bs, fs, dia, start_time))
        except Exception as e:
            dia.close()
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON,
                                          4000)
            log("downloadAPK, Failed! (%s) %s" % (url, str(e)), xbmc.LOGERROR)
            return self.deleteEXE(dest)
        return self.installEXE(dest)

    def pbhook(self, numblocks, blocksize, filesize, dia, start_time):
        try:
            percent = min(numblocks * blocksize * 100 / filesize, 100)
            currently_downloaded = float(numblocks) * blocksize / (1024 * 1024)
            kbps_speed = numblocks * blocksize / (time.time() - start_time)
            if kbps_speed > 0:
                eta = (filesize - numblocks * blocksize) / kbps_speed
            else:
                eta = 0
            kbps_speed = kbps_speed / 1024
            total = float(filesize) / (1024 * 1024)
            mbs = '%.02f MB of %.02f MB' % (currently_downloaded, total)
            e = 'Speed: %.02f Kb/s ' % kbps_speed
            if eta < 0: eta = divmod(0, 60)
            else: eta = divmod(eta, 60)
            e += 'ETA: %02d:%02d' % eta
            dia.update(percent, LANGUAGE(30002), mbs, e)
        except Exception('Download Failed'):
            dia.update(100)
        if dia.iscanceled(): raise Exception('Download Canceled')

    def installEXE(self, exefile):
        if not xbmcvfs.exists(exefile): return
        xbmc.executebuiltin(
            'XBMC.AlarmClock(shutdowntimer,XBMC.Quit(),0.5,true)')
        self.killKodi.start()
        subprocess.call(exefile, shell=True)

    def killME(self):
        subprocess.call('taskkill /f /im kodi.exe')
Exemple #37
0
class AIRYTV(object):
    def __init__(self, sysARG=sys.argv):
        log('__init__, sysARG = %s' % (sysARG))
        self.sysARG = sysARG
        self.cache = SimpleCache()
        self.channels = self.getChanneldata()

    def getURL(
        self,
        url,
        param={},
        header={
            'User-agent':
            'Mozilla/5.0 (Windows NT 6.2; rv:24.0) Gecko/20100101 Firefox/24.0'
        },
        life=datetime.timedelta(minutes=15)):
        log('getURL, url = %s, header = %s' % (url, header))
        cacheresponse = self.cache.get('%s.getURL, url = %s.%s.%s' %
                                       (ADDON_ID, url, param, header))
        if not cacheresponse:
            try:
                req = requests.get(url, param, headers=header)
                cacheresponse = req.json()
                req.close()
            except Exception as e:
                log("getURL, Failed! %s" % (e), xbmc.LOGERROR)
                notificationDialog(LANGUAGE(30001))
                return {}
            self.cache.set('%s.getURL, url = %s.%s.%s' %
                           (ADDON_ID, url, param, header),
                           json.dumps(cacheresponse),
                           expiration=life)
            return cacheresponse
        return json.loads(cacheresponse)

    def buildMenu(self):
        log('buildMenu')
        AIRY_MENU = [(LANGUAGE(30011), (getLive, )),
                     (LANGUAGE(30040), (getLiveFavs, )),
                     (LANGUAGE(30018), (getLineups, )),
                     (LANGUAGE(30017), (getCats, ))]
        for item in AIRY_MENU:
            self.addDir(*item)

    def getChanneldata(self):
        log('getChanneldata')
        collect = {}
        echannels = []
        categories = self.getURL(BASE_API.format(tz=getTZ()),
                                 life=datetime.timedelta(hours=1)).get(
                                     'response', {}).get('categories', [])
        for category in categories:
            genre = self.cleanString(category.get('name'))
            channels = (category.get('banners', []) +
                        category.get('stream_channels', []) +
                        category.get('channels', []))
            for channel in channels:
                channel['category'] = genre
                channel['name'] = self.cleanString(channel.get('name'))
                if channel['name'] not in echannels:  #catch dups; lazy fix
                    echannels.append(channel['name'])
                    collect.setdefault(genre, []).append(channel)
        return collect

    def getCategories(self):
        log('getCategories')
        return self.channels.keys()

    def getChannels(self):
        log('getChannels')
        categories = self.getCategories()
        for category in categories:
            channels = self.channels.get(category, [])
            for channel in channels:
                yield channel

    def getChannel(self, id):
        log('getChannel, id = %s' % (id))
        channels = self.getChannels()
        for channel in channels:
            if channel.get('id') == int(id): return channel
        return {}

    def getBroadcast(self, id, epid):
        log('getBroadcast, id = %s, epid = %s' % (id, epid))
        channel = self.getChannel(id)
        broadcasts = channel.get('broadcasts', [])
        for broadcast in broadcasts:
            if broadcast.get('id') == int(epid): return channel, broadcast
        return {}, {}

    def buildCategories(self, cat=None):
        log('buildCategories, cat = %s' % (cat))
        for category in self.getCategories():
            if cat and cat != category: continue
            self.addDir(category,
                        uri=(getCat, category),
                        infoArt={
                            'thumb': LOGO_URL % (category),
                            'fanart': FANART
                        })

    def buildLineups(self, id=None, cat=None):
        log('buildLineups, id = %s, cat = %s' % (id, cat))
        for channel in self.getChannels():
            if id and channel.get('id') != int(id): continue
            if cat and channel.get('category') != cat: continue
            self.addDir('%s| %s' %
                        (channel.get('number'), channel.get('name')),
                        uri=(getLineup, channel.get('id')),
                        infoArt={
                            'thumb': LOGO_URL % (channel.get('name')),
                            'fanart': FANART
                        })

    def buildChannels(self, opt='live'):
        log('buildChannels, opt=%s' % (opt))
        return list(self.poolList(self.buildChannel, self.getChannels(), opt))

    def buildChannel(self, data):
        channel, opt = data
        log('buildChannel, channel = %s, opt=%s' % (channel.get('id'), opt))
        stname = channel.get('name')
        stnum = channel.get('number')
        broadcasts = channel.get('broadcasts', [])
        favorite = isFavorite(stnum)
        if opt == 'iptv_channel':
            channel = {
                "name": stname,
                "stream":
                "plugin://%s/play/pvr/%s" % (ADDON_ID, channel.get('id')),
                "id":
                "%s.%s@%s" % (stnum, slugify(stname), slugify(ADDON_NAME)),
                "logo": LOGO,
                "preset": stnum,
                "group": [channel.get('category'), ADDON_NAME],
                "radio": False
            }
            if favorite: channel['group'].append(LANGUAGE(49012))
            channel['group'] = ';'.join(channel['group'])
            if REAL_SETTINGS.getSettingBool(
                    'Build_Favorites') and not favorite:
                return None
            return channel
        else:
            return self.buildBroadcasts(channel, broadcasts, opt)

    def buildBroadcasts(self, channel, broadcasts, opt=''):
        log('buildBroadcasts, channel = %s, opt = %s' %
            (channel.get('id'), opt))
        id = channel.get('id')
        hls = channel.get('hls', False)
        name = channel.get('name')
        number = channel.get('number')
        category = channel.get('category')
        favorite = isFavorite(number)
        programmes = {id: []}
        now = datetime.datetime.now().astimezone().replace(microsecond=0)
        for idx, broadcast in enumerate(broadcasts):
            """{
                'id': 3092301,
                'title': 'Mankind From Space',
                'parts': [{
                    'duration': 2617,
                    'source_url': 'https://ia801605.us.archive.org/12/items/National.GeographicAlien.Earths2009.720p.AC3_201702/National.Geographic%20-%20Mankind.From.Space%20-%202015.720p.AAC.mp4',
                    'start_at_iso': '2021-03-18T14:35:24-04:00'
                }],
                'description': "Trace humankind's long journey from hunter-gatherer to dominant global species. From the perspective of space, this two-hour special uses mind-boggling data and CGI to disclose the breathtaking extent of humanity's influence, revealing how we've transformed our planet and produced an interconnected world of extraordinary complexity. A trip through 12,000 years of development, the documentary shows how seemingly small flashes of innovation - innovations that touch all of us in ways unimaginable to our ancestors - have changed the course of civilization. As our global population soars, the program considers the challenges humanity will face in order to survive.",
                'view_duration': 1141,
                'stream_duration': 2617,
                'view_start_at_iso': '2021-03-18T15:00:00-04:00',
                'stream_start_at_iso': '2021-03-18T14:35:24-04:00'
                }"""
            """{
                'id': 3121442,
                'title': 'Fishing Offshore',
                'description': 'Fishing Offshore',
                'view_duration': 1391,
                'stream_duration': 2700,
                'view_start_at_iso': '2021-03-24T18:00:00-04:00',
                'stream_start_at_iso': '2021-03-24T17:38:11-04:00'
                }"""
            try:
                starttime = strpTime(broadcast['stream_start_at_iso'])
            except:
                continue

            offsettime = strpTime(broadcast.get('view_start_at_iso'))
            remaining = (broadcast.get('view_duration', 0))
            duration = (broadcast.get('stream_duration', '') or remaining)
            stoptime = (starttime + datetime.timedelta(seconds=duration))
            epid = (broadcast.get('id'))
            title = (broadcast.get('title') or name)
            plot = (broadcast.get('description')
                    or xbmc.getLocalizedString(161))

            parts = (broadcast.get('parts', []))
            for part in parts:
                runtime = (part.get('duration', 0))
                stream = (part.get('source_url'))
                start = strpTime(part.get('start_at_iso'))

            if hls: uri = (playLive, id)
            else: uri = (playVOD, id, epid)

            if opt == 'iptv_broadcasts':
                program = {
                    "start": starttime.strftime(DTFORMAT),
                    "stop": stoptime.strftime(DTFORMAT),
                    "title": title,
                    "description": plot,
                    "subtitle": "",
                    "episode": "",
                    "genre": category,
                    "image": FANART,
                    "date": starttime.strftime('%Y-%m-%d'),
                    "credits": "",
                    "stream":
                    "plugin://%s/play/vod/%s/%s" % (ADDON_ID, id, epid)
                }
                programmes[id].append(program)

            elif opt in ['live', 'favorites', 'broadcast']:
                chname = '%s| %s' % (number, name)
                label = '%s : [B] %s[/B]' % (chname, title)
                if opt == 'favorites' and not favorite: return None

                if now >= starttime and now < stoptime:
                    if opt == 'broadcast': return broadcast
                    return self.addLink(label,
                                        uri,
                                        infoList={
                                            "favorite": favorite,
                                            "chnum": number,
                                            "chname": name,
                                            "mediatype": "video",
                                            "label": label,
                                            "title": label
                                        },
                                        infoArt={
                                            'thumb': LOGO_URL % (name),
                                            'fanart': FANART
                                        })

            elif opt == 'lineup':
                if stoptime < now: continue
                elif now >= starttime and now < stoptime:
                    label = '%s - [B]%s[/B]' % (
                        starttime.strftime('%I:%M %p').lstrip('0'), title)
                else:
                    label = '%s - %s' % (
                        starttime.strftime('%I:%M %p').lstrip('0'), title)
                    uri = list(uri)
                    if hls: uri[1] = 'NEXT_SHOW'
                    uri = tuple(uri)
                self.addLink(label,
                             uri,
                             infoList={
                                 "favorite": favorite,
                                 "chnum": number,
                                 "chname": name,
                                 "mediatype": "video",
                                 "label": label,
                                 "title": label
                             },
                             infoArt={
                                 'thumb': LOGO_URL % (name),
                                 'fanart': FANART
                             })

        return programmes

    def cleanString(self, text):
        return text.replace('_', ' ')

    def poolList(self, method, items=None, args=None, chunk=25):
        log("poolList")
        results = []
        if ENABLE_POOL:
            pool = ThreadPool(CORES)
            if args is not None:
                results = pool.map(method, zip(items, repeat(args)))
            elif items:
                results = pool.map(method, items)  #, chunksize=chunk)
            pool.close()
            pool.join()
        else:
            if args is not None:
                results = [method((item, args)) for item in items]
            elif items:
                results = [method(item) for item in items]
        return filter(None, results)

    def resolveYoutube(self, url, seek=0):
        log('resolveYoutube, url = %s, seek = %s' % (url, seek))
        """Returns Video_ID extracting from the given url of Youtube
        Examples of URLs:
          Valid:
            'http://youtu.be/_lOT2p_FCvA',
            'www.youtube.com/watch?v=_lOT2p_FCvA&feature=feedu',
            'http://www.youtube.com/embed/_lOT2p_FCvA',
            'http://www.youtube.com/v/_lOT2p_FCvA?version=3&amp;hl=en_US',
            'https://www.youtube.com/watch?v=rTHlyTphWP0&index=6&list=PLjeDyYvG6-40qawYNR4juzvSOg-ezZ2a6',
            'youtube.com/watch?v=_lOT2p_FCvA',
          Invalid:
            'youtu.be/watch?v=_lOT2p_FCvA',
        """

        if url.startswith(('youtu', 'www')):
            url = 'http://%s' % url
        query = urllib.parse.urlparse(url)
        if 'youtube' in query.hostname:
            if query.path == '/watch':
                match = urllib.parse.parse_qs(query.query)['v'][0]
            elif query.path.startswith(('/embed/', '/v/')):
                match = query.path.split('/')[2]
        elif 'youtu.be' in query.hostname:
            match = query.path[1:]
        else:
            match = None
        if match:
            return 'plugin://plugin.video.tubed/?mode=play&video_id={vid}&start_offset={offset}'.format(
                vid=match, offset=float(seek))
        return url

    def resolveURL(self, id, epid=None, opt='live'):
        log('resolveURL, id = %s, epid = %s, opt = %s' % (id, epid, opt))
        lizs = []
        urls = []
        if opt == 'live':
            channel = self.getChannel(id)
            urls = [channel.get('source_url')]
            broadcast = self.buildChannel((channel, 'broadcast'))
            runtime = (broadcast.get('stream_duration', 0))
        elif opt == 'vod':
            channel, broadcast = self.getBroadcast(id, epid)
            parts = (broadcast.get('parts', []))
            runtime = (broadcast.get('stream_duration', 0))
            for part in parts:
                urls.append(part.get('source_url'))
        if not urls: urls = [channel.get('source_url')]
        print('channel', channel, 'broadcast', broadcast)
        for url in urls:
            name = (broadcast.get('title'))
            liz = xbmcgui.ListItem(name)
            if xbmcgui.Window(10000).getProperty('PseudoTVRunning') == "True":
                liz.setPath(self.resolveYoutube(url))
            else:  #apply channel offset when not using PseudoTV
                liz.setPath(
                    self.resolveYoutube(url, broadcast.get('view_duration',
                                                           0)))
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name,
                            "duration": runtime,
                            "plot": (broadcast.get('description', ''))
                        })
            liz.setArt({
                'thumb': ICON,
                'fanart': FANART,
                "icon": LOGO,
                "logo": LOGO,
                "clearart": LOGO
            })
            liz.setProperty("IsPlayable", "true")
            if 'm3u8' in url.lower() and inputstreamhelper.Helper(
                    'hls').check_inputstream():
                liz.setProperty('IsInternetStream', 'true')
                liz.setProperty('inputstream', 'inputstream.adaptive')
                liz.setProperty('inputstream.adaptive.manifest_type', 'hls')
            return liz  #todo playlist?
        return xbmcgui.ListItem()

        # #
        # self.listitems = []
        # self.playlist  = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
        # self.playlist.clear()
        # channel = list(filter(lambda k:k.get('_id','') == id, self.getGuidedata()))[0]
        # urls = channel.get('stitched',{}).get('urls',[])
        # if isinstance(urls, list): urls = [url['url'] for url in urls if url['type'].lower() == 'hls'][0]
        # liz = xbmcgui.ListItem(channel.get('name'),path=urls)
        # liz.setProperty('IsPlayable','true')
        # liz.setProperty('IsInternetStream','true')
        # if opt != 'pvr':
        # self.browseGuide(opt='play',data=[channel])
        # [self.playlist.add(urls,lz,idx) for idx,lz in enumerate(self.listitems)]
        # liz = self.listitems.pop(0)
        # liz.setPath(path=urls)
        # return liz

    def playVOD(self, id, epid):
        log('playVOD, id = %s, epid = %s' % (id, epid))
        xbmcplugin.setResolvedUrl(ROUTER.handle, True,
                                  self.resolveURL(id, epid, 'vod'))

    def playLive(self, id, epid=None, opt='live'):
        log('playLive, id = %s, epid = %s, opt = %s' % (id, epid, opt))
        #if opt == 'pvr', find epid.
        if id == 'NEXT_SHOW':
            found = False
            liz = xbmcgui.ListItem()
            notificationDialog(LANGUAGE(30029), time=4000)
        else:
            found = True
            liz = self.resolveURL(id, epid, opt)
            log('playLive, url = %s' % (liz.getPath()))
        xbmcplugin.setResolvedUrl(ROUTER.handle, found, liz)

    def addPlaylist(self,
                    name,
                    path='',
                    infoList={},
                    infoArt={},
                    infoVideo={},
                    infoAudio={},
                    infoType='video'):
        log('addPlaylist, name = %s' % name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        liz.setProperty('IsInternetStream', 'true')
        if infoList: liz.setInfo(type=infoType, infoLabels=infoList)
        else:
            liz.setInfo(type=infoType,
                        infoLabels={
                            "mediatype": infoType,
                            "label": name,
                            "title": name
                        })
        if infoArt: liz.setArt(infoArt)
        else:
            liz.setArt({
                'thumb': ICON,
                'fanart': FANART,
                "icon": LOGO,
                "logo": LOGO,
                "clearart": LOGO
            })
        if infoVideo: liz.addStreamInfo('video', infoVideo)
        if infoAudio: liz.addStreamInfo('audio', infoAudio)
        self.listitems.append(liz)

    def addLink(self,
                name,
                uri=(''),
                infoList={},
                infoArt={},
                infoVideo={},
                infoAudio={},
                infoType='video',
                total=0):
        log('addLink, name = %s' % name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        liz.setProperty('IsInternetStream', 'true')
        if infoList: liz.setInfo(type=infoType, infoLabels=infoList)
        else:
            liz.setInfo(type=infoType,
                        infoLabels={
                            "mediatype": infoType,
                            "label": name,
                            "title": name
                        })
        if infoArt: liz.setArt(infoArt)
        else:
            liz.setArt({
                'thumb': ICON,
                'fanart': FANART,
                "icon": LOGO,
                "logo": LOGO,
                "clearart": LOGO
            })
        if infoVideo: liz.addStreamInfo('video', infoVideo)
        if infoAudio: liz.addStreamInfo('audio', infoAudio)
        if infoList.get('favorite', None) is not None:
            liz = self.addContextMenu(liz, infoList)
        xbmcplugin.addDirectoryItem(ROUTER.handle,
                                    ROUTER.url_for(*uri),
                                    liz,
                                    isFolder=False,
                                    totalItems=total)

    def addDir(self,
               name,
               uri=(''),
               infoList={},
               infoArt={},
               infoType='video'):
        log('addDir, name = %s' % name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList: liz.setInfo(type=infoType, infoLabels=infoList)
        else:
            liz.setInfo(type=infoType,
                        infoLabels={
                            "mediatype": infoType,
                            "label": name,
                            "title": name
                        })
        if infoArt: liz.setArt(infoArt)
        else:
            liz.setArt({
                'thumb': ICON,
                'fanart': FANART,
                "icon": LOGO,
                "logo": LOGO,
                "clearart": LOGO
            })
        if infoList.get('favorite', None) is not None:
            liz = self.addContextMenu(liz, infoList)
        xbmcplugin.addDirectoryItem(ROUTER.handle,
                                    ROUTER.url_for(*uri),
                                    liz,
                                    isFolder=True)

    def addContextMenu(self, liz, infoList={}):
        log('addContextMenu')
        if infoList['favorite']:
            liz.addContextMenuItems([
                (LANGUAGE(49010),
                 'RunScript(special://home/addons/%s/favorites.py, %s)' %
                 (ADDON_ID,
                  urllib.parse.quote(
                      json.dumps({
                          "chnum": infoList.pop('chnum'),
                          "chname": infoList.pop('chname'),
                          "mode": "del"
                      }))))
            ])
        else:
            liz.addContextMenuItems([
                (LANGUAGE(49009),
                 'RunScript(special://home/addons/%s/favorites.py, %s)' %
                 (ADDON_ID,
                  urllib.parse.quote(
                      json.dumps({
                          "chnum": infoList.pop('chnum'),
                          "chname": infoList.pop('chname'),
                          "mode": "add"
                      }))))
            ])
        return liz

    def run(self):
        ROUTER.run()
        xbmcplugin.setContent(ROUTER.handle, CONTENT_TYPE)
        xbmcplugin.addSortMethod(ROUTER.handle,
                                 xbmcplugin.SORT_METHOD_UNSORTED)
        xbmcplugin.addSortMethod(ROUTER.handle, xbmcplugin.SORT_METHOD_NONE)
        xbmcplugin.addSortMethod(ROUTER.handle, xbmcplugin.SORT_METHOD_LABEL)
        xbmcplugin.addSortMethod(ROUTER.handle, xbmcplugin.SORT_METHOD_TITLE)
        xbmcplugin.endOfDirectory(ROUTER.handle, cacheToDisc=DISC_CACHE)
Exemple #38
0
class SCAN(object):
    def __init__(self):
        self.cache = SimpleCache()
        self.silent = False
        self.pDialog = None
        self.pUpdate = 0
        self.matchCNT = 0
        self.errorCNT = 0
        self.kodiModules = {}

    def sendJSON(self, command, life=datetime.timedelta(seconds=15)):
        log('sendJSON, command = ' + (command))
        cacheresponse = self.cache.get(ADDON_NAME +
                                       '.sendJSON, command = %s' % command)
        if not cacheresponse:
            cacheresponse = loadJSON(xbmc.executeJSONRPC(command))
            self.cache.set(ADDON_NAME + '.sendJSON, command = %s' % command,
                           cacheresponse,
                           expiration=life)
        return cacheresponse

    def openURL(self, url):
        try:
            log('openURL, url = ' + str(url))
            cacheresponse = self.cache.get(ADDON_NAME +
                                           '.openURL, url = %s' % url)
            if DEBUG: cacheresponse = None
            if not cacheresponse:
                headers = {'User-Agent': 'Kodi-Auditor'}
                req = urllib2.Request(url, None, headers)
                page = urllib2.urlopen(req, timeout=TIMEOUT)
                if page.headers.get('Content-Type').find(
                        'gzip') >= 0 or page.headers.get('Content-Type').find(
                            'application/octet-stream') >= 0:
                    d = zlib.decompressobj(16 + zlib.MAX_WBITS)
                    cacheresponse = d.decompress(page.read())
                else:
                    cacheresponse = page.read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s' % url,
                               cacheresponse,
                               expiration=datetime.timedelta(hours=12))
            return cacheresponse
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            notificationDialog(LANGUAGE(30001))
            return ''

    def preliminary(self):
        self.silent = True
        self.validate()
        plural = 's' if self.errorCNT > 0 else ''
        if self.errorCNT > 0:
            notificationDialog(LANGUAGE(32006) % (self.errorCNT, plural),
                               time=8000)

    def validate(self):
        log('validate')
        if getProperty('Running') == 'True': return
        setProperty('Running', 'True')
        self.matchCNT = 0
        self.errorCNT = 0
        summary = self.scanModules()
        setProperty('Running', 'False')
        if self.silent: return
        if yesnoDialog(LANGUAGE(32009),
                       yes=LANGUAGE(32008),
                       no=LANGUAGE(32007)):
            self.buildDetails(filterErrors(summary))
        else:
            textViewer('\n'.join([item['label'] for item in summary]),
                       silent=self.silent)

    def buildDetails(self, items):
        log('buildDetails')
        select = -1
        listItems = []
        for item in items:
            addonID = (item['myModule'].get('id', '')
                       or item['myModule'].get('addonid', None))
            if addonID is None: continue
            author = (item['myModule'].get('provider-name', '')
                      or item['myModule']['author'])
            label = '%s v.%s by %s' % (addonID, item['myModule']['version'],
                                       author)
            label2 = 'Enabled: [B]%s[/B] | %s' % (str(item['myModule'].get(
                'enabled', True)), item['label2'])
            liz = buildListItem((label, label2, addonID))
            # liz.setProperty('myModule'  ,dumpJSON(item['myModule']))
            # liz.setProperty('kodiModule',dumpJSON(item['kodiModule']))
            listItems.append(liz)
        while select is not None:
            select = selectDialog(listItems, LANGUAGE(32012), preselect=select)
            if select is None: return
            sitem = listItems[select]
            label = sitem.getLabel()
            label2 = sitem.getLabel2()
            addonID = sitem.getPath()
            pselect = selectDialog(
                [buildListItem((mItem, '', '')) for mItem in MENU_ITEMS],
                LANGUAGE(32025) % (addonID))
            if pselect == 0:
                state = not (cleanString(
                    label2.split('Enabled: ')[1].split(' |')[0]))
                if okDisable(LANGUAGE(32011) % (label), label, addonID, state):
                    listItems.pop(select)
            elif pselect == 1:
                setWhiteList(addonID)
                listItems.pop(select)

    def scanModules(self):
        log('scanModules')
        summary = []
        progCNT = 0
        repository = self.buildRepo()
        whiteList = getWhiteList()['modules']
        myModules = self.sendJSON(MOD_QUERY)['result']['addons']
        pTotal = len(myModules)
        for idx1, myModule in enumerate(myModules):
            found = False
            error = False
            if myModule['addonid'] in whiteList: continue
            self.label = '{name} v.{version}{filler}[B]{status}[/B]'.format(
                name=uni(myModule['name']),
                version=uni(myModule['version']),
                filler='{filler}',
                status='{status}')
            self.pUpdate = (idx1) * 100 // pTotal
            self.pDialog = progressDialog(self.pUpdate,
                                          control=self.pDialog,
                                          string1=LANGUAGE(32016),
                                          silent=self.silent)
            found, error, kodiModule = self.findModule(
                myModule, self.kodiModules[repository])
            log('scanModules, myModule = %s, repository = %s, found = %s' %
                (myModule['addonid'], repository, found))
            verifed = 'True' if found and not error else 'False'
            self.pDialog = progressDialog(self.pUpdate,
                                          control=self.pDialog,
                                          string2=LANGUAGE(32017) %
                                          (uni(myModule['addonid'])),
                                          silent=self.silent)
            if found and error:
                self.label = self.label.format(filler=generateFiller(
                    self.label, LANGUAGE(32004)),
                                               status=LANGUAGE(32004))
                self.label2 = LANGUAGE(32004)
            elif found and not error:
                self.label = self.label.format(filler=generateFiller(
                    self.label, LANGUAGE(32002)),
                                               status=LANGUAGE(32002))
                self.label2 = LANGUAGE(32002)
            if not found and not error:
                self.label = self.label.format(filler=generateFiller(
                    self.label, LANGUAGE(32003)),
                                               status=LANGUAGE(32003))
                self.label2 = LANGUAGE(32003)
            summary.append({
                'found': found,
                'error': error,
                'label': self.label,
                'label2': self.label2,
                'kodiModule': (kodiModule),
                'myModule': (myModule)
            })
        summary = sortItems(summary)
        filler = generateFiller(LANGUAGE(32013), '')
        filler = filler[:(len(filler) / 2) - 1]
        summary.insert(
            0, {
                'found': False,
                'error': False,
                'label': '%s%s%s' % (filler, LANGUAGE(32013), filler),
                'label2': '',
                'kodiModule': {},
                'myModule': {}
            })
        summary.insert(
            1, {
                'found': False,
                'error': False,
                'label': '\n',
                'label2': '',
                'kodiModule': {},
                'myModule': {}
            })
        self.pDialog = progressDialog(100,
                                      control=self.pDialog,
                                      string3=LANGUAGE(32018),
                                      silent=self.silent)
        return summary

    def findModule(self, myModule, kodiModules):
        found = False
        error = False
        for kodiModule in kodiModules:
            self.pDialog = progressDialog(self.pUpdate,
                                          control=self.pDialog,
                                          string3='Checking %s ...' %
                                          (uni(kodiModule['id'])),
                                          silent=self.silent)
            try:
                if myModule['addonid'].lower() == kodiModule['id'].lower():
                    found = True
                    self.matchCNT += 1
                    if myModule['version'] != kodiModule['version']:
                        error = True
                        self.errorCNT += 1
                    break
            except Exception as e:
                log(
                    'findModule, failed parse %s - %s' %
                    (str(myModule), str(e)), xbmc.LOGERROR)
        if found: return found, error, kodiModule
        return found, error, myModule

    def buildRepo(self):
        self.pDialog = progressDialog(0,
                                      string1=LANGUAGE(32014),
                                      silent=self.silent)
        repository = BUILDS[self.sendJSON(VER_QUERY)['result']['version']
                            ['major']]
        log('buildRepo, repository = %s' % (repository))
        self.pDialog = progressDialog(0,
                                      string2=LANGUAGE(32015) %
                                      (repository.title()),
                                      silent=self.silent)
        self.kodiModules[repository] = list(self.buildModules(repository))
        return repository

    def buildModules(self, branch):
        log('buildModules, branch = ' + (branch))
        tree = ET.fromstring(self.openURL(BASE_URL % (branch)))
        for elem in tree.iter():
            if elem.tag == 'addon': addon = elem.attrib.copy()
            if elem.tag == 'extension' and elem.attrib.copy(
            )['point'] == 'xbmc.python.module':
                yield (addon)

    def getParams(self):
        try:
            return dict(urlparse.parse_qsl(sys.argv[2][1:]))
        except:
            return None
Exemple #39
0
 def __init__(self, sysARG=sys.argv):
     log('__init__, sysARG = %s' % (sysARG))
     self.sysARG = sysARG
     self.cache = SimpleCache()
     self.channels = self.getChanneldata()
Exemple #40
0
class MainModule:
    '''mainmodule provides the script methods for the skinhelper addon'''

    def __init__(self):
        '''Initialization and main code run'''
        self.win = xbmcgui.Window(10000)
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.kodidb = KodiDb()
        self.cache = SimpleCache()

        self.params = self.get_params()
        log_msg("MainModule called with parameters: %s" % self.params)
        action = self.params.get("action", "")
        # launch module for action provided by this script
        try:
            getattr(self, action)()
        except AttributeError:
            log_exception(__name__, "No such action: %s" % action)
        except Exception as exc:
            log_exception(__name__, exc)
        finally:
            xbmc.executebuiltin("dialog.Close(busydialog)")

        # do cleanup
        self.close()

    def close(self):
        '''Cleanup Kodi Cpython instances on exit'''
        self.cache.close()
        del self.win
        del self.addon
        del self.kodidb
        log_msg("MainModule exited")

    @classmethod
    def get_params(self):
        '''extract the params from the called script path'''
        params = {}
        for arg in sys.argv[1:]:
            paramname = arg.split('=')[0]
            paramvalue = arg.replace(paramname + "=", "")
            paramname = paramname.lower()
            if paramname == "action":
                paramvalue = paramvalue.lower()
            params[paramname] = paramvalue
        return params

    def deprecated_method(self, newaddon):
        '''
            used when one of the deprecated methods is called
            print warning in log and call the external script with the same parameters
        '''
        action = self.params.get("action")
        log_msg("Deprecated method: %s. Please call %s directly" % (action, newaddon), xbmc.LOGWARNING)
        paramstring = ""
        for key, value in self.params.iteritems():
            paramstring += ",%s=%s" % (key, value)
        if xbmc.getCondVisibility("System.HasAddon(%s)" % newaddon):
            xbmc.executebuiltin("RunAddon(%s%s)" % (newaddon, paramstring))
        else:
            # trigger install of the addon
            if KODI_VERSION > 16:
                xbmc.executebuiltin("InstallAddon(%s)" % newaddon)
            else:
                xbmc.executebuiltin("RunPlugin(plugin://%s)" % newaddon)

    @staticmethod
    def musicsearch():
        '''helper to go directly to music search dialog'''
        xbmc.executebuiltin("ActivateWindow(Music)")
        xbmc.executebuiltin("SendClick(8)")

    def setview(self):
        '''sets the selected viewmode for the container'''
        xbmc.executebuiltin("ActivateWindow(busydialog)")
        content_type = get_current_content_type()
        if not content_type:
            content_type = "files"
        current_view = xbmc.getInfoLabel("Container.Viewmode").decode("utf-8")
        view_id, view_label = self.selectview(content_type, current_view)
        current_forced_view = xbmc.getInfoLabel("Skin.String(SkinHelper.ForcedViews.%s)" % content_type)

        if view_id is not None:
            # also store forced view
            if (content_type and current_forced_view and current_forced_view != "None" and
                    xbmc.getCondVisibility("Skin.HasSetting(SkinHelper.ForcedViews.Enabled)")):
                xbmc.executebuiltin("Skin.SetString(SkinHelper.ForcedViews.%s,%s)" % (content_type, view_id))
                xbmc.executebuiltin("Skin.SetString(SkinHelper.ForcedViews.%s.label,%s)" % (content_type, view_label))
                self.win.setProperty("SkinHelper.ForcedView", view_id)
                if not xbmc.getCondVisibility("Control.HasFocus(%s)" % current_forced_view):
                    xbmc.sleep(100)
                    xbmc.executebuiltin("Container.SetViewMode(%s)" % view_id)
                    xbmc.executebuiltin("SetFocus(%s)" % view_id)
            else:
                self.win.clearProperty("SkinHelper.ForcedView")
            # set view
            xbmc.executebuiltin("Container.SetViewMode(%s)" % view_id)

    def selectview(self, content_type="other", current_view=None, display_none=False):
        '''reads skinfile with all views to present a dialog to choose from'''
        cur_view_select_id = None
        label = ""
        all_views = []
        if display_none:
            listitem = xbmcgui.ListItem(label="None")
            listitem.setProperty("id", "None")
            all_views.append(listitem)
        # read the special skin views file
        views_file = xbmc.translatePath('special://skin/extras/views.xml').decode("utf-8")
        if xbmcvfs.exists(views_file):
            doc = parse(views_file)
            listing = doc.documentElement.getElementsByTagName('view')
            itemcount = 0
            for view in listing:
                label = xbmc.getLocalizedString(int(view.attributes['languageid'].nodeValue))
                viewid = view.attributes['value'].nodeValue
                mediatypes = view.attributes['type'].nodeValue.lower().split(",")
                if label.lower() == current_view.lower() or viewid == current_view:
                    cur_view_select_id = itemcount
                    if display_none:
                        cur_view_select_id += 1
                if (("all" in mediatypes or content_type.lower() in mediatypes) and
                    (not "!" + content_type.lower() in mediatypes) and not
                        xbmc.getCondVisibility("Skin.HasSetting(SkinHelper.view.Disabled.%s)" % viewid)):
                    image = "special://skin/extras/viewthumbs/%s.jpg" % viewid
                    listitem = xbmcgui.ListItem(label=label, iconImage=image)
                    listitem.setProperty("viewid", viewid)
                    listitem.setProperty("icon", image)
                    all_views.append(listitem)
                    itemcount += 1
        dialog = DialogSelect("DialogSelect.xml", "", listing=all_views,
                              windowtitle=self.addon.getLocalizedString(32012), richlayout=True)
        dialog.autofocus_id = cur_view_select_id
        dialog.doModal()
        result = dialog.result
        del dialog
        if result:
            viewid = result.getProperty("viewid")
            label = result.getLabel().decode("utf-8")
            return (viewid, label)
        else:
            return (None, None)

    # pylint: disable-msg=too-many-local-variables
    def enableviews(self):
        '''show select dialog to enable/disable views'''
        all_views = []
        views_file = xbmc.translatePath('special://skin/extras/views.xml').decode("utf-8")
        richlayout = self.params.get("richlayout", "") == "true"
        if xbmcvfs.exists(views_file):
            doc = parse(views_file)
            listing = doc.documentElement.getElementsByTagName('view')
            for view in listing:
                view_id = view.attributes['value'].nodeValue
                label = xbmc.getLocalizedString(int(view.attributes['languageid'].nodeValue))
                desc = label + " (" + str(view_id) + ")"
                image = "special://skin/extras/viewthumbs/%s.jpg" % view_id
                listitem = xbmcgui.ListItem(label=label, label2=desc, iconImage=image)
                listitem.setProperty("viewid", view_id)
                if not xbmc.getCondVisibility("Skin.HasSetting(SkinHelper.view.Disabled.%s)" % view_id):
                    listitem.select(selected=True)
                excludefromdisable = False
                try:
                    excludefromdisable = view.attributes['excludefromdisable'].nodeValue == "true"
                except Exception:
                    pass
                if not excludefromdisable:
                    all_views.append(listitem)

        dialog = DialogSelect(
            "DialogSelect.xml",
            "",
            listing=all_views,
            windowtitle=self.addon.getLocalizedString(32013),
            multiselect=True, richlayout=richlayout)
        dialog.doModal()
        result = dialog.result
        del dialog
        if result:
            for item in result:
                view_id = item.getProperty("viewid")
                if item.isSelected():
                    # view is enabled
                    xbmc.executebuiltin("Skin.Reset(SkinHelper.view.Disabled.%s)" % view_id)
                else:
                    # view is disabled
                    xbmc.executebuiltin("Skin.SetBool(SkinHelper.view.Disabled.%s)" % view_id)
    # pylint: enable-msg=too-many-local-variables

    def setforcedview(self):
        '''helper that sets a forced view for a specific content type'''
        content_type = self.params.get("contenttype")
        if content_type:
            current_view = xbmc.getInfoLabel("Skin.String(SkinHelper.ForcedViews.%s)" % content_type)
            if not current_view:
                current_view = "0"
            view_id, view_label = self.selectview(content_type, current_view, True)
            if view_id or view_label:
                xbmc.executebuiltin("Skin.SetString(SkinHelper.ForcedViews.%s,%s)" % (content_type, view_id))
                xbmc.executebuiltin("Skin.SetString(SkinHelper.ForcedViews.%s.label,%s)" % (content_type, view_label))

    @staticmethod
    def get_youtube_listing(searchquery):
        '''get items from youtube plugin by query'''
        lib_path = u"plugin://plugin.video.youtube/kodion/search/query/?q=%s" % searchquery
        return KodiDb().files(lib_path)

    def searchyoutube(self):
        '''helper to search youtube for the given title'''
        xbmc.executebuiltin("ActivateWindow(busydialog)")
        title = self.params.get("title", "")
        window_header = self.params.get("header", "")
        results = []
        for media in self.get_youtube_listing(title):
            if not media["filetype"] == "directory":
                label = media["label"]
                label2 = media["plot"]
                image = ""
                if media.get('art'):
                    if media['art'].get('thumb'):
                        image = (media['art']['thumb'])
                listitem = xbmcgui.ListItem(label=label, label2=label2, iconImage=image)
                listitem.setProperty("path", media["file"])
                results.append(listitem)

        # finished lookup - display listing with results
        xbmc.executebuiltin("dialog.Close(busydialog)")
        dialog = DialogSelect("DialogSelect.xml", "", listing=results, windowtitle=window_header,
                              multiselect=False, richlayout=True)
        dialog.doModal()
        result = dialog.result
        del dialog
        if result:
            if xbmc.getCondVisibility(
                    "Window.IsActive(script-skin_helper_service-CustomInfo.xml) | "
                    "Window.IsActive(movieinformation)"):
                xbmc.executebuiltin("Dialog.Close(movieinformation)")
                xbmc.executebuiltin("Dialog.Close(script-skin_helper_service-CustomInfo.xml)")
                xbmc.sleep(1000)
            xbmc.executebuiltin('PlayMedia("%s")' % result.getProperty("path"))
            del result

    def getcastmedia(self):
        '''helper to show a dialog with all media for a specific actor'''
        xbmc.executebuiltin("ActivateWindow(busydialog)")
        name = self.params.get("name", "")
        window_header = self.params.get("name", "")
        results = []
        items = self.kodidb.castmedia(name)
        items = process_method_on_list(self.kodidb.prepare_listitem, items)
        for item in items:
            if item["file"].startswith("videodb://"):
                item["file"] = "ActivateWindow(Videos,%s,return)" % item["file"]
            else:
                item["file"] = 'PlayMedia("%s")' % item["file"]
            results.append(self.kodidb.create_listitem(item, False))
        # finished lookup - display listing with results
        xbmc.executebuiltin("dialog.Close(busydialog)")
        dialog = DialogSelect("DialogSelect.xml", "", listing=results, windowtitle=window_header, richlayout=True)
        dialog.doModal()
        result = dialog.result
        del dialog
        if result:
            while xbmc.getCondVisibility("System.HasModalDialog"):
                xbmc.executebuiltin("Action(Back)")
                xbmc.sleep(300)
            xbmc.executebuiltin(result.getfilename())
            del result

    def setfocus(self):
        '''helper to set focus on a list or control'''
        control = self.params.get("control")
        fallback = self.params.get("fallback")
        position = self.params.get("position", "0")
        relativeposition = self.params.get("relativeposition")
        if relativeposition:
            position = int(relativeposition) - 1
        count = 0
        if control:
            while not xbmc.getCondVisibility("Control.HasFocus(%s)" % control):
                if xbmc.getCondVisibility("Window.IsActive(busydialog)"):
                    xbmc.sleep(150)
                    continue
                elif count == 20 or (xbmc.getCondVisibility(
                        "!Control.IsVisible(%s) | "
                        "!IntegerGreaterThan(Container(%s).NumItems,0)" % (control, control))):
                    if fallback:
                        xbmc.executebuiltin("Control.SetFocus(%s)" % fallback)
                    break
                else:
                    xbmc.executebuiltin("Control.SetFocus(%s,%s)" % (control, position))
                    xbmc.sleep(50)
                    count += 1

    def setwidgetcontainer(self):
        '''helper that reports the current selected widget container/control'''
        controls = self.params.get("controls", "").split("-")
        if controls:
            xbmc.sleep(50)
            for i in range(10):
                for control in controls:
                    if xbmc.getCondVisibility("Control.IsVisible(%s) + IntegerGreaterThan(Container(%s).NumItems,0)"
                                              % (control, control)):
                        self.win.setProperty("SkinHelper.WidgetContainer", control)
                        return
                xbmc.sleep(50)
        self.win.clearProperty("SkinHelper.WidgetContainer")

    def saveskinimage(self):
        '''let the user select an image and save it to addon_data for easy backup'''
        skinstring = self.params.get("skinstring", "")
        allow_multi = self.params.get("multi", "") == "true"
        header = self.params.get("header", "")
        value = SkinSettings().save_skin_image(skinstring, allow_multi, header)
        if value:
            xbmc.executebuiltin("Skin.SetString(%s,%s)" % (skinstring.encode("utf-8"), value.encode("utf-8")))

    @staticmethod
    def checkskinsettings():
        '''performs check of all default skin settings and labels'''
        SkinSettings().correct_skin_settings()

    def setskinsetting(self):
        '''allows the user to set a skin setting with a select dialog'''
        setting = self.params.get("setting", "")
        org_id = self.params.get("id", "")
        if "$" in org_id:
            org_id = xbmc.getInfoLabel(org_id).decode("utf-8")
        header = self.params.get("header", "")
        SkinSettings().set_skin_setting(setting=setting, window_header=header, original_id=org_id)

    def setskinconstant(self):
        '''allows the user to set a skin constant with a select dialog'''
        setting = self.params.get("setting", "")
        value = self.params.get("value", "")
        header = self.params.get("header", "")
        SkinSettings().set_skin_constant(setting, header, value)

    def setskinconstants(self):
        '''allows the skinner to set multiple skin constants'''
        settings = self.params.get("settings", "").split("|")
        values = self.params.get("values", "").split("|")
        SkinSettings().set_skin_constants(settings, values)

    def setskinshortcutsproperty(self):
        '''allows the user to make a setting for skinshortcuts using the special skinsettings dialogs'''
        setting = self.params.get("setting", "")
        prop = self.params.get("property", "")
        header = self.params.get("header", "")
        SkinSettings().set_skinshortcuts_property(setting, header, prop)

    def togglekodisetting(self):
        '''toggle kodi setting'''
        settingname = self.params.get("setting", "")
        cur_value = xbmc.getCondVisibility("system.getbool(%s)" % settingname)
        if cur_value:
            new_value = "false"
        else:
            new_value = "true"
        xbmc.executeJSONRPC(
            '{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"%s","value":%s}}' %
            (settingname, new_value))

    def setkodisetting(self):
        '''set kodi setting'''
        settingname = self.params.get("setting", "")
        value = self.params.get("value", "")
        is_int = False
        try:
            valueint = int(value)
            is_int = True
            del valueint
        except Exception:
            pass
        if value.lower() == "true":
            value = 'true'
        elif value.lower() == "false":
            value = 'false'
        elif is_int:
            value = '"%s"' % value
        xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue",\
            "params":{"setting":"%s","value":%s}}' % (settingname, value))

    def playtrailer(self):
        '''auto play windowed trailer inside video listing'''
        if not xbmc.getCondVisibility("Player.HasMedia | Container.Scrolling | Container.OnNext | "
                                      "Container.OnPrevious | !IsEmpty(Window(Home).Property(traileractionbusy))"):
            self.win.setProperty("traileractionbusy", "traileractionbusy")
            widget_container = self.params.get("widgetcontainer", "")
            trailer_mode = self.params.get("mode", "").replace("auto_", "")
            allow_youtube = self.params.get("youtube", "") == "true"
            if not trailer_mode:
                trailer_mode = "windowed"
            if widget_container:
                widget_container_prefix = "Container(%s)." % widget_container
            else:
                widget_container_prefix = ""

            li_title = xbmc.getInfoLabel("%sListItem.Title" % widget_container_prefix).decode('utf-8')
            li_trailer = xbmc.getInfoLabel("%sListItem.Trailer" % widget_container_prefix).decode('utf-8')
            if not li_trailer and allow_youtube:
                youtube_result = self.get_youtube_listing("%s Trailer" % li_title)
                if youtube_result:
                    li_trailer = youtube_result[0].get("file")
            # always wait a bit to prevent trailer start playing when we're scrolling the list
            xbmc.Monitor().waitForAbort(3)
            if li_trailer and (li_title == xbmc.getInfoLabel("%sListItem.Title"
                                                             % widget_container_prefix).decode('utf-8')):
                if trailer_mode == "fullscreen" and li_trailer:
                    xbmc.executebuiltin('PlayMedia("%s")' % li_trailer)
                else:
                    xbmc.executebuiltin('PlayMedia("%s",1)' % li_trailer)
                self.win.setProperty("TrailerPlaying", trailer_mode)
            self.win.clearProperty("traileractionbusy")

    def colorpicker(self):
        '''legacy'''
        self.deprecated_method("script.skin.helper.colorpicker")

    def backup(self):
        '''legacy'''
        self.deprecated_method("script.skin.helper.skinbackup")

    def restore(self):
        '''legacy'''
        self.deprecated_method("script.skin.helper.skinbackup")

    def reset(self):
        '''legacy'''
        self.deprecated_method("script.skin.helper.skinbackup")

    def colorthemes(self):
        '''legacy'''
        self.deprecated_method("script.skin.helper.skinbackup")

    def createcolortheme(self):
        '''legacy'''
        self.deprecated_method("script.skin.helper.skinbackup")

    def restorecolortheme(self):
        '''legacy'''
        self.deprecated_method("script.skin.helper.skinbackup")

    def conditionalbackgrounds(self):
        '''legacy'''
        self.deprecated_method("script.skin.helper.backgrounds")

    def splashscreen(self):
        '''helper to show a user defined splashscreen in the skin'''
        import time
        splashfile = self.params.get("file", "")
        duration = int(self.params.get("duration", 5))
        if (splashfile.lower().endswith("jpg") or splashfile.lower().endswith("gif") or
                splashfile.lower().endswith("png") or splashfile.lower().endswith("tiff")):
            # this is an image file
            self.win.setProperty("SkinHelper.SplashScreen", splashfile)
            # for images we just wait for X seconds to close the splash again
            start_time = time.time()
            while (time.time() - start_time) <= duration:
                xbmc.sleep(500)
        else:
            # for video or audio we have to wait for the player to finish...
            xbmc.Player().play(splashfile, windowed=True)
            xbmc.sleep(500)
            while xbmc.getCondVisibility("Player.HasMedia"):
                xbmc.sleep(150)
        # replace startup window with home
        startupwindow = xbmc.getInfoLabel("System.StartupWindow")
        xbmc.executebuiltin("ReplaceWindow(%s)" % startupwindow)
        autostart_playlist = xbmc.getInfoLabel("$ESCINFO[Skin.String(autostart_playlist)]")
        if autostart_playlist:
            xbmc.executebuiltin("PlayMedia(%s)" % autostart_playlist)

    def videosearch(self):
        '''show the special search dialog'''
        xbmc.executebuiltin("ActivateWindow(busydialog)")
        from resources.lib.searchdialog import SearchDialog
        search_dialog = SearchDialog("script-skin_helper_service-CustomSearch.xml",
                                     self.addon.getAddonInfo('path').decode("utf-8"), "Default", "1080i")
        search_dialog.doModal()
        del search_dialog

    def showinfo(self):
        '''shows our special videoinfo dialog'''
        dbid = self.params.get("dbid", "")
        dbtype = self.params.get("dbtype", "")
        from infodialog import show_infodialog
        show_infodialog(dbid, dbtype)

    def deletedir(self):
        '''helper to delete a directory, input can be normal filesystem path or vfs'''
        del_path = self.params.get("path")
        if del_path:
            ret = xbmcgui.Dialog().yesno(heading=xbmc.getLocalizedString(122),
                                         line1=u"%s[CR]%s" % (xbmc.getLocalizedString(125), del_path))
            if ret:
                success = recursive_delete_dir(del_path)
                if success:
                    xbmcgui.Dialog().ok(heading=xbmc.getLocalizedString(19179),
                                        line1=self.addon.getLocalizedString(32014))
                else:
                    xbmcgui.Dialog().ok(heading=xbmc.getLocalizedString(16205),
                                        line1=xbmc.getLocalizedString(32015))

    def overlaytexture(self):
        '''legacy: helper to let the user choose a background overlay from a skin defined folder'''
        skinstring = self.params.get("skinstring", "BackgroundOverlayTexture")
        self.params["skinstring"] = skinstring
        self.params["resourceaddon"] = "resource.images.backgroundoverlays"
        self.params["customfolder"] = "special://skin/extras/bgoverlays/"
        self.params["allowmulti"] = "false"
        self.params["header"] = self.addon.getLocalizedString(32002)
        self.selectimage()

    def busytexture(self):
        '''legacy: helper which lets the user select a busy spinner from predefined spinners in the skin'''
        skinstring = self.params.get("skinstring", "SkinHelper.SpinnerTexture")
        self.params["skinstring"] = skinstring
        self.params["resourceaddon"] = "resource.images.busyspinners"
        self.params["customfolder"] = "special://skin/extras/busy_spinners/"
        self.params["allowmulti"] = "true"
        self.params["header"] = self.addon.getLocalizedString(32006)
        self.selectimage()

    def selectimage(self):
        '''helper which lets the user select an image or imagepath from resourceaddons or custom path'''
        skinsettings = SkinSettings()
        skinstring = self.params.get("skinstring", "")
        skinshortcutsprop = self.params.get("skinshortcutsproperty", "")
        current_value = self.params.get("currentvalue", "")
        resource_addon = self.params.get("resourceaddon", "")
        allow_multi = self.params.get("allowmulti", "false") == "true"
        windowheader = self.params.get("header", "")
        skinhelper_backgrounds = self.params.get("skinhelperbackgrounds", "false") == "true"
        label, value = skinsettings.select_image(
            skinstring, allow_multi=allow_multi, windowheader=windowheader, resource_addon=resource_addon,
            skinhelper_backgrounds=skinhelper_backgrounds, current_value=current_value)
        if label:
            if skinshortcutsprop:
                # write value to skinshortcuts prop
                from skinshortcuts import set_skinshortcuts_property
                set_skinshortcuts_property(skinshortcutsprop, value, label)
            else:
                # write the values to skin strings
                if value.startswith("$INFO"):
                    # we got an dynamic image from window property
                    skinsettings.set_skin_variable(skinstring, value)
                    value = "$VAR[%s]" % skinstring
                skinstring = skinstring.encode("utf-8")
                label = label.encode("utf-8")
                xbmc.executebuiltin("Skin.SetString(%s.label,%s)" % (skinstring, label))
                xbmc.executebuiltin("Skin.SetString(%s.name,%s)" % (skinstring, label))
                xbmc.executebuiltin("Skin.SetString(%s,%s)" % (skinstring, value))
                xbmc.executebuiltin("Skin.SetString(%s.path,%s)" % (skinstring, value))
        del skinsettings

    def dialogok(self):
        '''helper to show an OK dialog with a message'''
        headertxt = self.params.get("header")
        bodytxt = self.params.get("message")
        if bodytxt.startswith(" "):
            bodytxt = bodytxt[1:]
        if headertxt.startswith(" "):
            headertxt = headertxt[1:]
        dialog = xbmcgui.Dialog()
        dialog.ok(heading=headertxt, line1=bodytxt)
        del dialog

    def dialogyesno(self):
        '''helper to show a YES/NO dialog with a message'''
        headertxt = self.params.get("header")
        bodytxt = self.params.get("message")
        yesactions = self.params.get("yesaction", "").split("|")
        noactions = self.params.get("noaction", "").split("|")
        if bodytxt.startswith(" "):
            bodytxt = bodytxt[1:]
        if headertxt.startswith(" "):
            headertxt = headertxt[1:]
        if xbmcgui.Dialog().yesno(heading=headertxt, line1=bodytxt):
            for action in yesactions:
                xbmc.executebuiltin(action.encode("utf-8"))
        else:
            for action in noactions:
                xbmc.executebuiltin(action.encode("utf-8"))

    def textviewer(self):
        '''helper to show a textviewer dialog with a message'''
        headertxt = self.params.get("header", "")
        bodytxt = self.params.get("message", "")
        if bodytxt.startswith(" "):
            bodytxt = bodytxt[1:]
        if headertxt.startswith(" "):
            headertxt = headertxt[1:]
        xbmcgui.Dialog().textviewer(headertxt, bodytxt)

    def fileexists(self):
        '''helper to let the skinner check if a file exists
        and write the outcome to a window prop or skinstring'''
        filename = self.params.get("file")
        skinstring = self.params.get("skinstring")
        windowprop = self.params.get("winprop")
        if xbmcvfs.exists(filename):
            if windowprop:
                self.win.setProperty(windowprop, "exists")
            if skinstring:
                xbmc.executebuiltin("Skin.SetString(%s,exists)" % skinstring)
        else:
            if windowprop:
                self.win.clearProperty(windowprop)
            if skinstring:
                xbmc.executebuiltin("Skin.Reset(%s)" % skinstring)

    def stripstring(self):
        '''helper to allow the skinner to strip a string and write results to a skin string'''
        splitchar = self.params.get("splitchar")
        if splitchar.upper() == "[SPACE]":
            splitchar = " "
        skinstring = self.params.get("string")
        if not skinstring:
            skinstring = self.params.get("skinstring")
        output = self.params.get("output")
        index = self.params.get("index", 0)
        skinstring = skinstring.split(splitchar)[int(index)]
        self.win.setProperty(output, skinstring)

    def getfilename(self, filename=""):
        '''helper to display a sanitized filename in the vidoeinfo dialog'''
        output = self.params.get("output")
        if not filename:
            filename = xbmc.getInfoLabel("ListItem.FileNameAndPath")
        if not filename:
            filename = xbmc.getInfoLabel("ListItem.FileName")
        if "filename=" in filename:
            url_params = dict(urlparse.parse_qsl(filename))
            filename = url_params.get("filename")
        self.win.setProperty(output, filename)

    def getplayerfilename(self):
        '''helper to parse the filename from a plugin (e.g. emby) filename'''
        filename = xbmc.getInfoLabel("Player.FileNameAndPath")
        if not filename:
            filename = xbmc.getInfoLabel("Player.FileName")
        self.getfilename(filename)

    def getpercentage(self):
        '''helper to calculate the percentage of 2 numbers and write results to a skinstring'''
        total = int(params.get("total"))
        count = int(params.get("count"))
        roundsteps = self.params.get("roundsteps")
        skinstring = self.params.get("skinstring")
        percentage = int(round((1.0 * count / total) * 100))
        if roundsteps:
            roundsteps = int(roundsteps)
            percentage = percentage + (roundsteps - percentage) % roundsteps
        xbmc.executebuiltin("Skin.SetString(%s,%s)" % (skinstring, percentage))

    def setresourceaddon(self):
        '''helper to let the user choose a resource addon and set that as skin string'''
        from resourceaddons import setresourceaddon
        addontype = self.params.get("addontype", "")
        skinstring = self.params.get("skinstring", "")
        setresourceaddon(addontype, skinstring)

    def checkresourceaddons(self):
        '''allow the skinner to perform a basic check if some required resource addons are available'''
        from resourceaddons import checkresourceaddons
        addonslist = self.params.get("addonslist", [])
        if addonslist:
            addonslist = addonslist.split("|")
        checkresourceaddons(addonslist)
Exemple #41
0
class ScreenRant(object):
    def __init__(self, sysARG):
        log('__init__, sysARG = ' + str(sysARG))
        self.sysARG = sysARG
        self.cache = SimpleCache()

    def openURL(self, url):
        try:
            log('openURL, url = ' + str(url))
            cacheresponse = self.cache.get(ADDON_NAME +
                                           '.openURL, url = %s' % url)
            if not cacheresponse:
                request = urllib2.Request(url)
                request.add_header(
                    'User-Agent',
                    'Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)'
                )
                cacheresponse = urllib2.urlopen(request,
                                                timeout=TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s' % url,
                               cacheresponse,
                               expiration=datetime.timedelta(minutes=15))
            return cacheresponse
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON,
                                          4000)
            return ''

    def buildMenu(self, items):
        for item in items:
            self.addDir(*item)
        self.addYoutube(LANGUAGE(30006),
                        'plugin://plugin.video.youtube/user/ScreenRant/')

    def browse(self, name, url):
        log('browse, name = ' + name)
        soup = BeautifulSoup(self.openURL(BASE_URL + url), "html.parser")
        videos = soup('div', {'class': 'w-browse-clip'})
        if name == LANGUAGE(30004): idx = 1
        else: idx = 0
        videos = videos[idx]('article', {'class': 'browse-clip'})
        for video in videos:
            link = BASE_URL + video.find('a').attrs['href']
            try:
                thumb = video('div', {'class': 'responsive-img'
                                      })[0].find('source').attrs['srcset']
            except:
                thumb = (video(
                    'div',
                    {'class': 'responsive-img'
                     })[0].find('source').attrs['data-srcset']).split('?')[0]
            try:
                label = video(
                    'h3', {'class': 'bc-title'})[0].find('a').attrs['title']
            except:
                label = (video(
                    'div', {'class': 'info-wrapper'})[0].find('a').get_text())
            try:
                airdate = datetime.datetime.strptime(
                    video('div',
                          {'class': 'bc-details'})[0].find('time').get_text(),
                    '%b %d, %Y')
            except:
                airdate = datetime.datetime.now()
            airdate = airdate.strftime('%Y-%m-%d')
            plot = '%s - %s' % (label, airdate)
            try:
                dur = (video('a', {'class': 'bc-img-link'
                                   })[0].find('span').get_text()).split(':')
                if len(dur) == 3:
                    h, m, s = dur
                    duration = int(h) * 3600 + int(m) * 60 + int(s)
                else:
                    m, s = dur
                    duration = int(m) * 60 + int(s)
            except:
                duration = '0'
            infoLabels = {
                "mediatype": "episode",
                "label": label,
                "title": label,
                "duration": duration,
                "plot": plot,
                "aired": airdate
            }
            infoArt = {
                "thumb": thumb,
                "poster": thumb,
                "fanart": FANART,
                "icon": thumb,
                "logo": thumb
            }
            vidID = thumb.split('/')[9].split('-')
            link = VIDEO_URL % (vidID[5].split('_')[2], vidID[2])
            self.addLink(label, link, 9, infoLabels, infoArt, len(videos))

        next = soup('div', {'class': 'wp-pagenavi'})
        if name == LANGUAGE(30004) or len(next) == 0: return
        current_pg = int(next[0]('span', {'class': 'current'})[0].get_text())
        next_url = '/video/page/%s' % (str(current_pg + 1))
        next_label = next[0]('span', {'class': 'pages'})[0].get_text()
        self.addDir(next_label, next_url, 1)

    def playVideo(self, name, url):
        log('playVideo')
        liz = xbmcgui.ListItem(name, path=url)
        liz.setProperty('inputstreamaddon', 'inputstream.adaptive')
        liz.setProperty('inputstream.adaptive.manifest_type', 'hls')
        xbmcplugin.setResolvedUrl(int(self.sysARG[1]), True, liz)

    def addYoutube(self, name, url):
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label": name, "title": name})
        liz.setArt({'thumb': ICON, 'fanart': FANART})
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),
                                    url=url,
                                    listitem=liz,
                                    isFolder=True)

    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb': ICON, 'fanart': FANART})
        else: liz.setArt(infoArt)
        u = self.sysARG[0] + "?url=" + urllib.quote_plus(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),
                                    url=u,
                                    listitem=liz,
                                    totalItems=total)

    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb': ICON, 'fanart': FANART})
        else: liz.setArt(infoArt)
        u = self.sysARG[0] + "?url=" + urllib.quote_plus(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),
                                    url=u,
                                    listitem=liz,
                                    isFolder=True)

    def getParams(self):
        return dict(urlparse.parse_qsl(self.sysARG[2][1:]))

    def run(self):
        params = self.getParams()
        try:
            url = urllib.unquote_plus(params["url"])
        except:
            url = None
        try:
            name = urllib.unquote_plus(params["name"])
        except:
            name = None
        try:
            mode = int(params["mode"])
        except:
            mode = None
        log("Mode: " + str(mode))
        log("URL : " + str(url))
        log("Name: " + str(name))

        if mode == None: self.buildMenu(MAIN_MENU)
        elif mode == 1: self.browse(name, url)
        elif mode == 9: self.playVideo(name, url)

        xbmcplugin.setContent(int(self.sysARG[1]), CONTENT_TYPE)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_UNSORTED)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_NONE)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_LABEL)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_TITLE)
        xbmcplugin.endOfDirectory(int(self.sysARG[1]), cacheToDisc=True)
Exemple #42
0
class NBC(object):
    def __init__(self):
        log('__init__')
        self.cache = SimpleCache()
        self.ydl = YoutubeDL()

    def openURL(self, url):
        log('openURL, url = ' + str(url))
        try:
            cacheResponce = self.cache.get(ADDON_NAME +
                                           '.openURL, url = %s' % url)
            if not cacheResponce:
                request = urllib2.Request(url)
                responce = urllib2.urlopen(request, timeout=TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s' % url,
                               responce,
                               expiration=datetime.timedelta(hours=1))
            return self.cache.get(ADDON_NAME + '.openURL, url = %s' % url)
        except urllib2.URLError as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
        except socket.timeout as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON,
                                          4000)
            return ''

    def buildMenu(self, items):
        for item in items:
            self.addDir(*item)
        self.addYoutube("Browse Youtube",
                        'plugin://plugin.video.youtube/user/NBC/')

    def browseEpisodes(self, url=None):
        log('browseEpisodes')
        if url is None:
            url = VIDEO_URL + FILTER % ('type', 'Full%20Episode')
        items = json.loads(self.openURL(url))
        if items and 'data' in items:
            for item in items['data']:
                path = item['attributes']['fullUrl']
                aired = str(item['attributes']['airdate']).split('T')[0]
                duration = int(item['attributes']['runTime'])
                plot = item['attributes']['description']
                title = item['attributes']['title']

                showTitle = ''
                for show in item['attributes']['categories']:
                    if show.startswith('Series'):
                        showTitle = show.split('Series/')[1]
                        break

                try:
                    episodeNumber = int(item['attributes']['episodeNumber'])
                except:
                    episodeNumber = 0
                try:
                    seasonNumber = int(item['attributes']['seasonNumber'])
                except:
                    seasonNumber = 0

                try:
                    thumb = ICON
                    for image in items['included']:
                        if image['id'] == item['relationships']['image'][
                                'data']['id']:
                            thumb = BASE_URL + image['attributes']['path']
                            break
                except:
                    thumb = ICON

                seinfo = ('S' + ('0' if seasonNumber < 10 else '') +
                          str(seasonNumber) + 'E' +
                          ('0' if episodeNumber < 10 else '') +
                          str(episodeNumber))
                label = '%s - %s' % (
                    showTitle, title
                ) if seasonNumber + episodeNumber == 0 else '%s - %s - %s' % (
                    showTitle, seinfo, title)
                infoLabels = {
                    "mediatype": "episodes",
                    "label": label,
                    "title": label,
                    "TVShowTitle": showTitle,
                    "plot": plot,
                    "aired": aired,
                    "duration": duration,
                    "season": seasonNumber,
                    "episode": episodeNumber
                }
                infoArt = {
                    "thumb": thumb,
                    "poster": thumb,
                    "fanart": FANART,
                    "icon": ICON,
                    "logo": ICON
                }
                self.addLink(label, path, 9, infoLabels, infoArt,
                             len(items['data']))

            try:
                next_page = items['links']['next']
            except:
                next_page = None
            if next_page:
                self.addDir('>> Next', next_page, 1)

    def browseShows(self, url=None):
        log('browseShows')
        if url is None:
            url = SHOWS_URL
        items = json.loads(self.openURL(url))
        if items and 'data' in items:
            for item in items['data']:
                showTitle = item['attributes']['shortTitle']
                plot = (item['attributes']['shortDescription']
                        or showTitle).replace('<p>', '').replace('</p>', '')
                path = VIDEO_URL + FILTER % ('show', item['id'])
                vidID = item['relationships']['aggregates']['data']['id']

                try:
                    thumb = ICON
                    for image in items['included']:
                        if image['id'] == item['relationships']['image'][
                                'data']['id']:
                            thumb = BASE_URL + image['attributes']['path']
                            break
                except:
                    thumb = ICON

                myURL = json.dumps({"url": path, "vidID": vidID})
                infoLabels = {
                    "mediatype": "tvshows",
                    "label": showTitle,
                    "title": showTitle,
                    "TVShowTitle": showTitle,
                    "plot": plot
                }
                infoArt = {
                    "thumb": thumb,
                    "poster": thumb,
                    "fanart": FANART,
                    "icon": ICON,
                    "logo": ICON
                }
                self.addDir(showTitle, myURL, 0, infoLabels, infoArt)

            try:
                next_page = items['links']['next']
            except:
                next_page = None
            if next_page:
                self.addDir('>> Next', next_page, 2)

    def resolveURL(self, url):
        log('resolveURL')
        myURL = json.loads(url)
        items = json.loads(self.openURL(SHOW_URL % myURL['vidID']))
        if items and 'data' in items:
            for item in items['data']['attributes']['videoTypes']:
                self.browseEpisodes(myURL['url'] + FILTER %
                                    ('type', urllib2.quote(item)))

    def playVideo(self, name, url, liz=None):
        log('playVideo')
        self.ydl.add_default_info_extractors()
        with self.ydl:
            result = self.ydl.extract_info(url, download=False)
            url = result['manifest_url']
            liz = xbmcgui.ListItem(name, path=url)
            xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)

    def addYoutube(self, name, url):
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label": name, "title": name})
        liz.setArt({'thumb': ICON, 'fanart': FANART})
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                    url=url,
                                    listitem=liz,
                                    isFolder=True)

    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name,
                            "genre": "News"
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)

        if infoArt == False:
            liz.setArt({'thumb': ICON, 'fanart': FANART})
        else:
            liz.setArt(infoArt)
        u = sys.argv[0] + "?url=" + urllib.quote_plus(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                    url=u,
                                    listitem=liz,
                                    totalItems=total)

    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name,
                            "genre": "News"
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False:
            liz.setArt({'thumb': ICON, 'fanart': FANART})
        else:
            liz.setArt(infoArt)
        u = sys.argv[0] + "?url=" + urllib.quote_plus(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                    url=u,
                                    listitem=liz,
                                    isFolder=True)
Exemple #43
0
class BackgroundWindow(xbmcgui.WindowXMLDialog):
    def __init__(self, *args, **kwargs):
        xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
        if DISABLE_TRAKT: xbmcgui.Window(10000).setProperty('script.trakt.paused','true')
        self.playList  = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)        
        self.fileCount = 0
        self.cache     = SimpleCache()
        self.myPlayer  = Player()
        self.myPlayer.myBackground = self
        
        
    def onInit(self):
        self.winid = xbmcgui.Window(xbmcgui.getCurrentWindowDialogId())
        self.winid.setProperty('ss_time', 'okay' if REAL_SETTINGS.getSetting("Time") == 'true' else 'nope')
        self.myPlayer.play(self.buildPlaylist())

        if saveVolume(): 
            setVolume(int(REAL_SETTINGS.getSetting('SetVolume')))
        setRepeat('all')
        
        
    def onAction(self, act):
        log('onAction')
        if KEYLOCK and act.getId() != ACTION_STOP: return
        self.onClose()
            
            
    def onClose(self):
        log('onClose')
        setRepeat(REAL_SETTINGS.getSetting('RepeatState').lower())
        xbmcgui.Window(10000).clearProperty('script.trakt.paused')
        xbmcgui.Window(10000).clearProperty('%s.Running'%(ADDON_ID))
        setVolume(int(xbmcgui.Window(10000).getProperty('%s.RESTORE'%ADDON_ID)))
        self.myPlayer.stop()
        self.playList.clear()
        self.close()
        
        
    def getDirectory(self, path, media='video', ignore='false', method='episode', order='ascending', end=0, start=0, filter={}):
        log('getDirectory, path = %s'%(path))
        cacheresponse = self.cache.get('%s.getDirectory, path = %s'%(ADDON_NAME,path))
        if not cacheresponse:
            if RANDOM_PLAY: method = 'random'
            json_query    = ('{"jsonrpc":"2.0","method":"Files.GetDirectory","params":{"directory":"%s","media":"%s","sort":{"ignorearticle":%s,"method":"%s","order":"%s"},"limits":{"end":%s,"start":%s}},"id":1}' % (path, media, ignore, method, order, end, start))
            cacheresponse = (sendJSON(json_query))
            if 'result' in cacheresponse: 
                self.cache.set('%s.getDirectory, path = %s'%(ADDON_NAME,path), json.dumps(cacheresponse), expiration=datetime.timedelta(minutes=15))
                return cacheresponse
        else: return json.loads(cacheresponse)


    def buildDirectory(self, path, limit):
        log('buildDirectory, path = %s'%(path))
        itemLST   = []
        dirLST    = []
        with busy_dialog():
            response = self.getDirectory(path, end=limit).get('result',{}).get('files',[])
            for idx, item in enumerate(response):
                if self.fileCount > limit: break
                file     = item.get('file','')
                fileType = item.get('filetype','')
                if fileType == 'file':
                    self.fileCount += 1
                    itemLST.append(file)
                elif fileType == 'directory': 
                    dirLST.append(file)  
            if self.fileCount < limit:
                for dir in dirLST:
                    if self.fileCount > limit: break 
                    itemLST.extend(self.buildDirectory(dir, limit))
            return itemLST
            

    def buildItem(self, responce):
        log('buildItem')
        if 'result' in responce and 'filedetails' in responce['result']: key = 'filedetails'
        elif 'result' in responce and 'files' in responce['result']: key = 'files'
        else: xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
        for item in responce['result'][key]:
            if key == 'files' and item.get('filetype','') == 'directory': continue
            yield responce['result'][key]['file']


    def buildPlaylist(self):
        log('buildPlaylist')
        self.playList.clear()
        xbmc.sleep(100)
        
        if not SINGLE_FLE: 
            playListItem = self.buildDirectory(VIDEO_PATH, VIDEO_LIMIT)
        elif PLAYLIST_FLE: 
            playListItem = self.buildDirectory(VIDEO_FILE, VIDEO_LIMIT)
        elif not VIDEO_FILE.startswith(('plugin://','upnp://','pvr://')): 
            playListItem = list(self.buildItem(getFileDetails(VIDEO_FILE)))
        else: return VIDEO_FILE
            
        for idx, playItem in enumerate(playListItem): 
            self.playList.add(playItem, index=idx)
            
        if RANDOM_PLAY: 
            self.playList.shuffle()
        else: 
            self.playList.unshuffle()
        return self.playList
Exemple #44
0
class FunnyOrDie(object):
    def __init__(self):
        log('__init__')
        self.cache   = SimpleCache()
           
           
    def openURL(self, url):
        log('openURL, url = ' + str(url))
        try:
            cacheresponse = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
            if not cacheresponse:
                request = urllib2.Request(url)
                response = urllib2.urlopen(request, timeout = TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, response, expiration=datetime.timedelta(days=1))
            return self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
            return ''
         
         
    @use_cache(1)
    def getData(self):
        try:
            soup = BeautifulSoup(self.openURL(CAT_URL), "html.parser")
            return json.loads(re.compile("data-react-props='(.*?)'>", re.DOTALL ).findall(str(soup('div' , {'class': 'action-bar'})))[0])
        except Exception as e: 
            log("getData Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
            return None
         
         
    def getSorts(self):
        log('getSorts')
        getData = self.getData()
        if getData is None: return
        for sort in getData['sortOptions']: yield (sort['title'], '%s/%s'%(sort['key'], sort['date_filter']), 0)
        
        
    def getCategories(self, url):
        log('getCategories')
        getData = self.getData()
        if getData is None: return
        for cat in getData['categoryOptions']: yield (cat['title'], json.dumps({"url":'%s/%s/%s'%(cat['category'], cat['grade'], url), "page":1}), 1)

        
    def buildMenu(self, items, yt=False):
        for item in items: self.addDir(*item)
        if yt: self.addYoutube("Browse Youtube" , 'plugin://plugin.video.youtube/user/funnyordie/')
         
        
    def browseVideos(self, name, myurl):
        log('browse, ' + name)
        myurl = json.loads(myurl)
        url   = myurl['url']
        page  = myurl['page']
        soup  = BeautifulSoup(self.openURL(VID_URL%(url,page)), "html.parser")
        videos = soup('div' , {'class': 'media-preview-crop'})
        if len(videos) == 0: return
        for video in videos:
            vidurl= BASE_URL + video.find_all('a')[0].attrs['href']
            title = video.find_all('a')[0].attrs['title']
            thumb = (video.find_all('a')[0]('img' , {'class': 'media-preview-thumbnail'})[0].attrs['data-src'] or ICON)
            duration = video.find_all('a')[0]('span' , {'class': 'media-video-duration'})[0].get_text()
            try:
                runtime = duration.split(':')
                if len(runtime) == 3:
                    h, m, s = runtime
                    duration = int(h) * 3600 + int(m) * 60 + int(s)
                else:
                    m, s = runtime   
                    duration = int(m) * 60 + int(s)
            except: duration = duration
            infoLabels   = {"mediatype":"episode","label":title ,"title":title,"duration":duration,"plot":title}
            infoArt      = {"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON}
            CONTENT_TYPE = 'episodes'
            self.addLink(title, vidurl, 9, infoLabels, infoArt, len(videos))
        myurl = json.dumps({"url":url,"page":page + 1})
        self.addDir('>> Next', myurl, 1)

        
    def playVideo(self, name, url, liz=None):
        log('playVideo')
        info = getVideoInfo(url,QUALITY,True)
        if info is None: return
        info = info.streams()
        url  = info[0]['xbmc_url']
        liz  = xbmcgui.ListItem(name, path=url)
        if 'subtitles' in info[0]['ytdl_format']: liz.setSubtitles([x['url'] for x in info[0]['ytdl_format']['subtitles'].get('en','') if 'url' in x])
        xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)

        
    def addYoutube(self, name, url):
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label":name,"title":name} )
        liz.setArt({'thumb':ICON,'fanart':FANART})
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=url,listitem=liz,isFolder=True)
        
           
    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,totalItems=total)


    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
Exemple #45
0
class StudioLogos():
    """Helper class for studio logo images"""
    def __init__(self, simplecache=None):
        """Initialize - optionaly provide simplecache object"""
        if not simplecache:
            from simplecache import SimpleCache
            self.cache = SimpleCache()
        else:
            self.cache = simplecache

    @use_cache(14)
    def get_studio_logo(self, studios, lookup_path):
        """get the studio logo for the given studio string(s)"""
        if not studios:
            return {}
        result = {}
        if not isinstance(studios, list):
            studios = studios.split(" / ")
        result["Studio"] = studios[0]
        result['Studios'] = "[CR]".join(studios)
        result['StudioLogo'] = self.match_studio_logo(
            studios, self.get_studio_logos(lookup_path))
        return result

    def get_studio_logos(self, lookup_path):
        """get all studio logos"""
        cache_str = u"SkinHelper.StudioLogos"
        cache = self.cache.get(cache_str, checksum=lookup_path)
        if cache:
            return cache
        # no cache - start lookup
        all_logos = {}
        if lookup_path.startswith("resource://"):
            all_logos = self.get_resource_addon_files(lookup_path)
        else:
            if not (lookup_path.endswith("/") or lookup_path.endswith("\\")):
                lookup_path = lookup_path + os.sep
                all_logos = self.list_files_in_path(lookup_path)
        # save in cache and return
        self.cache.set(cache_str,
                       all_logos,
                       expiration=timedelta(days=14),
                       checksum=lookup_path)
        return all_logos

    @staticmethod
    def match_studio_logo(studios, studiologos):
        """try to find a matching studio logo"""
        studiologo = ""
        for studio in studios:
            if studiologo:
                break
            studio = studio.lower()
            # find logo normal
            if studio in studiologos:
                studiologo = studiologos[studio]
            if not studiologo:
                # find logo by substituting characters
                if " (" in studio:
                    studio = studio.split(" (")[0]
                    if studio in studiologos:
                        studiologo = studiologos[studio]
            if not studiologo:
                # find logo by substituting characters for pvr channels
                if " HD" in studio:
                    studio = studio.replace(" HD", "")
                elif " " in studio:
                    studio = studio.replace(" ", "")
                if studio in studiologos:
                    studiologo = studiologos[studio]
        return studiologo

    @use_cache(90)
    def get_resource_addon_files(self, resourcepath):
        """get listing of all files (eg studio logos) inside a resource image addonName
        read data from our permanent cache file to prevent that we have to query the resource addon"""
        return self.list_files_in_path(resourcepath)

    @staticmethod
    def list_files_in_path(filespath):
        """used for easy matching of studio logos"""
        all_files = {}
        dirs, files = xbmcvfs.listdir(filespath)
        if "/" in filespath:
            sep = "/"
        else:
            sep = "\\"
        for file in files:
            file = try_decode(file)
            name = file.split(".png")[0].lower()
            all_files[name] = filespath + file
        for directory in dirs:
            directory = try_decode(directory)
            files = xbmcvfs.listdir(os.path.join(filespath, directory) +
                                    sep)[1]
            for file in files:
                file = try_decode(file)
                name = directory + "/" + file.split(".png")[0].lower()
                all_files[name] = filespath + directory + sep + file
        # return the list
        return all_files
Exemple #46
0
class EarthCam(object):
    def __init__(self):
        log('__init__')
        self.cache = SimpleCache()
           
           
    def openURL(self, url, force=False):
        log('openURL, url = ' + str(url))
        try:
            cacheresponse = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
            if not cacheresponse or force:
                request = urllib2.Request(url)
                request.add_header('User-Agent','Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)')
                response = urllib2.urlopen(request, timeout = TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, response, expiration=datetime.timedelta(days=1))
            return self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
            return ''
         
         
    def buildMenu(self, items):
        for item in items: self.addDir(*item)
        self.addYoutube(LANGUAGE(30005), 'plugin://plugin.video.youtube/user/earthcam/')
            
            
    def browse(self, name, url):
        log('browse, ' + name)
        soup = BeautifulSoup(self.openURL(url), "html.parser")
        if len(soup) == 0: return
        networks = soup('a', {'class': 'locationLink'})
        for region in networks:
            title = region.get_text()
            url   = NET_URL + region.attrs['href']
            thumb = LOGO_URL%(urllib.quote(title))
            infoLabels = {"mediatype":"files","label":title ,"title":title}
            infoArt    = {"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON}  
            self.addDir(title,url,2,infoLabels,infoArt)

            
    def browseVideos(self, name, url):
        log('browseVideos, ' + name)
        soup = BeautifulSoup(self.openURL(url), "html.parser")
        if len(soup) == 0: return
        featured = soup('div', {'class': 'col-lg-3 col-md-4 col-sm-5 col-xs-12'})
        for cam in featured:
            feat  = cam('a', {'class': 'listImg'})
            url   = cam('a', {'class': 'featuredTitleLink'})[0].attrs['href']
            if url.endswith('php'): continue
            thumb = feat[0].find('img').attrs['src']
            title = feat[0].find('img').attrs['title']
            infoLabels = {"mediatype":"files","label":title ,"title":title}
            infoArt    = {"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON}  
            self.addDir(title,url,8,infoLabels,infoArt) 

        
    def resolveURL(self, name, url):
        log('resolveURL, url = ' + str(url))
        try:
            response = self.openURL(url)
            results = json.loads(re.compile("var json_base					= (.*?);").findall(response)[0], strict=False)
            pageids  = (json.loads(re.compile("js_cam_list				= (.*?);").findall(response)[0], strict=False) or [url.split('?cam=')[1]])
        except: return
        
        for id in pageids:
            try: results = results["cam"][id]
            except: return
            thumb   = results["thumbnail_512"]
            ofset   = results.get("timezone_offset","0")
            plot    = (results["description"] or results["title"])
            infoArt = {"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON}
            if  results["liveon"] == "true":
                label      = '%s - %s, %s Live (HLS)'%(results["camtext"], name,results["country"])
                infoLabels = {"mediatype":"episode","label":label,"title":label,"plot":plot}
                liveurl = ('http:%s%s'%(results["html5_streamingdomain"],results["html5_streampath"]))
                self.addLink(label, liveurl, 9, infoLabels, infoArt, len(pageids))
                # label      = '%s,%s - Live (FLV)'%(results["long_title"],results["country"])
                # infoLabels = {"mediatype":"episode","label":label ,"title":label,"plot":plot}
                # liveurl = ('%s%s'%(results["streamingdomain"],results["livestreamingpath"]))
                # self.addLink(label, liveurl, 9, infoLabels, infoArt, len(pageids))
            elif  results["timelapseon"] == "true":
                label      = '%s - %s, %s Timelapse'%(results["camtext"], name,results["country"])
                infoLabels = {"mediatype":"episode","label":label,"title":label,"plot":plot}
                liveurl = ('http:%s%s'%(results["timelapsedomain"],results["timelapsepath"]))
                self.addLink(label, liveurl, 9, infoLabels, infoArt, len(pageids))
            elif  results["archiveon"] == "true":
                label      = '%s - %s, %s Archive'%(results["camtext"], name,results["country"])
                infoLabels = {"mediatype":"episode","label":label,"title":label,"plot":plot}
                liveurl = ('http:%s%s'%(results["archivedomain"],results["archivepath"]))
                self.addLink(label, liveurl, 9, infoLabels, infoArt, len(pageids))
                

    def prepareLink(self, url):
        log('prepareLink, url = ' + str(url))
        try:
            if len(re.findall('http[s]?://www.youtube.com/watch', url)) > 0: return 'plugin://plugin.video.youtube/play/?video_id=%s'%(url.split('/watch?v=')[1])
            elif url.lower().endswith(".m3u8"): return url.replace('playlist', re.search(r'^([^#].+)\.m3u8$', self.openURL(url, True), re.MULTILINE).group(1))
        except: return None
        return url

     
    def playVideo(self, name, url):
        log('playVideo')
        url = self.prepareLink(url)
        if url is None: return
        liz = xbmcgui.ListItem(name, path=url)
        # if url.endswith(".m3u8"):
            # liz.setProperty('inputstreamaddon','inputstream.adaptive')
            # liz.setProperty('inputstream.adaptive.manifest_type','hls')
        xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)

        
    def addYoutube(self, name, url):
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label":name,"title":name} )
        liz.setArt({'thumb':ICON,'fanart':FANART})
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=url,listitem=liz,isFolder=True)
        
           
    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,totalItems=total)


    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
Exemple #47
0
class CBR(object):
    def __init__(self):
        log('__init__')
        self.cache   = SimpleCache()

           
    def openURL(self, url):
        try:
            log('openURL, url = ' + str(url))
            cacheresponse = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
            if not cacheresponse:
                request = urllib2.Request(url)
                request.add_header('User-Agent','Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)')
                cacheresponse = urllib2.urlopen(request, timeout=TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, cacheresponse, expiration=datetime.timedelta(minutes=15))
            return cacheresponse
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
            return ''
         

    def buildMenu(self, items):
        for item in items: self.addDir(*item)
        self.addYoutube(LANGUAGE(30006), 'plugin://plugin.video.youtube/channel/UCuCk_7b2_4uSr6y5hFmjuMQ/')
        
        
    def browse(self, url):
        log('browse, url = ' + str(url))
        soup   = BeautifulSoup(self.openURL(url), "html.parser")
        videos = soup('div', {'class': 'thumb-wrap'})
        videos.extend(soup('article', {'class': 'thumb-wrap'}))
        for video in videos:
            link  = video('div', {'class': 'img-wrapper'})[0].find('a').attrs['href']
            thumb = video('div', {'class': 'responsiveImg'})[0].find('source').attrs['srcset']
            try: label = video('strong', {'class': 'title'})[0].find('a').attrs['title']
            except: label = (video('div', {'class': 'info-wrapper'})[0].find('a').get_text())
            try: airdate = datetime.datetime.strptime(video('div', {'class': 'details'})[0].find('time').get_text(), '%m.%d.%y')
            except: airdate = datetime.datetime.now()
            airdate = airdate.strftime('%Y-%m-%d')
            plot    = '%s - %s'%(label,airdate)
            try: 
                dur = (video('div', {'class': 'img-wrapper'})[0].find('span').get_text()).split(':')
                if len(dur) == 3:
                    h, m, s = dur
                    duration  = int(h) * 3600 + int(m) * 60 + int(s)
                else:
                    m, s = dur   
                    duration  = int(m) * 60 + int(s)
            except: duration = '0'
            infoLabels = {"mediatype":"episode","label":label ,"title":label,"duration":duration,"plot":plot,"aired":airdate}
            infoArt    = {"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":thumb,"logo":thumb}
            vidID      = ((thumb.split('/')[8]).split('-')[5]).split('_')
            link       = VIDEO_URL%(vidID[2],vidID[0])
            self.addLink(label, link, 9, infoLabels, infoArt, len(videos))

        next = soup('a', {'class': 'nextpostslink'})  
        if len(next) == 0: return
        next_url   = next[0].attrs['href']
        next_label = soup('span', {'class': 'pages'})[0].get_text()
        self.addDir(next_label, next_url, 1)
        
        
    def playVideo(self, name, url):
        log('playVideo')
        liz  = xbmcgui.ListItem(name, path=url)
        liz.setProperty('inputstreamaddon','inputstream.adaptive')
        liz.setProperty('inputstream.adaptive.manifest_type','hls') 
        xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)
        
        
    def addYoutube(self, name, url):
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label":name,"title":name} )
        liz.setArt({'thumb':ICON,'fanart':FANART})
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=url,listitem=liz,isFolder=True)
        
           
    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,totalItems=total)


    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
class CC(object):
    def __init__(self):
        log('__init__')
        self.cache = SimpleCache()
           
           
    def openURL(self, url):
        log('openURL, url = ' + str(url))
        try:
            cacheresponse = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
            if not cacheresponse:
                request = urllib2.Request(url)              
                response = urllib2.urlopen(request, timeout = TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, response, expiration=datetime.timedelta(days=1))
            return self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            if str(e).startswith('HTTP Error 500'): return ''
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
            return ''
         
         
    def buildMenu(self, items):
        for item in items: self.addDir(*item)
        self.addYoutube(LANGUAGE(30006), 'plugin://plugin.video.youtube/user/comedycentral/')
            
            
    def browse(self, name, url):
        log('browse, ' + name)
        response = self.openURL(url)
        if len(response) == 0: return
        try: items = json.loads(re.search('var triforceManifestFeed = (.+?);\n',response).group(1))
        except: items = json.loads(re.search('var triforceManifestURL = "(.+?)";',response).group(1))  
        try: thumb = (response.split('//meta[@property="og:image"]/@content')[0].strip() or ICON)
        except: thumb = ICON
        if not thumb.endswith(('.png','.jpg')): thumb = ICON
        elif thumb.startswith('//'): thumb = 'http:%s'%thumb
        if items and 'manifest' not in items: return
        for item in items['manifest']['zones']:
            if item in ('header', 'footer', 'ads-reporting', 'ENT_M171'): continue
            try: result = items['manifest']['zones'][item]['feed']
            except: result = None
            if result is None: continue
            try: ent_code = result.split('/feeds/')[1].split('/')[0]
            except:
                try: ent_code = result.split('/modules/')[1].split('/')[0]
                except: ent_code = ''
            ent_code = ent_code.split('_cc')[0].split('_tosh')[0]
            try: jsonResponse = json.loads(self.openURL(result))['result']
            except: log('browse, jsonResponse failed! ' + str(jsonResponse))
            if ent_code == 'ent_m081': return self.buildEpisodes(name, url, jsonResponse, jsonResponse['episodes'])
            elif ent_code == 'ent_m013': return self.buildEpisodes(name, url, jsonResponse, jsonResponse['episodes'])
            elif ent_code in ['ent_m100','ent_m150']:
                for item in jsonResponse['data']['items']:
                    if ent_code == 'ent_m100' and name == LANGUAGE(30008): self.buildShow(item)
                    elif ent_code == 'ent_m150' and name == LANGUAGE(30004):
                        for show in item['sortedItems']: self.buildShow(show)


    def buildShow(self, show):
        vid_url = (show.get('canonicalURL','') or show.get('url',None))
        title = (show.get('title','')          or show.get('shortTitle',None))
        plot  = (show.get('description','')    or show.get('shortDescription','') or title)
        if vid_url is None or title is None or not vid_url.startswith(BASE_URL): return
        try: thumb = show['image']['url']
        except: thumb = LOGO_URL%(urllib.quote(title))
        infoLabels = {"mediatype":"tvshows","label":title ,"title":title,"TVShowTitle":title,"plot":plot}
        infoArt    = {"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON}
        self.addDir(title,vid_url,1,infoLabels,infoArt)
                            
                            
    def buildEpisodes(self, name, url, jsonResponse=None, videos=[], jsonKey='episodes'):
        log('buildEpisodes, ' + name)
        if jsonResponse is None: 
            jsonResponse = json.loads(self.openURL(url))['result']
            videos = jsonResponse[jsonKey]
        for video in videos:
            vid_url = (video.get('canonicalURL','') or video.get('url',None))
            title   = (video.get('title','')          or video.get('shortTitle',None))
            plot    = (video.get('description','')    or video.get('shortDescription','') or title)
            if vid_url is None or title is None: continue
            elif not vid_url.startswith(BASE_URL): continue
            try: show = video['show'].get('title',None)
            except: show = name
            try: thumb = video['images'][0]['url']
            except: thumb = video['image'][0]['url']
            try: season = int(video['season']['seasonNumber'])
            except: season = 0
            try: episode = int(video['season']['episodeAiringOrder'])
            except: episode = 0
            label   = '%s - %s'%(show,title)
            seinfo  = ('S' + ('0' if season < 10 else '') + str(season) + 'E' + ('0' if episode < 10 else '') + str(episode))
            if season + episode > 0: label = '%s - %s - %s'%(show, seinfo, title)
            try: aired = datetime.datetime.fromtimestamp(float(video['airDate']))
            except: aired = datetime.datetime.now()
            try: duration = video['duration']
            except: duration = 0
            infoLabels = {"mediatype":"episode","label":label ,"title":label,"TVShowTitle":show,"plot":plot,"aired":aired.strftime('%Y-%m-%d'),"duration":duration,"season":season,"episode":episode}
            infoArt      = {"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON}
            CONTENT_TYPE = 'episodes'
            self.addLink(label, vid_url, 9, infoLabels, infoArt, len(videos))
        try: next_page = jsonResponse['nextPageURL']
        except: next_page = None
        if next_page:  self.addDir('>> Next',next_page, 2)
            
    
    def playVideo(self, name, url, liz=None):
        log('playVideo')
        info = getVideoInfo(url,QUALITY,True)
        if info is None: return
        info = info.streams()
        if len(info) > 1:
            if PTVL_RUNNING: return xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30007), ICON, 4000)
            info = sorted(info, key=lambda x: x['idx'])
            plst = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
            plst.clear()
            xbmc.sleep(200)
            for videos in info:
                vidIDX = videos['idx']
                url = videos['xbmc_url']
                liz = xbmcgui.ListItem(videos['title'], path=url)
                try: 
                    if 'subtitles' in videos['ytdl_format']: liz.setSubtitles([x['url'] for x in videos['ytdl_format']['subtitles'].get('en','') if 'url' in x])
                except: pass
                plst.add(url, liz, vidIDX)
                if vidIDX == 0: xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz) 
            plst.unshuffle()
        else:
            liz = xbmcgui.ListItem(info[0]['title'], path=info[0]['xbmc_url'])
            xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz) 
        
        
    def addYoutube(self, name, url):
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label":name,"title":name} )
        liz.setArt({'thumb':ICON,'fanart':FANART})
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=url,listitem=liz,isFolder=True)
        
           
    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,totalItems=total)


    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
Exemple #49
0
class MultiChannel(object):
    def __init__(self):
        log('__init__')
        self.cache = SimpleCache()
           
           
    def openURL(self, url):
        log('openURL, url = ' + str(url))
        try:
            cacheresponse = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
            if not cacheresponse:
                request = urllib2.Request(url)
                request.add_header('User-Agent','Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)')
                cacheresponse = urllib2.urlopen(request, timeout = TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, cacheresponse, expiration=datetime.timedelta(hours=1))
            return cacheresponse
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
            return ''
         
         
    def buildMenu(self):
        self.addDir(LANGUAGE(30003), BASE_VID, 1)
        self.addYoutube(LANGUAGE(30004), 'plugin://plugin.video.youtube/channel/UC0VOh1nD6Tlq_5gjkpSecWA/')
            
            
    def browse(self, url):
        log('browse')
        soup   = BeautifulSoup(self.openURL(url), "html.parser")
        videos = soup('div', {'class': 'l-grid--item'})
        for video in videos:
            link = video('div', {'class': 'm-card--media'})[0].find('a').attrs['href']
            if not link.startswith('/video/'): continue
            link  = BASE_URL+link
            label = video('div', {'class': 'm-card--media'})[0].find('a').attrs['title']
            thumb = video('div', {'class': 'm-card--media'})[0].find('source').attrs['data-srcset']
            try: plot = video('div', {'class': 'm-card--content'})[0].find('p').get_text()
            except: plot = label
            infoLabels = {"mediatype":"episode","label":label,"title":label,"plot":plot,"genre":'News'}
            infoArt    = {"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON}
            self.addLink(label, link, 9, infoLabels, infoArt, len(videos))
        next = soup('li', {'class': 'pager-next'})
        if len(next) == 0: return
        next_url   = BASE_URL + next[0].find('a').attrs['href']
        next_label = (next[0].find('a').attrs['title'] or next[0].get_text())
        self.addDir(next_label, next_url, 1)
            
            
    def playVideo(self, name, url, liz=None):
        log('playVideo')
        info = getVideoInfo(url,QUALITY,True)
        if info is None: return
        info = info.streams()
        url  = info[0]['xbmc_url']
        liz  = xbmcgui.ListItem(name, path=url)
        if 'subtitles' in info[0]['ytdl_format']: liz.setSubtitles([x['url'] for x in info[0]['ytdl_format']['subtitles'].get('en','') if 'url' in x])
        xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)
        
        
    def addYoutube(self, name, url):
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label":name,"title":name} )
        liz.setArt({'thumb':ICON,'fanart':FANART})
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=url,listitem=liz,isFolder=True)
        
           
    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,totalItems=total)


    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
class PluginContent:
    """Hidden plugin entry point providing some helper features"""

    params = {}
    win = None

    def __init__(self):
        self.cache = SimpleCache()
        self.kodi_db = KodiDb()
        self.win = xbmcgui.Window(10000)
        try:
            self.params = dict(urlparse.parse_qsl(sys.argv[2].replace("?", "").lower().decode("utf-8")))
            log_msg("plugin called with parameters: %s" % self.params)
            self.main()
        except Exception as exc:
            log_exception(__name__, exc)
            xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

        # cleanup when done processing
        self.close()

    def close(self):
        """Cleanup Kodi Cpython instances"""
        self.cache.close()
        del self.win

    def main(self):
        """main action, load correct function"""
        action = self.params.get("action", "")
        if self.win.getProperty("SkinHelperShutdownRequested"):
            # do not proceed if kodi wants to exit
            log_msg("%s --> Not forfilling request: Kodi is exiting" % __name__, xbmc.LOGWARNING)
            xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
        else:
            try:
                if hasattr(self.__class__, action):
                    # launch module for action provided by this plugin
                    getattr(self, action)()
                else:
                    # legacy (widget) path called !!!
                    self.load_widget()
            except Exception as exc:
                log_exception(__name__, exc)

    def load_widget(self):
        """legacy entrypoint called (widgets are moved to seperate addon), start redirect..."""
        action = self.params.get("action", "")
        newaddon = "script.skin.helper.widgets"
        log_msg(
            "Deprecated method: %s. Please reassign your widgets to get rid of this message. -"
            "This automatic redirect will be removed in the future" % (action),
            xbmc.LOGWARNING,
        )
        paramstring = ""
        for key, value in self.params.iteritems():
            paramstring += ",%s=%s" % (key, value)
        if xbmc.getCondVisibility("System.HasAddon(%s)" % newaddon):
            # TEMP !!! for backwards compatability reasons only - to be removed in the near future!!
            import imp

            addon = xbmcaddon.Addon(newaddon)
            addon_path = addon.getAddonInfo("path").decode("utf-8")
            imp.load_source("plugin", os.path.join(addon_path, "plugin.py"))
            from plugin import main

            main.Main()
            del addon
        else:
            # trigger install of the addon
            if KODI_VERSION >= 17:
                xbmc.executebuiltin("InstallAddon(%s)" % newaddon)
            else:
                xbmc.executebuiltin("RunPlugin(plugin://%s)" % newaddon)

    def playchannel(self):
        """play channel from widget helper"""
        params = {"item": {"channelid": int(self.params["channelid"])}}
        self.kodi_db.set_json("Player.Open", params)

    def playrecording(self):
        """retrieve the recording and play to get resume working"""
        recording = self.kodi_db.recording(self.params["recordingid"])
        params = {"item": {"recordingid": recording["recordingid"]}}
        self.kodi_db.set_json("Player.Open", params)
        # manually seek because passing resume to the player json cmd doesn't seem to work
        if recording["resume"].get("position"):
            for i in range(50):
                if xbmc.getCondVisibility("Player.HasVideo"):
                    break
                xbmc.sleep(50)
            xbmc.Player().seekTime(recording["resume"].get("position"))

    def launch(self):
        """launch any builtin action using a plugin listitem"""
        if "runscript" in self.params["path"]:
            self.params["path"] = self.params["path"].replace("?", ",")
        xbmc.executebuiltin(self.params["path"])

    def playalbum(self):
        """helper to play an entire album"""
        xbmc.executeJSONRPC(
            '{ "jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "albumid": %d } }, "id": 1 }'
            % int(self.params["albumid"])
        )

    def smartshortcuts(self):
        """called from skinshortcuts to retrieve listing of all smart shortcuts"""
        import skinshortcuts

        skinshortcuts.get_smartshortcuts(self.params.get("path", ""))

    @staticmethod
    def backgrounds():
        """called from skinshortcuts to retrieve listing of all backgrounds"""
        import skinshortcuts

        skinshortcuts.get_backgrounds()

    def widgets(self):
        """called from skinshortcuts to retrieve listing of all widgetss"""
        import skinshortcuts

        skinshortcuts.get_widgets(self.params.get("path", ""), self.params.get("sublevel", ""))

    def resourceimages(self):
        """retrieve listing of specific resource addon images"""
        from resourceaddons import get_resourceimages

        addontype = self.params.get("addontype", "")
        for item in get_resourceimages(addontype, True):
            listitem = xbmcgui.ListItem(item[0], label2=item[2], path=item[1], iconImage=item[3])
            xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=item[1], listitem=listitem, isFolder=False)
        xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

    def extrafanart(self):
        """helper to display extrafanart in multiimage control in the skin"""
        fanarts = eval(self.params["fanarts"])
        # process extrafanarts
        for item in fanarts:
            listitem = xbmcgui.ListItem(item, path=item)
            listitem.setProperty("mimetype", "image/jpeg")
            xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=item, listitem=listitem)
        xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

    def genrebackground(self):
        """helper to display images for a specific genre in multiimage control in the skin"""
        genre = self.params.get("genre").split(".")[0]
        arttype = self.params.get("arttype", "fanart")
        randomize = self.params.get("random", "false") == "true"
        mediatype = self.params.get("mediatype", "movies")
        if genre and genre != "..":
            filters = [{"operator": "is", "field": "genre", "value": genre}]
            if randomize:
                sort = {"method": "random", "order": "descending"}
            else:
                sort = None
            items = getattr(self.kodi_db, mediatype)(sort=sort, filters=filters, limits=(0, 50))
            for item in items:
                image = get_clean_image(item["art"].get(arttype, ""))
                if image:
                    image = get_clean_image(item["art"][arttype])
                    listitem = xbmcgui.ListItem(image, path=image)
                    listitem.setProperty("mimetype", "image/jpeg")
                    xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=image, listitem=listitem)
        xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

    def getcastmedia(self):
        """helper to display get all media for a specific actor"""
        name = self.params.get("name")
        if name:
            all_items = self.kodi_db.castmedia(name)
            all_items = process_method_on_list(self.kodi_db.prepare_listitem, all_items)
            all_items = process_method_on_list(self.kodi_db.create_listitem, all_items)
            xbmcplugin.addDirectoryItems(int(sys.argv[1]), all_items, len(all_items))
        xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

    def getcast(self):
        """helper to get all cast for a given media item"""
        db_id = None
        all_cast = []
        all_cast_names = list()
        cache_str = ""
        download_thumbs = self.params.get("downloadthumbs", "") == "true"
        extended_cast_action = self.params.get("castaction", "") == "extendedinfo"
        tmdb = Tmdb()
        movie = self.params.get("movie")
        tvshow = self.params.get("tvshow")
        episode = self.params.get("episode")
        movieset = self.params.get("movieset")

        try:  # try to parse db_id
            if movieset:
                cache_str = "movieset.castcache-%s-%s" % (self.params["movieset"], download_thumbs)
                db_id = int(movieset)
            elif tvshow:
                cache_str = "tvshow.castcache-%s-%s" % (self.params["tvshow"], download_thumbs)
                db_id = int(tvshow)
            elif movie:
                cache_str = "movie.castcache-%s-%s" % (self.params["movie"], download_thumbs)
                db_id = int(movie)
            elif episode:
                cache_str = "episode.castcache-%s-%s" % (self.params["episode"], download_thumbs)
                db_id = int(episode)
        except Exception:
            pass

        cachedata = self.cache.get(cache_str)
        if cachedata:
            # get data from cache
            all_cast = cachedata
        else:
            # retrieve data from json api...
            if movie and db_id:
                all_cast = self.kodi_db.movie(db_id)["cast"]
            elif movie and not db_id:
                filters = [{"operator": "is", "field": "title", "value": movie}]
                result = self.kodi_db.movies(filters=filters)
                all_cast = result[0]["cast"] if result else []
            elif tvshow and db_id:
                all_cast = self.kodi_db.tvshow(db_id)["cast"]
            elif tvshow and not db_id:
                filters = [{"operator": "is", "field": "title", "value": tvshow}]
                result = self.kodi_db.tvshows(filters=filters)
                all_cast = result[0]["cast"] if result else []
            elif episode and db_id:
                all_cast = self.kodi_db.episode(db_id)["cast"]
            elif episode and not db_id:
                filters = [{"operator": "is", "field": "title", "value": episode}]
                result = self.kodi_db.episodes(filters=filters)
                all_cast = result[0]["cast"] if result else []
            elif movieset:
                if not db_id:
                    for item in self.kodi_db.moviesets():
                        if item["title"].lower() == movieset.lower():
                            db_id = item["setid"]
                if db_id:
                    json_result = self.kodi_db.movieset(db_id, include_set_movies_fields=["cast"])
                    if "movies" in json_result:
                        for movie in json_result["movies"]:
                            all_cast += movie["cast"]

            # optional: download missing actor thumbs
            if all_cast and download_thumbs:
                for cast in all_cast:
                    if cast.get("thumbnail"):
                        cast["thumbnail"] = get_clean_image(cast.get("thumbnail"))
                    if not cast.get("thumbnail"):
                        artwork = tmdb.get_actor(cast["name"])
                        cast["thumbnail"] = artwork.get("thumb", "")
            # lookup tmdb if item is requested that is not in local db
            if not all_cast:
                tmdbdetails = {}
                if movie and not db_id:
                    tmdbdetails = tmdb.search_movie(movie)
                elif tvshow and not db_id:
                    tmdbdetails = tmdb.search_tvshow(tvshow)
                if tmdbdetails.get("cast"):
                    all_cast = tmdbdetails["cast"]
            # save to cache
            self.cache.set(cache_str, all_cast)

        # process listing with the results...
        for cast in all_cast:
            if cast.get("name") not in all_cast_names:
                liz = xbmcgui.ListItem(label=cast.get("name"), label2=cast.get("role"), iconImage=cast.get("thumbnail"))
                if extended_cast_action:
                    url = "RunScript(script.extendedinfo,info=extendedactorinfo,name=%s)" % cast.get("name")
                    url = "plugin://script.skin.helper.service/?action=launch&path=%s" % url
                    is_folder = False
                else:
                    url = "RunScript(script.skin.helper.service,action=getcastmedia,name=%s)" % cast.get("name")
                    url = "plugin://script.skin.helper.service/?action=launch&path=%s" % urlencode(url)
                    is_folder = False
                all_cast_names.append(cast.get("name"))
                liz.setThumbnailImage(cast.get("thumbnail"))
                xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=url, listitem=liz, isFolder=is_folder)
        xbmcplugin.endOfDirectory(int(sys.argv[1]))

    @staticmethod
    def alphabet():
        """display an alphabet scrollbar in listings"""
        all_letters = []
        if xbmc.getInfoLabel("Container.NumItems"):
            for i in range(int(xbmc.getInfoLabel("Container.NumItems"))):
                all_letters.append(xbmc.getInfoLabel("Listitem(%s).SortLetter" % i).upper())
            start_number = ""
            for number in ["2", "3", "4", "5", "6", "7", "8", "9"]:
                if number in all_letters:
                    start_number = number
                    break
            for letter in [
                start_number,
                "A",
                "B",
                "C",
                "D",
                "E",
                "F",
                "G",
                "H",
                "I",
                "J",
                "K",
                "L",
                "M",
                "N",
                "O",
                "P",
                "Q",
                "R",
                "S",
                "T",
                "U",
                "V",
                "W",
                "X",
                "Y",
                "Z",
            ]:
                if letter == start_number:
                    label = "#"
                else:
                    label = letter
                listitem = xbmcgui.ListItem(label=label)
                if letter not in all_letters:
                    lipath = "noop"
                    listitem.setProperty("NotAvailable", "true")
                else:
                    lipath = "plugin://script.skin.helper.service/?action=alphabetletter&letter=%s" % letter
                xbmcplugin.addDirectoryItem(int(sys.argv[1]), lipath, listitem, isFolder=False)
        xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

    def alphabetletter(self):
        """used with the alphabet scrollbar to jump to a letter"""
        if KODI_VERSION > 16:
            xbmcplugin.setResolvedUrl(handle=int(sys.argv[1]), succeeded=False, listitem=xbmcgui.ListItem())
        letter = self.params.get("letter", "").upper()
        jumpcmd = ""
        if letter in ["A", "B", "C", "2"]:
            jumpcmd = "2"
        elif letter in ["D", "E", "F", "3"]:
            jumpcmd = "3"
        elif letter in ["G", "H", "I", "4"]:
            jumpcmd = "4"
        elif letter in ["J", "K", "L", "5"]:
            jumpcmd = "5"
        elif letter in ["M", "N", "O", "6"]:
            jumpcmd = "6"
        elif letter in ["P", "Q", "R", "S", "7"]:
            jumpcmd = "7"
        elif letter in ["T", "U", "V", "8"]:
            jumpcmd = "8"
        elif letter in ["W", "X", "Y", "Z", "9"]:
            jumpcmd = "9"
        if jumpcmd:
            xbmc.executebuiltin("SetFocus(50)")
            for i in range(40):
                xbmc.executeJSONRPC(
                    '{ "jsonrpc": "2.0", "method": "Input.ExecuteAction",\
                    "params": { "action": "jumpsms%s" }, "id": 1 }'
                    % (jumpcmd)
                )
                xbmc.sleep(50)
                if xbmc.getInfoLabel("ListItem.Sortletter").upper() == letter:
                    break
Exemple #51
0
class Disclose(object):
    def __init__(self):
        log('__init__')
        self.cache = SimpleCache()

    def openURL(self, url):
        log('openURL, url = ' + str(url))
        try:
            cacheresponse = self.cache.get(ADDON_NAME +
                                           '.openURL, url = %s' % url)
            if not cacheresponse:
                request = urllib2.Request(url)
                request.add_header(
                    'User-Agent',
                    'Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)'
                )
                cacheresponse = urllib2.urlopen(request,
                                                timeout=TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s' % url,
                               cacheresponse,
                               expiration=datetime.timedelta(hours=1))
            return cacheresponse
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
        xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
        return ''

    def buildMenu(self):
        for item in MAIN_MENU:
            self.addDir(*item)
        self.addYoutube(
            LANGUAGE(30008),
            'plugin://plugin.video.youtube/channel/UCA-Ls4dkRBXHMjRjeTDTdjg/')

    def browse(self, url):
        log('browse')
        soup = BeautifulSoup(self.openURL(url), "html.parser")
        videos = soup('div', {'class': 'teaser teaser--third'})
        for video in videos:
            try:
                thumb = 'http:%s' % (video(
                    'div', {'class': 'ratio-container ratio16_9'
                            })[0].find('img').attrs['data-src'])
            except:
                thumb = FANART
            items = video('div', {'class': 'teaser__caption'})
            vid_url = BASE_URL + (items[0]('a', {
                'class': 'article-link'
            })[0].attrs['href'])
            label = items[0]('a', {'class': 'article-link'})[0].get_text()
            timeago = items[0]('span', {'class': 'meta-timeago'})[0].get_text()
            plot = '%s - %s' % (timeago, label)
            try:
                genre = video('span',
                              {'class': 'teaser-figure__cat'})[0].get_text()
            except:
                genre = 'Unknown'
            runtime = (video(
                'span',
                {'class': 'teaser-figure__len'})[0].get_text()).split(':')
            if len(runtime) == 3:
                h, m, s = runtime
                duration = int(h) * 3600 + int(m) * 60 + int(s)
            else:
                m, s = runtime
                duration = (int(m) * 60) + int(s)
            infoLabels = {
                "mediatype": "episode",
                "label": label,
                "title": label,
                "duration": duration,
                "plot": plot
            }
            infoArt = {
                "thumb": thumb,
                "poster": thumb,
                "fanart": FANART,
                "icon": ICON,
                "logo": ICON
            }
            self.addLink(label, vid_url, 9, infoLabels, infoArt, len(videos))
        next = soup('li', {'class': 'more-container__button m-auto'})
        if len(next) == 0: return
        next_url = BASE_URL + next[0].find('a').attrs['href']
        next_label = (next[0].find('a').attrs['title'] or next[0].get_text())
        self.addDir(next_label, next_url, 1)

    def resolveURL(self, name, url):
        try:
            data = json.loads(
                re.findall('"drupal-settings-json">(.+?)</script>',
                           self.openURL(url),
                           flags=re.DOTALL)[0])['dtv_video']
            provider = data['provider']
            log('resolveURL, provider = ' + provider)
            url = re.findall('src="(.+?)"', (data['player_code']),
                             flags=re.DOTALL)[0].split('?')[0]
            if provider == 'youtube':
                if len(re.findall('http[s]?://www.youtube', url)) > 0:
                    url = YTURL % (url.rsplit('/', 1)[1])
                elif len(re.findall('http[s]?://youtu.be/', url)) > 0:
                    url = YTURL % (url.split('/youtu.be/')[1])
            elif provider == 'vimeo':
                if len(re.findall('http[s]?://vimeo.com/', url)) > 0:
                    url = VMURL % (url.split('/vimeo.com/')[1])
            else:
                raise Exception('resolveURL, unknown provider; data =' +
                                json.dumps(data))
            log('resolveURL, url = ' + url)
            return xbmcgui.ListItem(name, path=url)
        except Exception as e:
            log("resolveURL Failed! " + str(e), xbmc.LOGERROR)
        if isUWP(): return ''
        from YDStreamExtractor import getVideoInfo
        info = getVideoInfo(url, QUALITY, True)
        if info is None: return
        info = info.streams()
        url = info[0]['xbmc_url']
        liz = xbmcgui.ListItem(name, path=url)
        try:
            if 'subtitles' in info[0]['ytdl_format']:
                liz.setSubtitles([
                    x['url']
                    for x in info[0]['ytdl_format']['subtitles'].get('en', '')
                    if 'url' in x
                ])
        except:
            pass
        return liz

    def playVideo(self, name, url):
        log('playVideo')
        xbmcplugin.setResolvedUrl(int(sys.argv[1]), True,
                                  self.resolveURL(name, url))

    def addYoutube(self, name, url):
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label": name, "title": name})
        liz.setArt({'thumb': ICON, 'fanart': FANART})
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                    url=url,
                                    listitem=liz,
                                    isFolder=True)

    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb': ICON, 'fanart': FANART})
        else: liz.setArt(infoArt)
        u = sys.argv[0] + "?url=" + urllib.quote_plus(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                    url=u,
                                    listitem=liz,
                                    totalItems=total)

    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb': ICON, 'fanart': FANART})
        else: liz.setArt(infoArt)
        u = sys.argv[0] + "?url=" + urllib.quote_plus(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),
                                    url=u,
                                    listitem=liz,
                                    isFolder=True)
Exemple #52
0
class NewsOn(object):
    def __init__(self):
        log('__init__')
        self.cache     = SimpleCache()
        self.stateMenu = self.getStates()

        
    def openURL(self, url):
        try:
            cacheResponse = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
            if not cacheResponse:
                request = urllib2.Request(url)
                request.add_header('Accept-encoding', 'gzip')
                request.add_header('User-Agent','Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)')
                response = urllib2.urlopen(request, timeout = TIMEOUT)
                log(response.headers['content-type'])
                log(response.headers['content-encoding'])
                if response.info().get('content-encoding') == 'gzip':
                    buf = StringIO(response.read())
                    f = gzip.GzipFile(fileobj=buf)
                    cacheResponse = f.read()
                else: cacheResponse = response
                response.close()
                self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, cacheResponse, expiration=datetime.timedelta(hours=1))
            if isinstance(cacheResponse, basestring): cacheResponse = json.loads(cacheResponse)
            return cacheResponse
        except Exception as e: 
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
            return ''
        
        
    def mainMenu(self):
        log('mainMenu')
        for item in MENU: self.addDir(*item)
        
                    
    def browseMenu(self, id=1):
        log('browseMenu, id = ' + str(id))
        self.stateMenu = [tuple(s.format(id) for s in tup) for tup in self.stateMenu]
        for item in self.stateMenu: self.addDir(*item)
            
            
    def getStates(self):
        log('getStates')
        state     = []
        stateLST  = []
        data = self.openURL(BASE_API)
        if len(data) == 0: return []
        for channel in data: 
            try: state.append(channel['config']['state'])
            except: pass
        states = collections.Counter(state)
        for key, value in sorted(states.iteritems()): stateLST.append(("%s"%(key), key , '{}'))
        return stateLST
            
            
    def newsCasts(self, state):
        log('newsCasts, state = ' + state)
        urls = []
        data = self.openURL(BASE_API)
        if len(data) == 0: return
        for channel in data:
            try: states = channel['config']['state']
            except: continue
            if state in states:
                chid   = channel['identifier']
                title  = channel['title']
                icon   = (channel['icon'] or ICON)
                for idx, stream in enumerate(channel['streams']):
                    streamType = stream['StreamType']
                    if streamType == 'website': continue#random.choice(['website','roku']): 
                    #multiple urls, only add unique.
                    url = stream['Url']
                    offset = stream['OffsetFromNow']
                    delay  = url+'&delay=%d'
                    #todo do something with delay option?
                    if url not in urls:
                        urls.append(url)
                        chid = chid+'.%d'%idx if idx > 0 else chid
                        label      = "%s - %s" % (chid, title)
                        infoLabels ={"mediatype":"episodes","label":label ,"title":label}
                        infoArt    ={"thumb":icon,"poster":icon,"fanart":FANART,"icon":icon,"logo":icon} 
                        self.addLink(title, url, 9, infoLabels, infoArt)
        
        
    def videoclips(self, state):
        log('videoclips, state = ' + state)
        data = self.openURL(BASE_API)
        if len(data) == 0: return
        for channel in data:
            try: states = channel['config']['state']
            except: continue
            if state in states:
                chid   = channel['identifier']
                title  = channel['title']
                icon   = (channel['icon'] or ICON)
                vidURL = channel['config']['localvodfeed']
                if vidURL:
                    label      = "%s - %s" % (chid, title)
                    infoLabels ={"mediatype":"video","label":label,"title":label}
                    infoArt    ={"thumb":icon,"poster":icon,"fanart":FANART,"icon":ICON,"logo":ICON} 
                    self.addDir(label, vidURL, 4, infoLabels, infoArt)


    def parseclips(self, url):
        log('parseclips, url = ' + url)
        feed = feedparser.parse(url)
        for item in feed['entries']:
            if item and 'summary_detail' in item:
                for vids in item['media_content']:
                    title = item['title']
                    url   = vids['url']
                    plot  = item['summary']
                    aired = item.get('published','').replace(' EST','').replace(' UTC','').replace(' GMT','')
                    try: aired = (datetime.datetime.strptime(aired, '%a, %d %b %Y %H:%M:%S'))
                    except: aired = datetime.datetime.now()
                    aired = aired.strftime("%Y-%m-%d")
                    thumb = item['media_thumbnail'][0]['url']
                    tagLST = []
                    if 'tags' in item:
                        for tag in item['tags']: tagLST.append(((tag['term']).split('/')[0]).title())
                    if len(tagLST) > 0: genre = (tagLST[0] or '')
                    infoLabels ={"mediatype":"episode","label":title,"title":title,"plot":plot,"aired":aired,'genre':genre,'tags':tagLST}
                    infoArt    ={"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON} 
                    self.addLink(title, url, 8, infoLabels, infoArt)

                    
    def playVideo(self, name, url, live=False):
        log('playVideo')
        liz = xbmcgui.ListItem(name, path=url)
        if live: 
            liz.setProperty('inputstreamaddon','inputstream.adaptive')
            liz.setProperty('inputstream.adaptive.manifest_type','hls') 
        xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)

           
    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False: liz.setInfo( type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,totalItems=total)


    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
 def __init__(self):
     self.cache = SimpleCache()
Exemple #54
0
class CNN(object):
    def __init__(self):
        log('__init__')
        self.cache = SimpleCache()
           
           
    def openURL(self, url):
        log('openURL, url = ' + str(url))
        try:
            cacheresponse = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
            if not cacheresponse:
                request = urllib2.Request(url)
                response = urllib2.urlopen(request, timeout = TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, response, expiration=datetime.timedelta(hours=1))
            return self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
            return ''
         
         
    def buildMenu(self):
        for item in MENU_ITEMS: self.addDir(item, JSON_URL%item.lower(), 1)
        self.addDir('Digital Shorts', SHORTS_URL, 2)
        self.addYoutube("Browse Youtube" , 'plugin://plugin.video.youtube/user/CNN/')
            
            
    def browse(self, name, url):
        log('browse, ' + name)
        response = json.loads(self.openURL(url))
        items = response['videos']
        for item in items:          
            try:
                runtime = item['duration'].split(':')
                if len(runtime) == 3:
                    h, m, s = runtime
                    duration = int(h) * 3600 + int(m) * 60 + int(s)
                else:
                    m, s = runtime   
                    duration = int(m) * 60 + int(s)
            except: duration = item['duration']
            label        = item['headline']
            thumb        = 'http:%s'%item['fullsize_url']
            infoLabels   = {"mediatype":"episode","label":label ,"title":label,"duration":duration,"plot":item['description'],"genre":"News"}
            infoArt      = {"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON}
            self.addLink(label, BASE_URL + item['clickback_url'], 9, infoLabels, infoArt, len(items))


    def browseShorts(self, name, url):
        log('browseShorts, ' + name)
        soup   = BeautifulSoup(self.openURL(url), "html.parser")
        videos = soup('article', {'class': 'cd'})
        for video in videos:
            vid_url = video('h3', {'class': 'cd__headline'})[0].find('a')['href']
            if not vid_url.startswith('http'): vid_url = BASE_URL + vid_url
            if vid_url.startswith('http://cnn.it'): continue
            if not '/video' in vid_url: continue
            thumb = (video('div', {'class': 'cd__wrapper'})[0])
            try: thumb = 'http:' + (json.loads((re.search('"large":(.*?)"},', str(thumb)).group(1) + '"}'))['uri'])
            except: thumb = ICON
            results = video('div', {'class': 'cd__content'})[0]
            try: title = results('div', {'class': 'cd__kicker'})[0].get_text()
            except: title = None
            subtitle = results('span', {'class': 'cd__headline-text'})[0].get_text()
            label = '%s - %s'%(title, subtitle) if title is not None else subtitle
            try: plot = results('div', {'class': 'cd__description'})[0].get_text()
            except: plot = subtitle
            duration   = 0
            infoLabels = {"mediatype":"episode","label":label ,"title":label,"duration":duration,"plot":plot}
            infoArt    = {"thumb":thumb,"poster":thumb,"fanart":FANART,"icon":ICON,"logo":ICON}
            self.addLink(label, vid_url, 9, infoLabels, infoArt, len(videos))

                
    def playVideo(self, name, url, liz=None):
        log('playVideo')
        info = getVideoInfo(url,QUALITY,True)
        if info is None: return
        info = info.streams()
        url  = info[0]['xbmc_url']
        liz  = xbmcgui.ListItem(name, path=url)
        if 'subtitles' in info[0]['ytdl_format']: liz.setSubtitles([x['url'] for x in info[0]['ytdl_format']['subtitles'].get('en','') if 'url' in x])
        xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)
        
        
    def addYoutube(self, name, url):
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label":name,"title":name} )
        liz.setArt({'thumb':ICON,'fanart':FANART})
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=url,listitem=liz,isFolder=True)
        
           
    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,totalItems=total)


    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
Exemple #55
0
class TUFFTV(object):
    def __init__(self):
        log('__init__')
        self.cache = SimpleCache()
           
           
    def openURL(self, url):
        log('openURL, url = ' + str(url))
        try:
            cacheresponse = self.cache.get(ADDON_NAME + '.openURL, url = %s'%url)
            if not cacheresponse:
                request  = urllib2.Request(url)
                cacheresponse = urllib2.urlopen(request, timeout = TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s'%url, cacheresponse, expiration=datetime.timedelta(minutes=5))
            return cacheresponse
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
            xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
            return ''

         
    def buildMenu(self):
        self.addLink(LANGUAGE(30003)%self.buildGuide(live=True),'',0)
        self.addDir( LANGUAGE(30004)%REGION,'',1)
        self.addYoutube(LANGUAGE(30005), 'plugin://plugin.video.youtube/channel/UCXEIxLGYxu5pB61GHnaQ_hA/')
            
            
    def buildLive(self):
        log('buildLive')
        return 'http:'+re.findall('"file": "(.+?)"',self.openURL(FEED_URL),re.DOTALL)[0]
        
                
    def buildGuide(self, live=False):
        log('buildGuide, live = ' + str(live))
        idx   = 0
        AMPM  = 'AM'
        url   = self.buildLive()
        now   = datetime.datetime.now()
        tnow  = datetime.datetime.strptime((datetime.datetime.time(now)).strftime('%I:%M %p'), '%I:%M %p')
        dayofweek = {'Monday':1,'Tuesday':2,'Wednesday':3,'Thursday':4,'Friday':5,'Saturday':6,'Sunday':7}[now.strftime('%A')]
        soup  = BeautifulSoup(self.openURL(REGION_URL), "html.parser")
        items = soup('table' , {'class': 'schedule-table'})[0].find_all('tr')
        
        for item in items:
            item = item.find_all('td')
            try: 
                stime = int((item[0].get_text()).split(':')[0])
                if idx > 6 and stime == 12: AMPM = 'PM'
                starttime = '%s %s'%(item[0].get_text(),AMPM)
                title = item[dayofweek].get_text().replace('[block]2','').replace('[block]4','')
                if title == '[/block]': continue
                label = '%s %s'%(starttime,title)
                startDate  = (datetime.datetime.strptime(starttime, '%I:%M %p'))
                endDate1   = (startDate + datetime.timedelta(minutes=30))
                endDate2   = (startDate + datetime.timedelta(minutes=60))
                idx += 1
                if live and (tnow >= startDate and (tnow <= endDate1 or tnow <= endDate2)): return label
                elif live: continue
                airdate    = now.strftime('%Y-%m-%d')
                plot       = title
                infoLabels = {"mediatype":"episode","label":label,"title":label,"plot":plot,"aired":airdate,"studio":"Tuff.TV"}
                infoArt    = {"thumb":ICON,"poster":ICON,"fanart":FANART,"icon":ICON,"logo":ICON}
                self.addLink(label,url,9,infoLabels,infoArt)
            except: pass
        
                
    def playLive(self, name):
        log('playLive')
        self.playVideo(name, self.buildLive())        
        
        
    def playVideo(self, name, url):
        log('playVideo')
        liz = xbmcgui.ListItem(name, path=url)
        if 'm3u8' in url:
            liz.setProperty('inputstreamaddon','inputstream.adaptive')
            liz.setProperty('inputstream.adaptive.manifest_type','hls') 
        xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz) 
        
           
    def addYoutube(self, name, url):
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label":name,"title":name} )
        liz.setArt({'thumb':ICON,'fanart':FANART})
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=url,listitem=liz,isFolder=True)
        
           
    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,totalItems=total)


    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz=xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False: liz.setInfo(type="Video", infoLabels={"mediatype":"video","label":name,"title":name})
        else: liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb':ICON,'fanart':FANART})
        else: liz.setArt(infoArt)
        u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
Exemple #56
0
class Disclose(object):
    def __init__(self, sysARG):
        log('__init__, sysARG = ' + str(sysARG))
        self.sysARG = sysARG
        self.cache = SimpleCache()

    def openURL(self, url):
        log('openURL, url = ' + str(url))
        try:
            cacheresponse = self.cache.get(ADDON_NAME +
                                           '.openURL, url = %s' % url)
            if not cacheresponse:
                request = urllib2.Request(url)
                request.add_header(
                    'User-Agent',
                    'Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)'
                )
                cacheresponse = urllib2.urlopen(request,
                                                timeout=TIMEOUT).read()
                self.cache.set(ADDON_NAME + '.openURL, url = %s' % url,
                               cacheresponse,
                               expiration=datetime.timedelta(hours=12))
            return cacheresponse
        except Exception as e:
            log("openURL Failed! " + str(e), xbmc.LOGERROR)
        xbmcgui.Dialog().notification(ADDON_NAME, LANGUAGE(30001), ICON, 4000)
        return ''

    def buildMenu(self):
        for item in MAIN_MENU:
            self.addDir(*item)
        self.addYoutube(
            LANGUAGE(30008),
            'plugin://plugin.video.youtube/channel/UCA-Ls4dkRBXHMjRjeTDTdjg/')

    def browse(self, url):
        soup = BeautifulSoup(self.openURL(url), "html.parser")
        videos = soup('div', {'class': 'grid-item'})
        for video in videos:
            items = video('div', {'class': 'teaser--masonry'})
            try:
                thumb = 'http:%s' % (video(
                    'div', {'class': 'ratio-container ratio16_9'
                            })[0].find('img').attrs['data-src'])
            except:
                thumb = FANART
            info = items[0]('a', {'class': 'article-link'})
            vid_url = BASE_URL + (info[0].attrs['href'])
            label = items[0]('h3', {'class': 'teaser__title'})[0].get_text()
            timeago = items[0]('span', {'class': 'meta-timeago'})[0].get_text()
            plot = label  #'%s - %s'%(timeago, label)
            try:
                genre = video('span',
                              {'class': 'teaser-figure__cat'})[0].get_text()
            except:
                genre = ''
            try:
                aired = (datetime.datetime.strptime(timeago, '%b %d %Y'))
            except:
                aired = datetime.datetime.now()
            aired = aired.strftime("%Y-%m-%d")
            try:
                runtime = (info[0].get_text()).split(':')
                if len(runtime) == 3:
                    h, m, s = runtime
                    duration = int(h) * 3600 + int(m) * 60 + int(s)
                else:
                    m, s = runtime
                    duration = (int(m) * 60) + int(s)
            except:
                duration = 0
            infoLabels = {
                "mediatype": "episode",
                "label": label,
                "title": label,
                "duration": duration,
                "plot": plot,
                "genre": genre,
                "aired": aired
            }
            infoArt = {
                "thumb": thumb,
                "poster": thumb,
                "fanart": FANART,
                "icon": ICON,
                "logo": ICON
            }
            self.addLink(label, vid_url, 9, infoLabels, infoArt, len(videos))
        next = soup('li', {'class': 'more-container__button m-auto'})
        if len(next) == 0: return
        next_url = BASE_URL.rstrip('/') + next[0].find('a').attrs['href']
        next_label = (next[0].find('a').attrs['title'] or next[0].get_text())
        self.addDir(next_label, next_url, 1)

    def resolveURL(self, name, url):
        log('resolveURL, url = %s' % url)
        soup = BeautifulSoup(self.openURL(url), "html.parser")
        vid_url = url
        for element in soup('iframe'):
            video = element.get('data-src', '')
            if video:
                vid_url = video
                break
        if vid_url == url:
            for element in soup('embed'):
                video = element.get('data-src', '')
                if video:
                    vid_url = video
                    break
        print vid_url

        if 'youtube' in vid_url:
            yt_id = re.search('embed\/([-\w]+)', vid_url).group(1)
            if not yt_id:
                yt_id = re.search('youtube.com\/watch\?v=([-\w]+)',
                                  vid_url).group(1)
            elif not yt_id:
                yt_id = re.search('youtube.be\/watch\?v=([-\w]+)',
                                  vid_url).group(1)
            if yt_id: vid_url = YTURL % (yt_id)

        if vid_url == url and not isUWP():
            from YDStreamExtractor import getVideoInfo
            info = getVideoInfo(url, QUALITY, True)
            if info is None: return
            info = info.streams()
            url = info[0]['xbmc_url']
        else:
            url = vid_url
        liz = xbmcgui.ListItem(name, path=url)
        try:
            if 'subtitles' in info[0]['ytdl_format']:
                liz.setSubtitles([
                    x['url']
                    for x in info[0]['ytdl_format']['subtitles'].get('en', '')
                    if 'url' in x
                ])
        except:
            pass
        return liz

    def playVideo(self, name, url):
        log('playVideo')
        xbmcplugin.setResolvedUrl(int(self.sysARG[1]), True,
                                  self.resolveURL(name, url))

    def addYoutube(self, name, url):
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        liz.setInfo(type="Video", infoLabels={"label": name, "title": name})
        liz.setArt({'thumb': ICON, 'fanart': FANART})
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),
                                    url=url,
                                    listitem=liz,
                                    isFolder=True)

    def addLink(self, name, u, mode, infoList=False, infoArt=False, total=0):
        name = name.encode("utf-8")
        log('addLink, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'true')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb': ICON, 'fanart': FANART})
        else: liz.setArt(infoArt)
        u = self.sysARG[0] + "?url=" + urllib.quote_plus(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),
                                    url=u,
                                    listitem=liz,
                                    totalItems=total)

    def addDir(self, name, u, mode, infoList=False, infoArt=False):
        name = name.encode("utf-8")
        log('addDir, name = ' + name)
        liz = xbmcgui.ListItem(name)
        liz.setProperty('IsPlayable', 'false')
        if infoList == False:
            liz.setInfo(type="Video",
                        infoLabels={
                            "mediatype": "video",
                            "label": name,
                            "title": name
                        })
        else:
            liz.setInfo(type="Video", infoLabels=infoList)
        if infoArt == False: liz.setArt({'thumb': ICON, 'fanart': FANART})
        else: liz.setArt(infoArt)
        u = self.sysARG[0] + "?url=" + urllib.quote_plus(u) + "&mode=" + str(
            mode) + "&name=" + urllib.quote_plus(name)
        xbmcplugin.addDirectoryItem(handle=int(self.sysARG[1]),
                                    url=u,
                                    listitem=liz,
                                    isFolder=True)

    def getParams(self):
        return dict(urlparse.parse_qsl(self.sysARG[2][1:]))

    def run(self):
        params = self.getParams()
        try:
            url = urllib.unquote_plus(params["url"])
        except:
            url = None
        try:
            name = urllib.unquote_plus(params["name"])
        except:
            name = None
        try:
            mode = int(params["mode"])
        except:
            mode = None
        log("Mode: " + str(mode))
        log("URL : " + str(url))
        log("Name: " + str(name))

        if mode == None: self.buildMenu()
        elif mode == 1: self.browse(url)
        elif mode == 9: self.playVideo(name, url)

        xbmcplugin.setContent(int(self.sysARG[1]), CONTENT_TYPE)
        xbmcplugin.addSortMethod(int(self.sysARG[1]),
                                 xbmcplugin.SORT_METHOD_UNSORTED)
        xbmcplugin.endOfDirectory(int(self.sysARG[1]), cacheToDisc=True)
Exemple #57
0
class MetadataUtils(object):
    '''
        Provides all kind of mediainfo for kodi media, returned as dict with details
    '''
    close_called = False

    def __init__(self):
        '''Initialize and load all our helpers'''
        self._studiologos_path = ""
        self.cache = SimpleCache()
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.kodidb = KodiDb()
        self.omdb = Omdb(self.cache)
        self.tmdb = Tmdb(self.cache)
        self.channellogos = ChannelLogos(self.kodidb)
        self.fanarttv = FanartTv(self.cache)
        self.imdb = Imdb(self.cache)
        self.google = GoogleImages(self.cache)
        self.studiologos = StudioLogos(self.cache)
        self.animatedart = AnimatedArt(self.cache, self.kodidb)
        self.thetvdb = TheTvDb()
        self.musicart = MusicArtwork(self)
        self.pvrart = PvrArtwork(self)
        log_msg("Initialized")

    def close(self):
        '''Cleanup instances'''
        self.close_called = True
        self.cache.close()
        self.addon = None
        del self.addon
        del self.kodidb
        del self.omdb
        del self.tmdb
        del self.channellogos
        del self.fanarttv
        del self.imdb
        del self.google
        del self.studiologos
        del self.animatedart
        del self.thetvdb
        del self.musicart
        del self.pvrart
        log_msg("Exited")

    def __del__(self):
        '''make sure close is called'''
        if not self.close_called:
            self.close()

    @use_cache(14)
    def get_extrafanart(self, file_path):
        '''helper to retrieve the extrafanart path for a kodi media item'''
        from helpers.extrafanart import get_extrafanart
        return get_extrafanart(file_path)

    def get_music_artwork(self, artist, album="", track="", disc="", ignore_cache=False, flush_cache=False):
        '''method to get music artwork for the goven artist/album/song'''
        return self.musicart.get_music_artwork(
            artist, album, track, disc, ignore_cache=ignore_cache, flush_cache=flush_cache)

    def music_artwork_options(self, artist, album="", track="", disc=""):
        '''options for music metadata for specific item'''
        return self.musicart.music_artwork_options(artist, album, track, disc)

    @use_cache(7)
    def get_extended_artwork(self, imdb_id="", tvdb_id="", tmdb_id="", media_type=""):
        '''get extended artwork for the given imdbid or tvdbid'''
        result = None
        if "movie" in media_type and tmdb_id:
            result = self.fanarttv.movie(tmdb_id)
        elif "movie" in media_type and imdb_id:
            result = self.fanarttv.movie(imdb_id)
        elif media_type in ["tvshow", "tvshows", "seasons", "episodes"]:
            if not tvdb_id:
                if imdb_id and not imdb_id.startswith("tt"):
                    tvdb_id = imdb_id
                elif imdb_id:
                    tvdb_id = self.thetvdb.get_series_by_imdb_id(imdb_id).get("tvdb_id")
            if tvdb_id:
                result = self.fanarttv.tvshow(tvdb_id)
        # add additional art with special path
        if result:
            result = {"art": result}
            for arttype in ["fanarts", "posters", "clearlogos", "banners"]:
                if result["art"].get(arttype):
                    result["art"][arttype] = "plugin://script.skin.helper.service/"\
                        "?action=extrafanart&fanarts=%s" % quote_plus(repr(result["art"][arttype]))
        return result

    def get_tmdb_details(self, imdb_id="", tvdb_id="", title="", year="", media_type="",
                         preftype="", manual_select=False, ignore_cache=False):
        '''returns details from tmdb'''
        result = {}
        if imdb_id:
            result = self.tmdb.get_videodetails_by_externalid(
                imdb_id, "imdb_id")
        elif tvdb_id:
            result = self.tmdb.get_videodetails_by_externalid(
                tvdb_id, "tvdb_id")
        elif title and media_type in ["movies", "setmovies", "movie"]:
            result = self.tmdb.search_movie(
                title, year, manual_select=manual_select)
        elif title and media_type in ["tvshows", "tvshow"]:
            result = self.tmdb.search_tvshow(
                title, year, manual_select=manual_select)
        elif title:
            result = self.tmdb.search_video(
                title, year, preftype=preftype, manual_select=manual_select)
        if result and result.get("status"):
            result["status"] = self.translate_string(result["status"])
        if result and result.get("runtime"):
            result["runtime"] = result["runtime"] / 60
            result.update(self.get_duration(result["runtime"]))
        return result

    def get_moviesetdetails(self, title, set_id):
        '''get a nicely formatted dict of the movieset details which we can for example set as window props'''
        # get details from tmdb
        from helpers.moviesetdetails import get_moviesetdetails
        return get_moviesetdetails(self, title, set_id)

    @use_cache(14)
    def get_streamdetails(self, db_id, media_type, ignore_cache=False):
        '''get a nicely formatted dict of the streamdetails '''
        from helpers.streamdetails import get_streamdetails
        return get_streamdetails(self.kodidb, db_id, media_type)

    def get_pvr_artwork(self, title, channel="", genre="", manual_select=False, ignore_cache=False):
        '''get artwork and mediadetails for PVR entries'''
        return self.pvrart.get_pvr_artwork(
            title, channel, genre, manual_select=manual_select, ignore_cache=ignore_cache)

    def pvr_artwork_options(self, title, channel="", genre=""):
        '''options for pvr metadata for specific item'''
        return self.pvrart.pvr_artwork_options(title, channel, genre)

    def get_channellogo(self, channelname):
        '''get channellogo for the given channel name'''
        return self.channellogos.get_channellogo(channelname)

    def get_studio_logo(self, studio):
        '''get studio logo for the given studio'''
        # dont use cache at this level because of changing logospath
        return self.studiologos.get_studio_logo(studio, self.studiologos_path)

    @property
    def studiologos_path(self):
        '''path to use to lookup studio logos, must be set by the calling addon'''
        return self._studiologos_path

    @studiologos_path.setter
    def studiologos_path(self, value):
        '''path to use to lookup studio logos, must be set by the calling addon'''
        self._studiologos_path = value

    def get_animated_artwork(self, imdb_id, manual_select=False, ignore_cache=False):
        '''get animated artwork, perform extra check if local version still exists'''
        artwork = self.animatedart.get_animated_artwork(
            imdb_id, manual_select=manual_select, ignore_cache=ignore_cache)
        if not (manual_select or ignore_cache):
            refresh_needed = False
            if artwork.get("animatedposter") and not xbmcvfs.exists(
                    artwork["animatedposter"]):
                refresh_needed = True
            if artwork.get("animatedfanart") and not xbmcvfs.exists(
                    artwork["animatedfanart"]):
                refresh_needed = True

        return {"art": artwork}

    def get_omdb_info(self, imdb_id="", title="", year="", content_type=""):
        '''Get (kodi compatible formatted) metadata from OMDB, including Rotten tomatoes details'''
        title = title.split(" (")[0]  # strip year appended to title
        result = {}
        if imdb_id:
            result = self.omdb.get_details_by_imdbid(imdb_id)
        elif title and content_type in ["seasons", "season", "episodes", "episode", "tvshows", "tvshow"]:
            result = self.omdb.get_details_by_title(title, "", "tvshows")
        elif title and year:
            result = self.omdb.get_details_by_title(title, year, content_type)
        if result and result.get("status"):
            result["status"] = self.translate_string(result["status"])
        if result and result.get("runtime"):
            result["runtime"] = result["runtime"] / 60
            result.update(self.get_duration(result["runtime"]))
        return result

    def get_top250_rating(self, imdb_id):
        '''get the position in the IMDB top250 for the given IMDB ID'''
        return self.imdb.get_top250_rating(imdb_id)

    @use_cache(14)
    def get_duration(self, duration):
        '''helper to get a formatted duration'''
        if isinstance(duration, (str, unicode)) and ":" in duration:
            dur_lst = duration.split(":")
            return {
                "Duration": "%s:%s" % (dur_lst[0], dur_lst[1]),
                "Duration.Hours": dur_lst[0],
                "Duration.Minutes": dur_lst[1],
                "Runtime": str((int(dur_lst[0]) * 60) + int(dur_lst[1])),
            }
        else:
            return _get_duration(duration)

    @use_cache(2)
    def get_tvdb_details(self, imdbid="", tvdbid=""):
        '''get metadata from tvdb by providing a tvdbid or tmdbid'''
        result = {}
        self.thetvdb.days_ahead = 365
        if not tvdbid and imdbid and not imdbid.startswith("tt"):
            # assume imdbid is actually a tvdbid...
            tvdbid = imdbid
        if tvdbid:
            result = self.thetvdb.get_series(tvdbid)
        elif imdbid:
            result = self.thetvdb.get_series_by_imdb_id(imdbid)
        if result:
            if result["status"] == "Continuing":
                # include next episode info
                result["nextepisode"] = self.thetvdb.get_nextaired_episode(result["tvdb_id"])
            # include last episode info
            result["lastepisode"] = self.thetvdb.get_last_episode_for_series(result["tvdb_id"])
            result["status"] = self.translate_string(result["status"])
            if result.get("runtime"):
                result["runtime"] = result["runtime"] / 60
                result.update(_get_duration(result["runtime"]))
        return result

    @use_cache(90)
    def get_imdbtvdb_id(self, title, content_type, year="", imdbid="", tvshowtitle=""):
        '''try to figure out the imdbnumber and/or tvdbid'''
        tvdbid = ""
        if content_type in ["seasons", "episodes"] or tvshowtitle:
            title = tvshowtitle
            content_type = "tvshows"
        if imdbid and not imdbid.startswith("tt"):
            if content_type in ["tvshows", "seasons", "episodes"]:
                tvdbid = imdbid
                imdbid = ""
        if not imdbid and year:
            imdbid = self.get_omdb_info(
                "", title, year, content_type).get("imdbnumber", "")
        if not imdbid:
            # repeat without year
            imdbid = self.get_omdb_info("", title, "", content_type).get("imdbnumber", "")
        # return results
        return (imdbid, tvdbid)

    def translate_string(self, _str):
        '''translate the received english string from the various sources like tvdb, tmbd etc'''
        translation = _str
        _str = _str.lower()
        if "continuing" in _str:
            translation = self.addon.getLocalizedString(32037)
        elif "ended" in _str:
            translation = self.addon.getLocalizedString(32038)
        elif "released" in _str:
            translation = self.addon.getLocalizedString(32040)
        return translation
 def __init__(self):
     log('__init__')
     self.cache = SimpleCache()
Exemple #59
0
 def __init__(self, sysARG):
     log('__init__, sysARG = ' + str(sysARG))
     self.sysARG = sysARG
     self.cache = SimpleCache()