Beispiel #1
0
    def onNotification(self, sender, method, data):
        '''builtin function for the xbmc.Monitor class'''
        try:
            log_msg("Kodi_Monitor: sender %s - method: %s  - data: %s" % (sender, method, data))
            data = json.loads(data.decode('utf-8'))
            mediatype = ""
            if data and isinstance(data, dict):
                if data.get("item"):
                    mediatype = data["item"].get("type", "")
                elif data.get("type"):
                    mediatype = data["type"]

            if method == "VideoLibrary.OnUpdate":
                if not mediatype:
                    mediatype = self.last_mediatype # temp hack
                self.refresh_video_widgets(mediatype)

            if method == "AudioLibrary.OnUpdate":
                self.refresh_music_widgets(mediatype)

            if method == "Player.OnStop":
                self.last_mediatype = mediatype
                if mediatype in ["movie", "episode", "musicvideo"]:
                    if self.addon.getSetting("aggresive_refresh") == "true":
                        self.refresh_video_widgets(mediatype)

        except Exception as exc:
            log_msg("Exception in KodiMonitor: %s" % exc, xbmc.LOGERROR)
Beispiel #2
0
 def onDatabaseUpdated(self, database):
     '''builtin function for the xbmc.Monitor class'''
     log_msg("Kodi_Monitor: %s database updated" % database)
     if database == "music":
         self.refresh_music_widgets("")
     else:
         self.refresh_video_widgets("")
Beispiel #3
0
    def __init__(self):
        self.win = xbmcgui.Window(10000)
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.metadatautils = MetadataUtils()
        self.addonname = self.addon.getAddonInfo('name').decode("utf-8")
        self.addonversion = self.addon.getAddonInfo('version').decode("utf-8")
        self.kodimonitor = KodiMonitor(metadatautils=self.metadatautils, win=self.win)
        listitem_monitor = ListItemMonitor(
            metadatautils=self.metadatautils, win=self.win, monitor=self.kodimonitor)
        webservice = WebService(metadatautils=self.metadatautils)

        # start the extra threads
        listitem_monitor.start()
        webservice.start()
        self.win.clearProperty("SkinHelperShutdownRequested")
        log_msg('%s version %s started' % (self.addonname, self.addonversion), xbmc.LOGNOTICE)

        # run as service, check skin every 10 seconds and keep the other threads alive
        while not self.kodimonitor.abortRequested():

            # check skin version info
            self.check_skin_version()

            # sleep for 10 seconds
            self.kodimonitor.waitForAbort(10)

        # Abort was requested while waiting. We should exit
        self.win.setProperty("SkinHelperShutdownRequested", "shutdown")
        log_msg('Shutdown requested !', xbmc.LOGNOTICE)
        # stop the extra threads
        listitem_monitor.stop()
        webservice.stop()

        # cleanup objects
        self.close()
 def stop(self):
     '''cleanup on exit'''
     self.__exit = True
     if self.__spotty_proc:
         self.__spotty_proc.terminate()
         log_msg("spotty terminated")
         self.join(2)
Beispiel #5
0
 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")
    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)
Beispiel #7
0
def insert_data_into_db(timestamp, metrics):
    global db, last_day, last_hour

    if not timestamp:
        return

    new_data = []
    hosts = 0
    length = 0
    count = 0
    (day, hour, minute) = timestamp.split('|')

    if last_hour != hour:
        db.summarize_data('hour', last_day, last_hour)
        last_hour = hour

    if last_day != day:
        db.summarize_data('day', last_day)
        last_day = day

    for host_id in metrics:
        new_data.append((day, hour, minute, host_id, metrics[host_id]['length'], metrics[host_id]['count']))
        hosts += 1
        count += metrics[host_id]['count']
        length += metrics[host_id]['length']
    log_msg('adding: day='+str(day)+' '+str(hour)+':'+str(minute)+', hosts='+str(hosts)+', count='+str(count)+', length='+str(length))

    db.add_bandwidth(new_data)
 def close(self):
     '''Cleanup Kodi Cpython instances'''
     self.artutils.close()
     del self.win
     del self.kodimonitor
     del self.artutils
     log_msg('%s version %s stopped' % (self.addonname, self.addonversion), xbmc.LOGNOTICE)
Beispiel #9
0
 def pvr_proceed_lookup(self, title, channel, genre, recordingdetails):
     '''perform some checks if we can proceed with the lookup'''
     filters = []
     if not title:
         filters.append("Title is empty")
     for item in self.metadatautils.addon.getSetting("pvr_art_ignore_titles").split("|"):
         if item and item.lower() == title.lower():
             filters.append("Title is in list of titles to ignore")
     for item in self.metadatautils.addon.getSetting("pvr_art_ignore_channels").split("|"):
         if item and item.lower() == channel.lower():
             filters.append("Channel is in list of channels to ignore")
     for item in self.metadatautils.addon.getSetting("pvr_art_ignore_genres").split("|"):
         if genre and item and item.lower() in genre.lower():
             filters.append("Genre is in list of genres to ignore")
     if self.metadatautils.addon.getSetting("pvr_art_ignore_commongenre") == "true":
         # skip common genres like sports, weather, news etc.
         genre = genre.lower()
         kodi_strings = [19516, 19517, 19518, 19520, 19548, 19549, 19551,
                         19552, 19553, 19554, 19555, 19556, 19557, 19558, 19559]
         for kodi_string in kodi_strings:
             kodi_string = xbmc.getLocalizedString(kodi_string).lower()
             if (genre and (genre in kodi_string or kodi_string in genre)) or kodi_string in title:
                 filters.append("Common genres like weather/sports are set to be ignored")
     if self.metadatautils.addon.getSetting("pvr_art_recordings_only") == "true" and not recordingdetails:
         filters.append("PVR Artwork is enabled for recordings only")
     if filters:
         filterstr = " - ".join(filters)
         log_msg("PVR artwork - filter active for title: %s - channel %s --> %s" % (title, channel, filterstr))
         return filterstr
     else:
         return ""
Beispiel #10
0
 def refresh_music_widgets(self, media_type):
     '''refresh music widgets'''
     log_msg("Music database changed - type: %s - refreshing widgets...." % media_type)
     timestr = time.strftime("%Y%m%d%H%M%S", time.gmtime())
     self.win.setProperty("widgetreload-music", timestr)
     self.win.setProperty("widgetreloadmusic", timestr)
     if media_type:
         self.win.setProperty("widgetreload-%ss" % media_type, timestr)
 def tvshowtitle(self, showtitle, prefix=""):
     '''set details for single show by name'''
     log_msg("Set NextAired properties for TV Show: %s" % showtitle)
     details = self.thetvdb.get_kodishow_details(showtitle)
     if not details or not showtitle:
         self.clear_properties(prefix)
     else:
         self.set_properties(details, prefix)
Beispiel #12
0
    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 xbmc.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 xbmc.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 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 onPlayBackSeek(self, seekTime, seekOffset):
     '''Kodi event fired when the user is seeking'''
     if self.__ignore_seek:
         self.__ignore_seek = False
     elif self.connect_playing:
         log_msg("Kodiplayer seekto: %s" % seekTime)
         if self.connect_local:
             self.__ignore_seek = True
         self.__sp.seek_track(seekTime)
 def run(self):
     '''called to start our webservice'''
     log_msg("WebService - start helper webservice on port %s" % PORT, xbmc.LOGNOTICE)
     try:
         server = StoppableHttpServer(('127.0.0.1', PORT), StoppableHttpRequestHandler)
         server.artutils = self.artutils
         server.serve_forever()
     except Exception as exc:
         log_exception(__name__, exc)
 def updateshow(self, showtitle):
     '''force update of single show'''
     if showtitle:
         log_msg("Update show data requested for TV Show: %s" % showtitle)
         self.win.setProperty("nextaired.update_data", "busy")
         self.thetvdb.ignore_cache = True
         self.thetvdb.get_kodishow_details(showtitle)
         self.thetvdb.ignore_cache = False
         self.win.clearProperty("nextaired.update_data")
Beispiel #16
0
 def refresh_video_widgets(self, media_type):
     '''refresh video widgets'''
     log_msg("Video database changed - type: %s - refreshing widgets...." % media_type)
     timestr = time.strftime("%Y%m%d%H%M%S", time.gmtime())
     self.win.setProperty("widgetreload", timestr)
     if media_type:
         self.win.setProperty("widgetreload-%ss" % media_type, timestr)
         if "episode" in media_type:
             self.win.setProperty("widgetreload-tvshows", timestr)
Beispiel #17
0
 def run(self):
     '''called to start our webservice'''
     log_msg("WebService - start helper webservice on port %s" % PORT, xbmc.LOGNOTICE)
     try:
         server = StoppableHttpServer(('127.0.0.1', PORT), StoppableHttpRequestHandler)
         server.metadatautils = self.metadatautils
         server.serve_forever()
     except Exception as exc:
         if "10053" not in exc: # ignore host diconnected errors
             log_exception(__name__, exc)
 def onPlayBackStopped(self):
     '''Kodi event fired when playback is stopped'''
     if self.connect_playing:
         try:
             self.__sp.pause_playback()
         except Exception:
             pass
         log_msg("playback stopped")
     self.connect_playing = False
     self.connect_local = False
 def stop(self):
     '''called when the thread needs to stop'''
     try:
         log_msg("WebService - stop called", 0)
         conn = httplib.HTTPConnection("127.0.0.1:%d" % PORT)
         conn.request("QUIT", "/")
         conn.getresponse()
         self.exit = True
         self.event.set()
     except Exception as exc:
         log_exception(__name__, exc)
 def refresh_video_widgets(self, media_type):
     '''refresh video widgets'''
     if not self.update_video_widgets_busy:
         self.update_video_widgets_busy = True
         log_msg("Video database changed - type: %s - refreshing widgets...." % media_type)
         xbmc.sleep(500)
         timestr = time.strftime("%Y%m%d%H%M%S", time.gmtime())
         self.win.setProperty("widgetreload", timestr)
         if media_type:
             self.win.setProperty("widgetreload-%ss" % media_type, timestr)
         self.update_video_widgets_busy = False
 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 onNotification(self, sender, method, data):
        '''builtin function for the xbmc.Monitor class'''
        try:
            log_msg("Kodi_Monitor: sender %s - method: %s  - data: %s" % (sender, method, data))
            data = json.loads(data.decode('utf-8'))
            mediatype = ""
            dbid = 0
            transaction = False
            if data and isinstance(data, dict):
                if data.get("item"):
                    mediatype = data["item"].get("type", "")
                    dbid = data["item"].get("id", 0)
                elif data.get("type"):
                    mediatype = data["type"]
                    id = data.get("id", 0)
                if data.get("transaction"):
                    transaction = True

            if method == "System.OnQuit":
                self.win.setProperty("SkinHelperShutdownRequested", "shutdown")

            if method == "VideoLibrary.OnUpdate":
                self.process_db_update(mediatype, dbid, transaction)

            if method == "AudioLibrary.OnUpdate":
                self.process_db_update(mediatype, dbid, transaction)

            if method == "Player.OnStop":
                self.monitoring_stream = False
                self.infopanelshown = False
                self.win.clearProperty("Skinhelper.PlayerPlaying")
                self.win.clearProperty("TrailerPlaying")
                self.reset_win_props()
                if not dbid:
                    self.process_db_update(mediatype, "", transaction)

            if method == "Player.OnPlay":
                self.reset_win_props()
                if self.wait_for_player():
                    if xbmc.getCondVisibility("Player.HasAudio"):
                        if xbmc.getCondVisibility("Player.IsInternetStream"):
                            self.monitor_radiostream()
                        else:
                            self.set_music_properties()
                    elif xbmc.getCondVisibility("VideoPlayer.Content(livetv)"):
                        self.monitor_livetv()
                    else:
                        self.set_video_properties(mediatype, dbid)
                        self.show_info_panel()
        except Exception as exc:
            log_exception(__name__, exc)
    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 update_data(self, ignore_cache=False):
     '''updates all data we need in cache'''
     if self.win.getProperty("nextaired.update_data"):
         log_msg("Update data skipped, another update is in progress")
     else:
         self.win.setProperty("nextaired.update_data", "busy")
         # build details in cache for all continuing series in the kodi db
         log_msg("Updating TheTVDB info for all continuing Kodi tv shows...", xbmc.LOGNOTICE)
         self.thetvdb.ignore_cache = ignore_cache
         continuing_kodi_shows = self.thetvdb.get_kodishows_details(continuing_only=True)
         self.win.setProperty("NextAired.Total", "%s" % len(continuing_kodi_shows))
         # build nextaired episodes listing in cache
         log_msg("Retrieving next airing episodes for all continuing Kodi tv shows...", xbmc.LOGNOTICE)
         want_yesterday = self.addon.getSetting("WantYesterday") == 'true'
         self.thetvdb.get_kodi_unaired_episodes(include_last_episode=want_yesterday)
         # set the window properties for the shows that are airing today
         prev_total = self.win.getProperty("NextAired.TodayTotal")
         prev_total = int(prev_total) if prev_total else 0
         # clear previous properties
         for count in range(prev_total + 1):
             self.clear_properties("%s." % count)
         shows_airing_today = self.thetvdb.get_kodishows_airingtoday()
         all_titles = []
         for count, show_details in enumerate(shows_airing_today):
             self.set_properties(show_details, "%s." % count)
             all_titles.append(show_details["title"])
         self.win.setProperty("NextAired.TodayTotal", "%s" % len(shows_airing_today))
         self.win.setProperty("NextAired.TodayShow", "[CR]".join(all_titles))
         self.thetvdb.ignore_cache = False
         self.win.clearProperty("nextaired.update_data")
         log_msg("Update complete", xbmc.LOGNOTICE)
 def __init__(self):
     '''Initialization and main code run'''
     self.win = xbmcgui.Window(10000)
     self.addon = xbmcaddon.Addon(ADDON_ID)
     self.thetvdb = TheTvDb()
     self.set_dates()
     action, action_param = self.get_params()
     self.improve_dates = self.addon.getSetting("ImproveDates") == 'true'
     log_msg("MainModule called with action: %s - parameter: %s" % (action, action_param))
     # launch module for action provided by this script
     try:
         getattr(self, action)(action_param)
     except Exception as exc:
         log_exception(__name__, exc)
     finally:
         self.close()
    def __init__(self):
        addon = xbmcaddon.Addon(ADDON_ID)
        addonname = addon.getAddonInfo('name').decode("utf-8")
        addonversion = addon.getAddonInfo('version').decode("utf-8")
        del addon
        kodimonitor = xbmc.Monitor()       
        log_msg('%s version %s started' % (addonname, addonversion), xbmc.LOGNOTICE)

        while not kodimonitor.abortRequested():
            
            # run update task every hour
            xbmc.executebuiltin("RunScript(script.tv.show.next.aired,update=True)")
            kodimonitor.waitForAbort(3600)

        # Abort was requested while waiting. Do cleanup
        del kodimonitor
        log_msg('%s version %s stopped' % (addonname, addonversion), xbmc.LOGNOTICE)
 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)
 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)
Beispiel #29
0
 def get_animated_artwork(self, imdb_id, manual_select=False, ignore_cache=False):
     '''returns all available animated art for the given imdbid/tmdbid'''
     # prefer local result
     kodi_movie = self.kodidb.movie_by_imdbid(imdb_id)
     if not manual_select and kodi_movie and kodi_movie["art"].get("animatedposter"):
         result = {
             "animatedposter": kodi_movie["art"].get("animatedposter"),
             "animatedfanart": kodi_movie["art"].get("animatedfanart")
         }
     else:
         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
Beispiel #30
0
 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)
Beispiel #31
0
    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
Beispiel #32
0
    def get_album_metadata(self,
                           artist,
                           album,
                           track,
                           disc,
                           ignore_cache=False,
                           flush_cache=False,
                           manual=False):
        """collect all album metadata"""
        cache_str = "music_artwork.album.%s.%s.%s" % (
            artist.lower(), album.lower(), disc.lower())
        if not album:
            cache_str = "music_artwork.album.%s.%s" % (artist.lower(),
                                                       track.lower())
        details = {"art": {}, "cachestr": cache_str}

        log_msg("get_album_metadata --> artist: %s - album: %s - track: %s" %
                (artist, album, track))
        # retrieve details from cache
        cache = self._mutils.cache.get(cache_str)
        if not cache and flush_cache:
            # nothing to do - just return empty results
            return details
        elif cache and flush_cache:
            # only update kodi metadata for updated counts etc
            details = extend_dict(
                self.get_album_kodi_metadata(artist, album, track, disc),
                cache)
        elif cache and not ignore_cache:
            # we have a valid cache - return that
            details = cache
        elif cache and manual:
            # user wants to manually override the artwork in the cache
            details = self.manual_set_music_artwork(cache, "album")
        else:
            # nothing in cache - start metadata retrieval
            local_path = ""
            local_path_custom = ""
            # get metadata from kodi db
            details = extend_dict(
                details,
                self.get_album_kodi_metadata(artist, album, track, disc))
            if not album and details.get("title"):
                album = details["title"]
            # get artwork from songlevel path
            if details.get(
                    "local_path_custom") and self._mutils.addon.getSetting(
                        "music_art_musicfolders") == "true":
                details["art"] = extend_dict(
                    details["art"],
                    self.lookup_albumart_in_folder(
                        details["local_path_custom"]))
                local_path = details["local_path_custom"]
            # get artwork from custom folder
            custom_path = None
            if self._mutils.addon.getSetting("music_art_custom") == "true":
                if sys.version_info.major == 3:
                    custom_path = self._mutils.addon.getSetting(
                        "music_art_custom_path")
                else:
                    custom_path = self._mutils.addon.getSetting(
                        "music_art_custom_path").decode("utf-8")
                local_path_custom = self.get_custom_album_path(
                    custom_path, artist, album, disc)
                details["art"] = extend_dict(
                    details["art"],
                    self.lookup_albumart_in_folder(local_path_custom))
                details["customartpath"] = local_path_custom
            # lookup online metadata
            if self._mutils.addon.getSetting("music_art_scraper") == "true":
                # prefer the musicbrainzid that is already in the kodi database - only perform lookup if missing
                mb_albumid = details.get("musicbrainzalbumid")
                if not mb_albumid:
                    mb_albumid = self.get_mb_album_id(artist, album, track)
                    adb_album = self.audiodb.get_album_id(artist, album, track)
                if mb_albumid:
                    # get artwork from fanarttv
                    if self._mutils.addon.getSetting(
                            "music_art_scraper_fatv") == "true":
                        details["art"] = extend_dict(
                            details["art"],
                            self._mutils.fanarttv.album(mb_albumid))
                    # get metadata from theaudiodb
                    if self._mutils.addon.getSetting(
                            "music_art_scraper_adb") == "true":
                        details = extend_dict(
                            details,
                            self.audiodb.album_info(artist, adb_album))
                    # get metadata from lastfm
                    if self._mutils.addon.getSetting(
                            "music_art_scraper_lfm") == "true":
                        details = extend_dict(
                            details, self.lastfm.album_info(mb_albumid))
                    # metadata from musicbrainz
                    if not details.get("year") or not details.get("genre"):
                        details = extend_dict(
                            details, self.mbrainz.get_albuminfo(mb_albumid))
                    # musicbrainz thumb as last resort
                    if not details["art"].get("thumb"):
                        details["art"]["thumb"] = self.mbrainz.get_albumthumb(
                            mb_albumid)
                    # download artwork to music folder
                    # get artwork from custom folder
                    # (yes again, but this time we might have an album where we didnt have that before)
                    if custom_path and not album and details.get("title"):
                        album = details["title"]
                        diskpath = self.get_custom_album_path(
                            custom_path, artist, album, disc)
                        if diskpath:
                            details["art"] = extend_dict(
                                details["art"],
                                self.lookup_albumart_in_folder(diskpath))
                            local_path_custom = diskpath
                            details["customartpath"] = diskpath
                    # download artwork to custom folder
                    if custom_path and self._mutils.addon.getSetting(
                            "music_art_download_custom") == "true":
                        if local_path_custom:
                            # allow folder creation if we enabled downloads and the folder does not exist
                            artist_path = self.get_customfolder_path(
                                custom_path, artist)
                            if artist_path:
                                local_path_custom = os.path.join(
                                    artist_path, album)
                            else:
                                local_path_custom = os.path.join(
                                    custom_path, artist, album)
                            details["customartpath"] = local_path_custom
                        details["art"] = download_artwork(
                            local_path_custom, details["art"])
        # set default details
        if not details.get("album") and details.get("title"):
            details["album"] = details["title"]
        if details["art"].get("thumb"):
            details["art"]["albumthumb"] = details["art"]["thumb"]

        # store results in cache and return results
        self._mutils.cache.set(cache_str, details)
        #        self.write_kodidb(details)
        return details
Beispiel #33
0
    def show_widget_listing(self):
        '''display the listing for the provided action and mediatype'''
        media_type = self.options["mediatype"]
        action = self.options["action"]
        # set widget content type
        if media_type in ["favourites", "pvr", "media"]:
            xbmcplugin.setContent(ADDON_HANDLE, "files")
        else:
            xbmcplugin.setContent(ADDON_HANDLE, media_type)

        # try to get from cache first...
        all_items = []
        # alter cache_str depending on whether "tag" is available
        if self.options["action"] == "similar":
            # if action is similar, use imdbid
            cache_id = self.options.get("imdbid", "")
            # if similar was called without imdbid, skip cache
            if not self.options.get("imdbid", ""):
                self.options["skipcache"] = "true"
        elif self.options["action"] == "playlist" and self.options[
                "mediatype"] == "media":
            # if action is mixed playlist, use playlist labels
            cache_id = self.options.get("movie_label") + self.options.get(
                "tv_label")
        else:
            # use tag otherwise
            cache_id = self.options.get("tag")
        cache_str = "SkinHelper.Widgets.%s.%s.%s.%s.%s" % (
            media_type, action, self.options["limit"],
            self.options.get("path"), cache_id)
        if not self.win.getProperty("widgetreload2"):
            # at startup we simply accept whatever is in the cache
            cache_checksum = None
        else:
            # we use a checksum based on the reloadparam to make sure we have the most recent data
            cache_checksum = self.options.get("reload", "")
        # only check cache if not "skipcache"
        if not self.options.get("skipcache") == "true":
            cache = self.metadatautils.cache.get(cache_str,
                                                 checksum=cache_checksum)
            if cache:
                log_msg(
                    "MEDIATYPE: %s - ACTION: %s - PATH: %s - TAG: %s -- got items from cache - CHECKSUM: %s"
                    % (media_type, action, self.options.get("path"),
                       self.options.get("tag"), cache_checksum))
                all_items = cache

        # Call the correct method to get the content from json when no cache
        if not all_items:
            log_msg(
                "MEDIATYPE: %s - ACTION: %s - PATH: %s - TAG: %s -- no cache, quering kodi api to get items - CHECKSUM: %s"
                % (media_type, action, self.options.get("path"),
                   self.options.get("tag"), cache_checksum))

            # dynamically import and load the correct module, class and function
            try:
                media_module = __import__(media_type)
                media_class = getattr(media_module, media_type.capitalize())(
                    self.addon, self.metadatautils, self.options)
                all_items = getattr(media_class, action)()
                del media_class
            except AttributeError:
                log_exception(__name__,
                              "Incorrect widget action or type called")
            except Exception as exc:
                log_exception(__name__, exc)

            # randomize output if requested by skinner or user
            if self.options.get("randomize", "") == "true":
                all_items = sorted(all_items, key=lambda k: random.random())

            # prepare listitems and store in cache
            all_items = self.metadatautils.process_method_on_list(
                self.metadatautils.kodidb.prepare_listitem, all_items)
            self.metadatautils.cache.set(cache_str,
                                         all_items,
                                         checksum=cache_checksum)

        # fill that listing...
        xbmcplugin.addSortMethod(int(sys.argv[1]),
                                 xbmcplugin.SORT_METHOD_UNSORTED)
        all_items = self.metadatautils.process_method_on_list(
            self.metadatautils.kodidb.create_listitem, all_items)
        xbmcplugin.addDirectoryItems(ADDON_HANDLE, all_items, len(all_items))

        # end directory listing
        xbmcplugin.endOfDirectory(handle=ADDON_HANDLE)
Beispiel #34
0
 def lms(self, filename, **kwargs):
     ''' fake lms hook to retrieve events form spotty daemon'''
     method = cherrypy.request.method.upper()
     if method != "POST" or filename != "jsonrpc.js":
         raise cherrypy.HTTPError(405)
     input_json = cherrypy.request.json
     if input_json and input_json.get("params"):
         event = input_json["params"][1]
         log_msg("lms event hook called. Event: %s" % event)
         # check username, it might have changed
         spotty_user = self.__spotty.get_username()
         cur_user = xbmc.getInfoLabel(
             "Window(Home).Property(spotify-username)").decode("utf-8")
         if spotty_user != cur_user:
             log_msg("user change detected")
             xbmc.executebuiltin("SetProperty(spotify-cmd,__LOGOUT__,Home)")
         if "start" in event:
             log_msg("playback start requested by connect")
             xbmc.executebuiltin(
                 "RunPlugin(plugin://plugin.audio.spotify/?action=play_connect)"
             )
         elif "change" in event:
             log_msg("playback change requested by connect")
             # we ignore this as track changes are
             #xbmc.executebuiltin("RunPlugin(plugin://plugin.audio.spotify/?action=play_connect)")
         elif "stop" in event:
             log_msg("playback stop requested by connect")
             xbmc.executebuiltin("PlayerControl(Stop)")
         elif "volume" in event:
             vol_level = event[2]
             log_msg("volume change detected on connect player: %s" %
                     vol_level)
             # ignore for now as it needs more work
             #xbmc.executebuiltin("SetVolume(%s,true)" % vol_level)
     return {"operation": "request", "result": "success"}
Beispiel #35
0
def archive_table(name='', weeks=''):
    global db
    day = (date.today() - timedelta(weeks=weeks)).strftime('%Y-%m-%d')
    log_msg('archiving table: name=' + str(name) + ', weeks=' + str(weeks) +
            ', day=' + str(day))
    log_msg('archiving done')
    def show_widget_listing(self):
        '''display the listing for the provided action and mediatype'''
        media_type = self.options["mediatype"]
        action = self.options["action"]
        # set widget content type
        xbmcplugin.setContent(ADDON_HANDLE, media_type)

        # try to get from cache first...
        # we use a checksum based on the options to make sure the cache is ignored when needed
        all_items = []
        cache_str = "SkinHelper.Widgets.%s.%s" % (media_type, action)
        if not self.win.getProperty("widgetreload2"):
            # at startup we simply accept whatever is in the cache
            cache_checksum = None
        else:
            cache_checksum = ""
            for key in sorted(self.options):
                cache_checksum += "%s.%s" % (key, self.options[key])
        cache = self.cache.get(cache_str, checksum=cache_checksum)
        if cache and not self.options.get("skipcache") == "true":
            log_msg(
                "MEDIATYPE: %s - ACTION: %s -- got items from cache - CHECKSUM: %s"
                % (media_type, action, cache_checksum))
            all_items = cache

        # Call the correct method to get the content from json when no cache
        if not all_items:
            log_msg(
                "MEDIATYPE: %s - ACTION: %s -- no cache, quering kodi api to get items - CHECKSUM: %s"
                % (media_type, action, cache_checksum))

            # dynamically import and load the correct module, class and function
            try:
                media_module = __import__(media_type)
                media_class = getattr(media_module,
                                      media_type.capitalize())(self.addon,
                                                               self.artutils,
                                                               self.options)
                all_items = getattr(media_class, action)()
                del media_class
            except AttributeError:
                log_exception(__name__,
                              "Incorrect widget action or type called")
            except Exception as exc:
                log_exception(__name__, exc)

            # randomize output if requested by skinner or user
            if self.options.get("randomize", "") == "true":
                all_items = sorted(all_items, key=lambda k: random.random())

            # prepare listitems and store in cache
            all_items = process_method_on_list(
                self.artutils.kodidb.prepare_listitem, all_items)
            self.cache.set(cache_str, all_items, checksum=cache_checksum)

        # fill that listing...
        xbmcplugin.addSortMethod(int(sys.argv[1]),
                                 xbmcplugin.SORT_METHOD_UNSORTED)
        all_items = process_method_on_list(
            self.artutils.kodidb.create_listitem, all_items)
        xbmcplugin.addDirectoryItems(ADDON_HANDLE, all_items, len(all_items))

        # end directory listing
        xbmcplugin.endOfDirectory(handle=ADDON_HANDLE)
Beispiel #37
0
 def run(self):
     log_msg("Start Spotify Connect Daemon")
     self.__exit = False
     self.daemon_active = True
     spotty_args = ["--lms", "localhost:52308/lms", "--player-mac", "None"]
     disable_discovery = False
     if xbmcvfs.exists("/run/libreelec/"):
         disable_discovery = True  # avahi on libreelec conflicts with the mdns implementation of librespot
         xbmc.executebuiltin("SetProperty(spotify-discovery,disabled,Home)")
     try:
         try:
             log_msg("trying AP Port 443", xbmc.LOGNOTICE)
             self.__spotty_proc = self.__spotty.run_spotty(
                 arguments=spotty_args,
                 disable_discovery=disable_discovery,
                 ap_port="443")
         except:
             try:
                 log_msg("trying AP Port 80", xbmc.LOGNOTICE)
                 self.__spotty_proc = self.__spotty.run_spotty(
                     arguments=spotty_args,
                     disable_discovery=disable_discovery,
                     ap_port="80")
             except:
                 log_msg("trying AP Port 4070", xbmc.LOGNOTICE)
                 self.__spotty_proc = self.__spotty.run_spotty(
                     arguments=spotty_args,
                     disable_discovery=disable_discovery,
                     ap_port="4070")
         while not self.__exit:
             line = self.__spotty_proc.stdout.readline()
             if self.__spotty_proc.returncode and self.__spotty_proc.returncode > 0 and not self.__exit:
                 # daemon crashed ? restart ?
                 log_msg("spotty stopped!", xbmc.LOGNOTICE)
                 break
             xbmc.sleep(100)
         self.daemon_active = False
         log_msg("Stopped Spotify Connect Daemon")
     except:
         self.daemon_active = False
         log_msg("Cannot run SPOTTY, No APs available", xbmc.LOGNOTICE)
Beispiel #38
0
def privmsg(**kwargs):
    if kwargs["target"] == '#turkish':
        nick = kwargs["nick"]
        msg = kwargs["message"]
        log_msg(nick, msg)
        if title:
            log_msg(
                "Animated Art: lookup imdbid by title and year: (%s - %s)" %
                (title, year), xbmc.LOGNOTICE)
            imdb_id = artutils.get_omdb_info("", title, year,
                                             content_type).get(
                                                 "imdbnumber", "")
        if not imdb_id:
            return title
    return imdb_id


# Kodi contextmenu item to configure the artwork
if __name__ == '__main__':
    xbmc.executebuiltin("ActivateWindow(busydialog)")
    log_msg("Contextmenu for Animated Art opened", xbmc.LOGNOTICE)
    ARTUTILS = ArtUtils()
    WIN = xbmcgui.Window(10000)
    imdb_id = get_imdb_id(WIN, ARTUTILS)
    WIN.setProperty("SkinHelper.Artwork.ManualLookup", "busy")
    log_msg("Animated Art: Query animated art by IMDBID: %s" % imdb_id,
            xbmc.LOGNOTICE)
    artwork = ARTUTILS.get_animated_artwork(imdb_id,
                                            ignore_cache=True,
                                            manual_select=True)
    log_msg("Animated Art result: %s" % artwork, xbmc.LOGNOTICE)
    xbmc.executebuiltin("Dialog.Close(busydialog)")
    xbmc.executebuiltin("Container.Refresh")
    WIN.clearProperty("SkinHelper.Artwork.ManualLookup")
    del WIN
    ARTUTILS.close()
Beispiel #40
0
 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)))
     if sys.version_info.major == 3:
         json_object = json.loads(json_response)
     else:
         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
             if sys.version_info.major == 3:
                 for key, value in json_object['result'].items():
                     if not key == "limits" and (isinstance(value, list) or
                                                 isinstance(value, dict)):
                         result = value
             else:
                 for key, value in json_object['result'].items():
                     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
    def monitor_lms(self):
        '''monitor the state of the self.lmsserver/player'''
        # poll the status every interval
        self.lmsserver.update_status()

        if self.exit:
            return

        # make sure that the status is not actually changing right now
        if not self.lmsserver.state_changing and not self.kodiplayer.is_busy:

            # monitor LMS player and server details
            if self._sl_exec and (
                    self.lmsserver.power == 1 or not self._temp_power_off
            ) and xbmc.getCondVisibility("Player.HasVideo"):
                # turn off lms player when kodi is playing video
                self.lmsserver.send_command("power 0")
                self._temp_power_off = True
                self.kodiplayer.is_playing = False
                log_msg("Kodi started playing video - disabled the LMS player")
            elif self._temp_power_off and not xbmc.getCondVisibility(
                    "Player.HasVideo"):
                # turn on player again when video playback was finished
                self.lmsserver.send_command("power 1")
                self._temp_power_off = False
            elif self.kodiplayer.is_playing and self._prev_checksum != self.lmsserver.timestamp:
                # the playlist was modified
                self._prev_checksum = self.lmsserver.timestamp
                log_msg("playlist changed on lms server")
                self.kodiplayer.update_playlist()
                # self.kodiplayer.play(self.kodiplayer.playlist, startpos=self.lmsserver.cur_index) # Don't start playing again
            elif not self.kodiplayer.is_playing and self.lmsserver.mode == "play":
                # playback started
                log_msg("play started by lms server")
                self._prev_checksum = self.lmsserver.timestamp  # Set Timestemp on start of playing
                self.kodiplayer.update_playlist(
                )  # Update playlist on start of playing
                # if not len(self.kodiplayer.playlist):
                #    self.kodiplayer.update_playlist()
                self.kodiplayer.play(self.kodiplayer.playlist,
                                     startpos=self.lmsserver.cur_index)

            elif self.kodiplayer.is_playing:
                # monitor some conditions if the player is playing
                if self.kodiplayer.is_playing and self.lmsserver.mode == "stop":
                    # playback stopped
                    log_msg("stop requested by lms server")
                    self.kodiplayer.stop()
                elif xbmc.getCondVisibility("Playlist.IsRandom"):
                    # make sure that the kodi player doesnt have shuffle enabled
                    log_msg("Playlist is randomized! Reload to unshuffle....")
                    self.kodiplayer.playlist.unshuffle()
                    self.kodiplayer.update_playlist()
                    self.kodiplayer.is_playing = False  # it seems that xbmc.player calls the OnPlayBackStopped function if the play function is called while already playing.
                    self.kodiplayer.play(self.kodiplayer.playlist,
                                         startpos=self.lmsserver.cur_index)
                elif xbmc.getCondVisibility(
                        "Player.Paused") and self.lmsserver.mode == "play":
                    # playback resumed
                    log_msg("resume requested by lms server")
                    xbmc.executebuiltin("PlayerControl(play)")
                elif not xbmc.getCondVisibility(
                        "Player.Paused") and self.lmsserver.mode == "pause":
                    # playback paused
                    log_msg("pause requested by lms server")
                    self.kodiplayer.pause()
                elif self.kodiplayer.playlist.getposition(
                ) != self.lmsserver.cur_index:
                    # other track requested
                    self.kodiplayer.is_playing = False  # it seems that xbmc.player calls the OnPlayBackStopped function if the play function is called while already playing.
                    log_msg("other track requested by lms server")
                    self.kodiplayer.play(self.kodiplayer.playlist,
                                         startpos=self.lmsserver.cur_index)
                elif self.lmsserver.status["title"] != xbmc.getInfoLabel(
                        "MusicPlayer.Title").decode("utf-8"):
                    # monitor if title still matches
                    log_msg("title mismatch - updating playlist...")
                    self.kodiplayer.update_playlist()
                    log_msg("other track requested by lms server")
                    self.kodiplayer.is_playing = False  # it seems that xbmc.player calls the OnPlayBackStopped function if the play function is called while already playing.
                    self.kodiplayer.play(self.kodiplayer.playlist,
                                         startpos=self.lmsserver.cur_index)
                elif self.lmsserver.mode == "play" and not self.lmsserver.status[
                        "current_title"]:
                    # check if seeking is needed - if current_title has value, it means it's a radio stream so we ignore that
                    # we accept a difference of max 2 seconds
                    cur_time_lms = int(self.lmsserver.time)
                    cur_time_kodi = self.kodiplayer.cur_time()
                    if cur_time_kodi > 2:
                        if cur_time_kodi != cur_time_lms and abs(
                                cur_time_lms - cur_time_kodi
                        ) > 2 and not xbmc.getCondVisibility("Player.Paused"):
                            # seek started
                            log_msg(
                                "seek requested by lms server - kodi-time: %s  - lmstime: %s"
                                % (cur_time_kodi, cur_time_lms))
                            self.kodiplayer.is_busy = True
                            self.kodiplayer.seekTime(cur_time_lms)
                            xbmc.sleep(250)
                            self.kodiplayer.is_busy = False
Beispiel #42
0
 def nexttrack(self, **kwargs):
     '''play silence while spotify connect player is waiting for the next track'''
     log_msg('play silence while spotify connect player is waiting for the next track', xbmc.LOGDEBUG)
     return self.silence(20)
Beispiel #43
0
 def onPlayBackPaused(self):
     '''Kodi event fired when playback is paused'''
     if self.connect_playing and not self.__is_paused:
         self.__sp.pause_playback()
         log_msg("Playback paused")
     self.__is_paused = True
Beispiel #44
0
 def default(self, path):
     '''all other requests go here'''
     log_msg("Webservice: Unknown method called ! (%s)" % path,
             xbmc.LOGWARNING)
     raise cherrypy.HTTPError(404, "Unknown method called")
Beispiel #45
0
 def onPlayBackResumed(self):
     '''Kodi event fired when playback is resumed after pause'''
     if self.connect_playing and self.__is_paused:
         self.__sp.start_playback()
         log_msg("Playback unpaused")
     self.__is_paused = False
Beispiel #46
0
def create_tables():
    global db
    log_msg('creating tables')
    db.create_tables()
Beispiel #47
0
    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 close(self):
     '''Cleanup Kodi Cpython instances on exit'''
     del self.win
     del self.addon
     del self.thetvdb
     log_msg("MainModule exited")
Beispiel #49
0
    log_msg('rebuilding table: name=' + str(name))
    day = db.get_min_full_day()
    db.summarize_data(name, day, compare='>=')
    log_msg('rebuilding done')


def archive_table(name='', weeks=''):
    global db
    day = (date.today() - timedelta(weeks=weeks)).strftime('%Y-%m-%d')
    log_msg('archiving table: name=' + str(name) + ', weeks=' + str(weeks) +
            ', day=' + str(day))
    log_msg('archiving done')


if __name__ == "__main__":
    global db

    log_msg('Initializing ' + __file__ + '...')

    args = parse_args()

    init_globals(args)

    rebuild_table('hour')
    rebuild_table('day')
    #archive_table('minute', args.minute_table)
    #archive_table('hour', args.hour_table)
    #archive_table('day', args.day_table)

    log_msg('Done.')
    def get_pvr_artwork(self,
                        title,
                        channel,
                        genre="",
                        manual_select=False,
                        ignore_cache=False):
        """
            collect full metadata and artwork for pvr entries
            parameters: title (required)
            channel: channel name (required)
            year: year or date (optional)
            genre: (optional)
            the more optional parameters are supplied, the better the search results
        """
        details = {"art": {}}
        # try cache first

        # use searchtitle when searching cache
        cache_title = title.lower()
        cache_channel = channel.lower()
        searchtitle = self.get_searchtitle(cache_title, cache_channel)
        # original cache_str assignment cache_str = "pvr_artwork.%s.%s" % (title.lower(), channel.lower())
        cache_str = "pvr_artwork.%s.%s" % (searchtitle, channel.lower())
        cache = self._mutils.cache.get(cache_str)
        if cache and not manual_select and not ignore_cache:
            log_msg("get_pvr_artwork - return data from cache - %s" %
                    cache_str)
            details = cache
        else:
            # no cache - start our lookup adventure
            log_msg("get_pvr_artwork - no data in cache - start lookup - %s" %
                    cache_str)

            # workaround for recordings
            recordingdetails = self.lookup_local_recording(title, channel)
            if recordingdetails and not (channel and genre):
                genre = recordingdetails["genre"]
                channel = recordingdetails["channel"]

            details["pvrtitle"] = title
            details["pvrchannel"] = channel
            details["pvrgenre"] = genre
            details["cachestr"] = cache_str
            details["media_type"] = ""
            details["art"] = {}

            # filter genre unknown/other
            if not genre or genre.split(" / ")[0] in xbmc.getLocalizedString(
                    19499).split(" / "):
                details["genre"] = []
                genre = ""
                log_msg("genre is unknown so ignore....")
            else:
                details["genre"] = genre.split(" / ")
                details["media_type"] = self.get_mediatype_from_genre(genre)
            searchtitle = self.get_searchtitle(title, channel)

            # only continue if we pass our basic checks
            filterstr = self.pvr_proceed_lookup(title, channel, genre,
                                                recordingdetails)
            proceed_lookup = False if filterstr else True
            if not proceed_lookup and manual_select:
                # warn user about active skip filter
                proceed_lookup = xbmcgui.Dialog().yesno(
                    line1=self._mutils.addon.getLocalizedString(32027),
                    line2=filterstr,
                    heading=xbmc.getLocalizedString(750))

            if proceed_lookup:

                # if manual lookup get the title from the user
                if manual_select:
                    if sys.version_info.major == 3:
                        searchtitle = xbmcgui.Dialog().input(
                            xbmc.getLocalizedString(16017),
                            searchtitle,
                            type=xbmcgui.INPUT_ALPHANUM)
                    else:
                        searchtitle = xbmcgui.Dialog().input(
                            xbmc.getLocalizedString(16017),
                            searchtitle,
                            type=xbmcgui.INPUT_ALPHANUM).decode("utf-8")
                    if not searchtitle:
                        return

                # if manual lookup and no mediatype, ask the user
                if manual_select and not details["media_type"]:
                    yesbtn = self._mutils.addon.getLocalizedString(32042)
                    nobtn = self._mutils.addon.getLocalizedString(32043)
                    header = self._mutils.addon.getLocalizedString(32041)
                    if xbmcgui.Dialog().yesno(header,
                                              header,
                                              yeslabel=yesbtn,
                                              nolabel=nobtn):
                        details["media_type"] = "movie"
                    else:
                        details["media_type"] = "tvshow"

                # append thumb from recordingdetails
                if recordingdetails and recordingdetails.get("thumbnail"):
                    details["art"]["thumb"] = recordingdetails["thumbnail"]
                # lookup custom path
                details = extend_dict(
                    details, self.lookup_custom_path(searchtitle, title))
                # lookup movie/tv library
                details = extend_dict(
                    details,
                    self.lookup_local_library(searchtitle,
                                              details["media_type"]))

                # do internet scraping if enabled
                if self._mutils.addon.getSetting("pvr_art_scraper") == "true":

                    log_msg(
                        "pvrart start scraping metadata for title: %s - media_type: %s"
                        % (searchtitle, details["media_type"]))

                    # prefer tmdb scraper
                    tmdb_result = self._mutils.get_tmdb_details(
                        "",
                        "",
                        searchtitle,
                        "",
                        "",
                        details["media_type"],
                        manual_select=manual_select,
                        ignore_cache=manual_select)
                    log_msg("pvrart lookup for title: %s - TMDB result: %s" %
                            (searchtitle, tmdb_result))
                    if tmdb_result:
                        details["media_type"] = tmdb_result["media_type"]
                        details = extend_dict(details, tmdb_result)

                    # fallback to tvdb scraper
                    # following 3 lines added as part of "auto refresh" fix. ensure manual_select=true for TVDB lookup. No idea why this works
                    tempmanualselect = manual_select
                    manual_select = "true"
                    log_msg(
                        "DEBUG INFO: TVDB lookup: searchtitle: %s channel: %s manual_select: %s"
                        % (searchtitle, channel, manual_select))
                    if (not tmdb_result
                            or (tmdb_result and not tmdb_result.get("art"))
                            or details["media_type"] == "tvshow"):
                        # original code: tvdb_match = self.lookup_tvdb(searchtitle, channel, manual_select=manual_select). part of "auto refresh" fix.
                        tvdb_match = self.lookup_tvdb(
                            searchtitle,
                            channel,
                            manual_select=manual_select,
                            tempmanualselect=tempmanualselect)
                        log_msg(
                            "pvrart lookup for title: %s - TVDB result: %s" %
                            (searchtitle, tvdb_match))
                        if tvdb_match:
                            # get full tvdb results and extend with tmdb
                            if not details["media_type"]:
                                details["media_type"] = "tvshow"
                            details = extend_dict(
                                details,
                                self._mutils.thetvdb.get_series(tvdb_match))
                            details = extend_dict(
                                details,
                                self._mutils.tmdb.
                                get_videodetails_by_externalid(
                                    tvdb_match,
                                    "tvdb_id"), ["poster", "fanart"])
                    # part of "auto refresh" fix - revert manual_select to original value
                    manual_select = tempmanualselect
                    # fanart.tv scraping - append result to existing art
                    if details.get(
                            "imdbnumber") and details["media_type"] == "movie":
                        details["art"] = extend_dict(
                            details["art"],
                            self._mutils.fanarttv.movie(details["imdbnumber"]),
                            ["poster", "fanart", "landscape"])
                    elif details.get(
                            "tvdb_id") and details["media_type"] == "tvshow":
                        details["art"] = extend_dict(
                            details["art"],
                            self._mutils.fanarttv.tvshow(details["tvdb_id"]),
                            ["poster", "fanart", "landscape"])

                    # append omdb details
                    if details.get("imdbnumber"):
                        details = extend_dict(
                            details,
                            self._mutils.omdb.get_details_by_imdbid(
                                details["imdbnumber"]), ["rating", "votes"])

                    # set thumbnail - prefer scrapers
                    thumb = ""
                    if details.get("thumbnail"):
                        thumb = details["thumbnail"]
                    elif details["art"].get("landscape"):
                        thumb = details["art"]["landscape"]
                    elif details["art"].get("fanart"):
                        thumb = details["art"]["fanart"]
                    elif details["art"].get("poster"):
                        thumb = details["art"]["poster"]
                    # use google images as last-resort fallback for thumbs - if enabled
                    elif self._mutils.addon.getSetting(
                            "pvr_art_google") == "true":
                        if manual_select:
                            google_title = searchtitle
                        else:
                            google_title = '%s %s' % (
                                searchtitle, channel.lower().split(" hd")[0])
                        thumb = self._mutils.google.search_image(
                            google_title, manual_select)
                    if thumb:
                        details["thumbnail"] = thumb
                        details["art"]["thumb"] = thumb
                    # extrafanart
                    if details["art"].get("fanarts"):
                        for count, item in enumerate(
                                details["art"]["fanarts"]):
                            details["art"]["fanart.%s" % count] = item
                        if not details["art"].get("extrafanart") and len(
                                details["art"]["fanarts"]) > 1:
                            details["art"]["extrafanart"] = "plugin://script.skin.helper.service/"\
                                "?action=extrafanart&fanarts=%s" % quote_plus(repr(details["art"]["fanarts"]))

                    # download artwork to custom folder
                    if self._mutils.addon.getSetting(
                            "pvr_art_download") == "true":
                        details["art"] = download_artwork(
                            self.get_custom_path(searchtitle, title),
                            details["art"])

            log_msg("pvrart lookup for title: %s - final result: %s" %
                    (searchtitle, details))

        # always store result in cache
        # manual lookups should not expire too often
        if manual_select:
            self._mutils.cache.set(cache_str,
                                   details,
                                   expiration=timedelta(days=365))
        else:
            self._mutils.cache.set(cache_str,
                                   details,
                                   expiration=timedelta(days=365))
        return details
Beispiel #51
0
def rebuild_table(name=''):
    global db
    log_msg('rebuilding table: name=' + str(name))
    day = db.get_min_full_day()
    db.summarize_data(name, day, compare='>=')
    log_msg('rebuilding done')
 def lookup_tvdb(self,
                 searchtitle,
                 channel,
                 manual_select=False,
                 tempmanualselect=False):
     """helper to select a match on tvdb"""
     tvdb_match = None
     searchtitle = searchtitle.lower()
     tvdb_result = self._mutils.thetvdb.search_series(searchtitle, True)
     searchchannel = channel.lower().split("hd")[0].replace(" ", "")
     if " FHD" in channel:
         searchchannel = channel.lower().split("fhd")[0].replace(" ", "")
     if " HD" in channel:
         searchchannel = channel.lower().split("hd")[0].replace(" ", "")
     if " SD" in channel:
         searchchannel = channel.lower().split("sd")[0].replace(" ", "")
     match_results = []
     if tvdb_result:
         for item in tvdb_result:
             item["score"] = 0
             if not item["seriesName"]:
                 continue  # seriesname can be None in some conditions
             itemtitle = item["seriesName"].lower()
             if not item["network"]:
                 continue  # network can be None in some conditions
             network = item["network"].lower().replace(" ", "")
             # high score if channel name matches
             if network in searchchannel or searchchannel in network:
                 item["score"] += 800
             # exact match on title - very high score
             if searchtitle == itemtitle:
                 item["score"] += 1000
             # match title by replacing some characters
             if re.sub('\*|,|.\"|\'| |:|;', '',
                       searchtitle) == re.sub('\*|,|.\"|\'| |:|;', '',
                                              itemtitle):
                 item["score"] += 750
             # add SequenceMatcher score to the results
             stringmatchscore = SM(None, searchtitle, itemtitle).ratio()
             if stringmatchscore > 0.7:
                 item["score"] += stringmatchscore * 500
             # prefer items with native language as we've searched with localized info enabled
             try:
                 if item["overview"]:
                     item["score"] += 250
             except KeyError:
                 log_msg(
                     "pvrartwork.py - Overview Key Error in lookup_tvb: %s"
                     % searchchannel)
             # prefer items with artwork
             if item["banner"]:
                 item["score"] += 1
             if item["score"] > 500 or manual_select:
                 match_results.append(item)
         # sort our new list by score
         match_results = sorted(match_results,
                                key=itemgetter("score"),
                                reverse=True)
         # original code:  if match_results and manual_select:. part of "auto refresh" fix.
         if match_results and manual_select and tempmanualselect:
             # show selectdialog to manually select the item
             listitems = []
             for item in match_results:
                 thumb = "http://thetvdb.com%s" % item["poster"] if item[
                     "poster"] else ""
                 try:
                     listitem = xbmcgui.ListItem(label=item["seriesName"],
                                                 label2=item["overview"])
                 except KeyError:
                     listitem = xbmcgui.ListItem(label=item["seriesName"])
                     log_msg(
                         "pvrartwork.py - Overview Key Error in lookup_tvb: %s"
                         % searchchannel)
                 listitem.setArt({'icon': thumb})
                 listitems.append(listitem)
             dialog = DialogSelect("DialogSelect.xml",
                                   "",
                                   listing=listitems,
                                   window_title="%s - TVDB" %
                                   xbmc.getLocalizedString(283))
             dialog.doModal()
             selected_item = dialog.result
             del dialog
             if selected_item != -1:
                 tvdb_match = match_results[selected_item]["id"]
             else:
                 match_results = []
         if not tvdb_match and match_results:
             # just grab the first item as best match
             tvdb_match = match_results[0]["id"]
     return tvdb_match
Beispiel #53
0
 def stop(self):
     '''called when the thread has to stop working'''
     log_msg("ListItemMonitor - stop called")
     self.exit = True
     self.event.set()
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), "resources", "lib"))

from main_service import MainService
from httpproxy import ProxyRunner
from utils import log_msg
import xbmc

kodimonitor = xbmc.Monitor()

# start the webservice (which hosts our silenced audio tracks)
proxy_runner = ProxyRunner(host='127.0.0.1', allow_ranges=True)
proxy_runner.start()
webport = proxy_runner.get_port()
log_msg('started webproxy at port {0}'.format(webport))

# run the main background service
main = MainService(kodimonitor=kodimonitor, webport=webport)
main.start()

# keep thread alive and send signal when we need to exit
while not kodimonitor.waitForAbort(10):
    pass

# stop requested
log_msg("Abort requested !", xbmc.LOGNOTICE)
main.stop()
proxy_runner.stop()
log_msg("Stopped", xbmc.LOGNOTICE)
Beispiel #55
0
 def close(self):
     '''Cleanup Kodi Cpython instances'''
     self.metadatautils.close()
     del self.addon
     del self.win
     log_msg("MainModule exited")
Beispiel #56
0
    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"),
                    "progress": item.get('progresspercentage')
                }
                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
Beispiel #57
0
 def switch_user(self, restart_daemon=False):
     '''called whenever we switch to a different user/credentials'''
     log_msg("login credentials changed")
     if self.renew_token():
         xbmc.executebuiltin("Container.Refresh")
Beispiel #58
0
    def get_artist_metadata(self,
                            artist,
                            album,
                            track,
                            ignore_cache=False,
                            flush_cache=False,
                            manual=False):
        """collect artist metadata for given artist"""
        details = {"art": {}}
        cache_str = "music_artwork.artist.%s" % artist.lower()
        # retrieve details from cache
        cache = self._mutils.cache.get(cache_str)
        if not cache and flush_cache:
            # nothing to do - just return empty results
            return details
        elif cache and flush_cache:
            # only update kodi metadata for updated counts etc
            details = extend_dict(self.get_artist_kodi_metadata(artist), cache)
        elif cache and not ignore_cache:
            # we have a valid cache - return that
            details = cache
        elif cache and manual:
            # user wants to manually override the artwork in the cache
            details = self.manual_set_music_artwork(cache, "artist")
        else:
            # nothing in cache - start metadata retrieval
            log_msg(
                "get_artist_metadata --> artist: %s - album: %s - track: %s" %
                (artist, album, track))
            details["cachestr"] = cache_str
            local_path = ""
            local_path_custom = ""
            # get metadata from kodi db
            details = extend_dict(details,
                                  self.get_artist_kodi_metadata(artist))
            # get artwork from songlevel path
            if details.get("diskpath") and self._mutils.addon.getSetting(
                    "music_art_musicfolders") == "true":
                details["art"] = extend_dict(
                    details["art"],
                    self.lookup_artistart_in_folder(details["diskpath"]))
                local_path = details["diskpath"]
            # get artwork from custom folder
            custom_path = None
            if self._mutils.addon.getSetting("music_art_custom") == "true":
                if sys.version_info.major == 3:
                    custom_path = self._mutils.addon.getSetting(
                        "music_art_custom_path")
                else:
                    custom_path = self._mutils.addon.getSetting(
                        "music_art_custom_path").decode("utf-8")
                local_path_custom = self.get_customfolder_path(
                    custom_path, artist)
                log_msg("custom path on disk for artist: %s --> %s" %
                        (artist, local_path_custom))
                details["art"] = extend_dict(
                    details["art"],
                    self.lookup_artistart_in_folder(local_path_custom))
                details["customartpath"] = local_path_custom
            # lookup online metadata
            if self._mutils.addon.getSetting("music_art_scraper") == "true":
                if not album and not track:
                    album = details.get("ref_album")
                    track = details.get("ref_track")
                # prefer the musicbrainzid that is already in the kodi database - only perform lookup if missing
                mb_artistid = details.get(
                    "musicbrainzartistid",
                    self.get_mb_artist_id(artist, album, track))
                details["musicbrainzartistid"] = mb_artistid
                if mb_artistid:
                    # get artwork from fanarttv
                    if self._mutils.addon.getSetting(
                            "music_art_scraper_fatv") == "true":
                        details["art"] = extend_dict(
                            details["art"],
                            self._mutils.fanarttv.artist(mb_artistid))
                    # get metadata from theaudiodb
                    if self._mutils.addon.getSetting(
                            "music_art_scraper_adb") == "true":
                        details = extend_dict(details,
                                              self.audiodb.artist_info(artist))
                    # get metadata from lastfm
                    if self._mutils.addon.getSetting(
                            "music_art_scraper_lfm") == "true":
                        details = extend_dict(
                            details, self.lastfm.artist_info(mb_artistid))
                    # download artwork to music folder
                    if local_path and self._mutils.addon.getSetting(
                            "music_art_download") == "true":
                        details["art"] = download_artwork(
                            local_path, details["art"])
                    # download artwork to custom folder
                    if local_path_custom and self._mutils.addon.getSetting(
                            "music_art_download_custom") == "true":
                        details["art"] = download_artwork(
                            local_path_custom, details["art"])
                    # fix extrafanart
                    if details["art"].get("fanarts"):
                        for count, item in enumerate(
                                details["art"]["fanarts"]):
                            details["art"]["fanart.%s" % count] = item
                        if not details["art"].get("extrafanart") and len(
                                details["art"]["fanarts"]) > 1:
                            details["art"]["extrafanart"] = "plugin://script.skin.helper.service/"\
                                "?action=extrafanart&fanarts=%s" % quote_plus(repr(details["art"]["fanarts"]))
                    # multi-image path for all images for each arttype
                    for arttype in ["banners", "clearlogos", "thumbs"]:
                        art = details["art"].get(arttype, [])
                        if len(art) > 1:
                            # use the extrafanart plugin entry to display multi images
                            details["art"][arttype] = "plugin://script.skin.helper.service/"\
                                "?action=extrafanart&fanarts=%s" % quote_plus(repr(art))
        # set default details
        if not details.get("artist"):
            details["artist"] = artist
        if details["art"].get("thumb"):
            details["art"]["artistthumb"] = details["art"]["thumb"]

        # always store results in cache and return results
        self._mutils.cache.set(cache_str, details)
        return details
Beispiel #59
0
    def build_wallimages(self, win_prop, wall_images, art_type):
        '''build wall images with PIL module for the collection'''
        return_images = []
        if not SUPPORTS_PIL:
            log_msg(
                "Wall backgrounds disabled - PIL is not supported on this device!",
                xbmc.LOGWARNING)
            return []
        log_msg(
            "Building Wall background for %s - this might take a while..." %
            win_prop)
        if art_type == "thumb":
            # square images
            img_columns = 11
            img_rows = 7
            img_width = 260
            img_height = 260
        elif art_type == "poster":
            # poster images
            img_columns = 15
            img_rows = 5
            img_width = 128
            img_height = 216
        else:
            # landscaped images
            img_columns = 8
            img_rows = 8
            img_width = 240
            img_height = 135
        size = img_width, img_height

        # build the wall images
        images_required = img_columns * img_rows
        if wall_images:
            # duplicate images if we don't have enough

            while len(wall_images) < images_required:
                wall_images += wall_images

            for count in range(self.max_wallimages):
                if self.exit:
                    return []
                random.shuffle(wall_images)
                img_canvas = Image.new(
                    "RGBA", (img_width * img_columns, img_height * img_rows))
                img_count = 0
                for x in range(img_rows):
                    for y in range(img_columns):
                        file = xbmcvfs.File(wall_images[img_count])
                        try:
                            img_obj = io.BytesIO(bytearray(file.readBytes()))
                            img = Image.open(img_obj)
                            img = img.resize(size)
                            img_canvas.paste(img,
                                             (y * img_width, x * img_height))
                            del img
                        except Exception:
                            log_msg(
                                "Invalid image file found! --> %s" %
                                wall_images[img_count], xbmc.LOGWARNING)
                        finally:
                            file.close()
                            img_count += 1

                # save the files..
                out_file = "%s%s.%s.jpg" % (WALLS_PATH, win_prop, count)
                out_file = xbmc.translatePath(out_file).decode("utf-8")
                if xbmcvfs.exists(out_file):
                    xbmcvfs.delete(out_file)
                    xbmc.sleep(500)
                img_canvas.save(out_file, "JPEG")

                out_file_bw = "%s%s_BW.%s.jpg" % (WALLS_PATH, win_prop, count)
                out_file_bw = xbmc.translatePath(out_file_bw).decode("utf-8")
                if xbmcvfs.exists(out_file_bw):
                    xbmcvfs.delete(out_file_bw)
                    xbmc.sleep(500)
                img_canvas = img_canvas.convert("L")
                img_canvas.save(out_file_bw, "JPEG")
                del img_canvas
                # add our images to the dict
                return_images.append({"wall": out_file, "wallbw": out_file_bw})
        log_msg("Building Wall background %s DONE" % win_prop)
        return return_images
Beispiel #60
0
debug_flag = False
for o, a in opts:
    if o in ("-s", "--server-name"):
        server_name = a
    else:
        if o in ("-d", "--debug"):
            debug_flag = True
        else:
            if o in ("--remove-after"):
                remove_after = True
            else:
                assert False, "unhandled option"

server_log_id = "Node:" + server_name

utils.log_msg(" ".join([server_log_id, "Starting build-one"]), "INFO",
              config.print_to)

pyrax.set_setting("identity_type", "rackspace")
pyrax.set_setting("region", config.cloud_region)
try:
    pyrax.set_credentials(config.cloud_user,
                          config.cloud_api_key,
                          region=config.cloud_region)
except pyrax.exc.AuthenticationFailed:
    utils.log_msg(
        " ".join([server_log_id, "Pyrax auth failed using",
                  config.cloud_user]), "ERROR", config.print_to)

utils.log_msg(
    " ".join([server_log_id, "Authenticated using", config.cloud_user]),
    "INFO", config.print_to)