def GetDefaultCachePath(self): """ returns the default cache path for this channel""" # set the UZG path if AddonSettings.GetUzgCacheDuration() > 0: cachPath = AddonSettings.GetUzgCachePath() if cachPath: Logger.Trace("UZG Cache path resolved to: %s", cachPath) return cachPath cachePath = chn_class.Channel.GetDefaultCachePath(self) Logger.Trace("UZG Cache path resolved chn_class default: %s", cachePath) return cachePath
def __init__(self, pluginName, params, handle=0): """Initialises the plugin with given arguments.""" # some constants self.actionDownloadVideo = "downloadVideo".lower() # : Action used to download a video item self.actionFavourites = "favourites".lower() # : Action used to show favorites for a channel self.actionAllFavourites = "allfavourites".lower() # : Action used to show all favorites self.actionRemoveFavourite = "removefromfavourites".lower() # : Action used to remove items from favorites self.actionAddFavourite = "addtofavourites".lower() # : Action used to add items to favorites self.actionPlayVideo = "playvideo".lower() # : Action used to play a video item self.actionUpdateChannels = "updatechannels".lower() # : Action used to update channels self.actionListFolder = "listfolder".lower() # : Action used to list a folder self.actionListCategory = "listcategory" # : Action used to show the channels from a category self.actionConfigureChannel = "configurechannel" # : Action used to configure a channel self.keywordPickle = "pickle".lower() # : Keyword used for the pickle item self.keywordAction = "action".lower() # : Keyword used for the action item self.keywordChannel = "channel".lower() # : Keyword used for the channel self.keywordChannelCode = "channelcode".lower() # : Keyword used for the channelcode self.keywordCategory = "category" # : Keyword used for the category self.keywordRandomLive = "rnd" # : Keyword used for randomizing live items self.pluginName = pluginName self.handle = int(handle) # channel objects self.channelObject = None self.channelFile = "" self.channelCode = None self.contentType = "episodes" self.methodContainer = dict() # : storage for the inspect.getmembers(channel) method. Improves performance # determine the query parameters self.params = self.__GetParameters(params) Logger.Info("*********** Starting %s add-on version %s ***********", Config.appName, Config.version) Logger.Debug("Plugin Params: %s (%s) [handle=%s, name=%s, query=%s]", self.params, len(self.params), self.handle, self.pluginName, params) # are we in session? sessionActive = SessionHelper.IsSessionActive(Logger.Instance()) # fetch some environment settings envCtrl = envcontroller.EnvController(Logger.Instance()) # self.FavouritesEnabled = envCtrl.SQLiteEnabled() self.FavouritesEnabled = not envCtrl.IsPlatform(Environments.Xbox) if not sessionActive: # do add-on start stuff Logger.Info("Add-On start detected. Performing startup actions.") # print the folder structure envCtrl.DirectoryPrinter(Config, AddonSettings) # show notification XbmcWrapper.ShowNotification(None, LanguageHelper.GetLocalizedString(LanguageHelper.StartingAddonId) % ( Config.appName,), fallback=False, logger=Logger) # check for updates if envCtrl.IsPlatform(Environments.Xbox): Updater().AutoUpdate() # check if the repository is available envCtrl.IsInstallMethodValid(Config) # check for cache folder envCtrl.CacheCheck() # do some cache cleanup envCtrl.CacheCleanUp(Config.cacheDir, Config.cacheValidTime) envCtrl.CacheCleanUp(AddonSettings.GetUzgCachePath(), AddonSettings.GetUzgCacheDuration() * 24 * 3600, "xot.*") # create a session SessionHelper.CreateSession(Logger.Instance()) #=============================================================================== # Start the plugin version of progwindow #=============================================================================== if len(self.params) == 0: # Show initial start if not in a session # now show the list if AddonSettings.ShowCategories(): self.ShowCategories() else: self.ShowChannelList() #=============================================================================== # Start the plugin verion of the episode window #=============================================================================== else: try: # Determine what stage we are in. Check that there are more than 2 Parameters if len(self.params) > 1 and self.keywordChannel in self.params: # retrieve channel characteristics self.channelFile = os.path.splitext(self.params[self.keywordChannel])[0] self.channelCode = self.params[self.keywordChannelCode] Logger.Debug("Found Channel data in URL: channel='%s', code='%s'", self.channelFile, self.channelCode) # import the channel channelRegister = ChannelImporter.GetRegister() channel = channelRegister.GetSingleChannel(self.channelFile, self.channelCode) if channel is not None: self.channelObject = channel else: Logger.Critical("None or more than one channels were found, unable to continue.") return # init the channel as plugin self.channelObject.InitChannel() Logger.Info("Loaded: %s", self.channelObject.channelName) elif self.keywordCategory in self.params: # no channel needed. pass elif self.keywordAction in self.params and ( self.params[self.keywordAction] == self.actionAllFavourites or self.params[self.keywordAction] == self.actionRemoveFavourite): # no channel needed for these favourites actions. pass else: Logger.Critical("Error determining Plugin action") return #=============================================================================== # See what needs to be done. #=============================================================================== if self.keywordAction not in self.params: Logger.Critical("Action parameters missing from request. Parameters=%s", self.params) return if self.params[self.keywordAction] == self.actionListCategory: self.ShowChannelList(self.params[self.keywordCategory]) elif self.params[self.keywordAction] == self.actionConfigureChannel: self.__ConfigureChannel(self.channelObject) elif self.params[self.keywordAction] == self.actionFavourites: # we should show the favourites self.ShowFavourites(self.channelObject) elif self.params[self.keywordAction] == self.actionAllFavourites: if self.channelObject is not None: Logger.Warning("We have a self.channelObject with self.actionAllFavourites") self.ShowFavourites(None) elif self.params[self.keywordAction] == self.actionRemoveFavourite: self.RemoveFavourite() elif self.params[self.keywordAction] == self.actionAddFavourite: self.AddFavourite() elif self.params[self.keywordAction] == self.actionListFolder: # channelName and URL is present, Parse the folder self.ProcessFolderList() elif self.params[self.keywordAction] == self.actionPlayVideo: self.PlayVideoItem() elif not self.params[self.keywordAction] == "": self.OnActionFromContextMenu(self.params[self.keywordAction]) else: Logger.Warning("Number of parameters (%s) or parameter (%s) values not implemented", len(self.params), self.params) except: Logger.Critical("Error parsing for add-on", exc_info=True) self.__FetchTextures() return
def __UpdateVideoItem(self, item, episodeId): """Updates an existing MediaItem with more data. Arguments: item : MediaItem - the MediaItem that needs to be updated episodeId : String - The episodeId, e.g.: VARA_xxxxxx Returns: The original item with more data added to it's properties. Used to update none complete MediaItems (self.complete = False). This could include opening the item's URL to fetch more data and then process that data or retrieve it's real media-URL. The method should at least: * cache the thumbnail to disk (use self.noImage if no thumb is available). * set at least one MediaItemPart with a single MediaStream. * set self.complete = True. if the returned item does not have a MediaItemPart then the self.complete flag will automatically be set back to False. """ Logger.Trace("Using Generic UpdateVideoItem method") # get the subtitle subTitleUrl = "http://e.omroep.nl/tt888/%s" % (episodeId,) subTitlePath = subtitlehelper.SubtitleHelper.DownloadSubtitle(subTitleUrl, episodeId + ".srt", format='srt', proxy=self.proxy) # we need an hash code hashCode = NpoStream.GetNpoToken(self.proxy, Config.cacheDir) item.MediaItemParts = [] part = item.CreateNewEmptyMediaPart() part.Subtitle = subTitlePath # then we fetch alternative streams locations and start with the non-adapative ones streamsUrls = [] directStreamVideos = AddonSettings.GetUzgCacheDuration() == 0 streamSource = [ "http://ida.omroep.nl/odi/?prid=%s&puboptions=h264_bb,h264_sb,h264_std&adaptive=no&part=1&token=%s" % ( episodeId, hashCode,)] if directStreamVideos: # if we stream, then we first look for adaptive streams Logger.Debug("UZG is configured to streams, so also check for the adaptive streams") streamSource.insert(0, "http://ida.omroep.nl/odi/?prid=%s&puboptions=adaptive&adaptive=yes&part=1&token=%s" % ( episodeId, hashCode,)) else: Logger.Debug("UZG is configured to download. Not going to fetch the adaptive streams") # get the actual stream locations streams: for streamSourceUrl in streamSource: streamUrlData = UriHandler.Open(streamSourceUrl, proxy=self.proxy, noCache=True) streamJson = JsonHelper(streamUrlData, logger=Logger.Instance()) for url in streamJson.GetValue('streams'): Logger.Trace("Going to look for streams in: %s", url) streamsUrls.append(url) # should we cache before playback if not directStreamVideos: part.CanStream = False # now we should now actually go and fetch urls for url in streamsUrls: data = UriHandler.Open(url, proxy=self.proxy) jsonData = JsonHelper(data, logger=Logger.Instance()) # check for errors streamData = jsonData.GetValue() if "errorstring" in streamData: Logger.Warning("Found error response: %s", streamData["errorstring"]) continue # either do m3u8 or hls if "m3u8" in url.lower(): Logger.Trace("Processing M3U8 Json: %s", url) m3u8url = jsonData.GetValue("url") if m3u8url is None: Logger.Warning("Could not find stream in: %s", m3u8url) continue Logger.Trace("Processing M3U8 Streams: %s", m3u8url) for s, b in M3u8.GetStreamsFromM3u8(m3u8url, self.proxy): item.complete = True part.AppendMediaStream(s, b) # if we found an adaptive m3u8, we take that one as it's better Logger.Info("Found M3u8 streams and using those. Stop looking further for non-adaptive ones.") break else: Logger.Trace("Processing HLS: %s", url) if "h264_bb" in url: bitrate = 500 elif "h264_sb" in url: bitrate = 220 elif "h264_std" in url: bitrate = 1000 else: bitrate = None protocol = jsonData.GetValue('protocol') if protocol: url = "%s://%s%s" % (protocol, jsonData.GetValue('server'), jsonData.GetValue('path')) part.AppendMediaStream(url, bitrate=bitrate) else: Logger.Warning("Found UZG Stream without a protocol. Probably a expired page.") if not item.HasMediaItemParts(): Logger.Warning("Apparently no streams were present in the normal places. Trying streams in metadata") # fetch the meta data to get more streams metaUrl = "http://e.omroep.nl/metadata/%s" % (episodeId,) metaData = UriHandler.Open(metaUrl, proxy=self.proxy) metaJson = JsonHelper(metaData, logger=Logger.Instance()) # sometimes there are streams direct in the meta data file directStreams = metaJson.GetValue("streams", fallback=[]) for stream in directStreams: quality = stream.get("kwaliteit", 0) if quality == 1: bitrate = 180 elif quality == 2: bitrate = 1000 elif quality == 3: bitrate = 1500 else: bitrate = 0 if "formaat" in stream and stream["formaat"] == "h264": bitrate += 1 part.AppendMediaStream(stream["url"], bitrate) # now we can get extra info from the data item.description = metaJson.GetValue("info") item.title = metaJson.GetValue('aflevering_titel') station = metaJson.GetValue('streamSense', 'station') if station is None: item.icon = self.icon elif station.startswith('nederland_1'): item.icon = self.GetImageLocation("1large.png") elif station.startswith('nederland_2'): item.icon = self.GetImageLocation("2large.png") elif station.startswith('nederland_3'): item.icon = self.GetImageLocation("3large.png") Logger.Trace("Icon for station %s = %s", station, item.icon) # <image size="380x285" ratio="4:3">http://u.omroep.nl/n/a/2010-12/380x285_boerzoektvrouw_yvon.png</image> thumbUrls = metaJson.GetValue('images') # , {"size": "380x285"}, {"ratio":"4:3"}) Logger.Trace(thumbUrls) if thumbUrls: thumbUrl = thumbUrls[-1]['url'] if "http" not in thumbUrl: thumbUrl = "http://u.omroep.nl/n/a/%s" % (thumbUrl,) else: thumbUrl = self.noImage item.thumb = thumbUrl item.complete = True return item