def CreatePageItem(self, resultSet): """Creates a MediaItem of type 'page' using the resultSet from the regex. Arguments: resultSet : tuple(string) - the resultSet of the self.pageNavigationRegex Returns: A new MediaItem of type 'page' This method creates a new MediaItem from the Regular Expression or Json results <resultSet>. The method should be implemented by derived classes and are specific to the channel. """ Logger.Debug("Starting CreatePageItem") # current page? baseUrl, page = self.parentItem.url.rsplit("=", 1) page = int(page) maxPages = resultSet.get("total_pages", 0) Logger.Trace("Current Page: %d of %d (%s)", page, maxPages, baseUrl) if page + 1 >= maxPages: return None title = LanguageHelper.GetLocalizedString(LanguageHelper.MorePages) url = "%s=%s" % (baseUrl, page + 1) item = mediaitem.MediaItem(title, url) item.fanart = self.parentItem.fanart item.thumb = self.parentItem.thumb return item
def CreateVideoItem(self, resultSet): """Creates a MediaItem of type 'video' using the resultSet from the regex. Arguments: resultSet : tuple (string) - the resultSet of the self.videoItemRegex Returns: A new MediaItem of type 'video' or 'audio' (despite the method's name) This method creates a new MediaItem from the Regular Expression or Json results <resultSet>. The method should be implemented by derived classes and are specific to the channel. If the item is completely processed an no further data needs to be fetched the self.complete property should be set to True. If not set to True, the self.UpdateVideoItem method is called if the item is focussed or selected for playback. """ Logger.Trace(resultSet) item = mediaitem.MediaItem(resultSet[0], resultSet[1]) item.thumb = self.noImage item.icon = self.icon item.type = 'video' item.thumb = resultSet[2] item.complete = False return item
def UpdateVideoItem(self, item): data = UriHandler.Open(item.url, proxy=self.proxy, additionalHeaders=item.HttpHeaders) mediaRegex = 'data-media="([^"]+)"' mediaInfo = Regexer.DoRegex(mediaRegex, data)[0] mediaInfo = HtmlEntityHelper.ConvertHTMLEntities(mediaInfo) mediaInfo = JsonHelper(mediaInfo) Logger.Trace(mediaInfo) # sources part = item.CreateNewEmptyMediaPart() # high, web, mobile, url mediaSources = mediaInfo.json.get("sources", {}) for quality in mediaSources: url = mediaSources[quality] if quality == "high": bitrate = 2000 elif quality == "web": bitrate = 800 elif quality == "mobile": bitrate = 400 else: bitrate = 0 part.AppendMediaStream(url, bitrate) # geoLocRestriction item.isGeoLocked = not mediaInfo.GetValue("geoLocRestriction", fallback="world") == "world" item.complete = True return item
def GetChannel(self): """ Instantiates a channel from a ChannelInfo object """ Logger.Trace("Importing module %s from path %s", self.moduleName, self.path) sys.path.append(self.path) exec ("import %s" % (self.moduleName,)) channelCommand = '%s.Channel(self)' % (self.moduleName,) try: Logger.Trace("Running command: %s", channelCommand) channel = eval(channelCommand) except: Logger.Error("Cannot Create channel for %s", self, exc_info=True) return None return channel
def Validate(test, raiseOnMissing=False, logger=None): """ Validates if in instance has all properties after depickling. The __class__ of the 'test' should implement a self.__dir__(self) that returns the required attributes. @param test: Item to test @param raiseOnMissing: If True an error will be raised on failure @param logger Pass a loger in @return None if no error, or an error message if an error occurred. """ if logger is not None: Logger.Trace("Testing: %s", test.__dir__()) # the default dir() does not work for Android at the moment. for attribute in test.__dir__(): if logger is not None: logger.Trace("Testing: %s", attribute) # manage private attributes if attribute.startswith("__"): attribute = "_%s%s" % (test.__class__.__name__, attribute) if not hasattr(test, attribute): error = "Attribute Missing: %s" % attribute if logger is not None: logger.Warning(error) if raiseOnMissing: raise Exception(error) return error # We are good return None
def PickleMediaItem(item): """Serialises a mediaitem Arguments: item : MediaItem - the item that should be serialized Returns: A pickled and base64 encoded serialization of the <item>. """ if item.guid in Pickler.__PickleContainer: Logger.Trace("Pickle Container cache hit") return Pickler.__PickleContainer[item.guid] pickleString = pickle.dumps(item, protocol=pickle.HIGHEST_PROTOCOL) # Logger.Trace("Pickle: PickleString: %s", pickleString) hexString = base64.b64encode(pickleString) # if not unquoted, we must replace the \n's for the URL hexString = reduce( lambda x, y: x.replace(y, Pickler.__Base64CharsEncode[y]), Pickler.__Base64CharsEncode.keys(), hexString) # Logger.Trace("Pickle: HexString: %s", hexString) Pickler.__PickleContainer[item.guid] = hexString return hexString
def ParseTvList(self, data): """Parses the mainlist of the channel and returns a list of MediaItems This method creates a list of MediaItems that represent all the different programs that are available in the online source. The list is used to fill the ProgWindow. Keyword parameters: returnData : [opt] boolean - If set to true, it will return the retrieved data as well Returns a list of MediaItems that were retrieved. """ items = [] # read the regional ones # noinspection PyUnresolvedReferences dataPath = os.path.abspath(os.path.join(__file__, '..', 'data')) Logger.Info("TV streams located at: %s", dataPath) regionals = os.listdir(dataPath) Logger.Trace(regionals) for regional in regionals: path = os.path.join(dataPath, regional) if not os.path.isdir(path): continue item = mediaitem.MediaItem(regional, path) item.complete = True items.append(item) pass # add the National ones self.mainListItems = items return data, items
def CreateEpisodeItem(self, resultSet): """Creates a new MediaItem for an episode Arguments: resultSet : list[string] - the resultSet of the self.episodeItemRegex Returns: A new MediaItem of type 'folder' This method creates a new MediaItem from the Regular Expression or Json results <resultSet>. The method should be implemented by derived classes and are specific to the channel. """ Logger.Trace(resultSet) if resultSet[0]: title = resultSet[0] url = resultSet[1] else: title = resultSet[2] url = resultSet[3] item = mediaitem.MediaItem(title, url) item.thumb = self.noImage item.icon = self.icon return item
def CreateVideoItem(self, resultSet): """ Call base method and then do some more stuff """ item = chn_class.Channel.CreateVideoItem(self, resultSet) # set the POW id item.url = resultSet["url"] item.isPaid = "premium" in resultSet["class"] # TODO: set date try: dateTime = resultSet["date2"].strip().replace(" ", " ").split(" ") Logger.Trace(dateTime) if dateTime[0].lower() == "gisteren": dateTime = datetime.datetime.now() + datetime.timedelta(days=-1) item.SetDate(dateTime.year, dateTime.month, dateTime.day) elif dateTime[0].lower() == "vandaag": dateTime = datetime.datetime.now() item.SetDate(dateTime.year, dateTime.month, dateTime.day) elif ":" in dateTime[-1]: if dateTime[-2].isalpha(): year = datetime.datetime.now().year dateTime.insert(-1, year) year = int(dateTime[-2]) month = DateHelper.GetMonthFromName(dateTime[-3], language="nl") day = int(dateTime[-4]) stamp = datetime.datetime(year, month, day) if stamp > datetime.datetime.now(): year -= 1 item.SetDate(year, month, day) else: # there is an actual date present if dateTime[0].isalpha(): # first part is ma/di/wo/do/vr/za/zo dateTime.pop(0) # translate the month month = DateHelper.GetMonthFromName(dateTime[1], language="nl") # if the year is missing, let's assume it is this year if ":" in dateTime[2]: dateTime[2] = datetime.datetime.now().year # in the past of future, if future, we need to substract stamp = datetime.datetime(dateTime[2], month, int(dateTime[0])) if stamp > datetime.datetime.now(): dateTime[2] -= 1 item.SetDate(dateTime[2], month, dateTime[0]) except: Logger.Warning("Cannot set date from label: %s", resultSet["date2"], exc_info=True) # 2016-07-05T00:00:00Z dateValue = resultSet.get("date", None) if dateValue: timeStamp = DateHelper.GetDateFromString(dateValue, "%Y-%m-%dT%H:%M:%SZ") item.SetDate(*timeStamp[0:6]) else: Logger.Warning("Cannot set date from 'data-from': %s", resultSet["date"], exc_info=True) return item
def UpdateVideoItem(self, item): """Updates an existing MediaItem with more data. Arguments: item : MediaItem - the MediaItem that needs to be updated 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.Debug('Starting UpdateVideoItem for %s (%s)', item.name, self.channelName) data = UriHandler.Open(item.url, proxy=self.proxy) # get the playlist GUID playlistGuids = Regexer.DoRegex("<div[^>]+data-playlist-id='([^']+)'[^>]+></div>", data) if not playlistGuids: # let's try the alternative then (for the new channels) playlistGuids = Regexer.DoRegex('local_playlist[", -]+([a-f0-9]{20})"', data) playlistGuid = playlistGuids[0] # Logger.Trace(playlistGuid) # now we can get the playlist meta data # http://api.mtvnn.com/v2/mrss.xml?uri=mgid%3Asensei%3Avideo%3Amtvnn.com%3Alocal_playlist-39ce0652b0b3c09258d9-SE-uma_site--ad_site-nickelodeon.se-ad_site_referer-video/9764-barjakt&adSite=nickelodeon.se&umaSite={umaSite}&show_images=true&url=http%3A//www.nickelodeon.se/video/9764-barjakt # but this seems to work. # http://api.mtvnn.com/v2/mrss.xml?uri=mgid%3Asensei%3Avideo%3Amtvnn.com%3Alocal_playlist-39ce0652b0b3c09258d9 playListUrl = "http://api.mtvnn.com/v2/mrss.xml?uri=mgid%3Asensei%3Avideo%3Amtvnn.com%3Alocal_playlist-" + playlistGuid playListData = UriHandler.Open(playListUrl, proxy=self.proxy) # now get the real RTMP data rtmpMetaData = Regexer.DoRegex("<media:content [^>]+url='([^']+)'", playListData)[0] rtmpData = UriHandler.Open(rtmpMetaData, proxy=self.proxy) rtmpUrls = Regexer.DoRegex('<rendition[^>]+bitrate="(\d+)"[^>]*>\W+<src>([^<]+ondemand)/([^<]+)</src>', rtmpData) part = item.CreateNewEmptyMediaPart() for rtmpUrl in rtmpUrls: url = "%s/%s" % (rtmpUrl[1], rtmpUrl[2]) bitrate = rtmpUrl[0] # convertedUrl = url.replace("ondemand/","ondemand?slist=") convertedUrl = self.GetVerifiableVideoUrl(url) part.AppendMediaStream(convertedUrl, bitrate) item.complete = True Logger.Trace("Media url: %s", item) return item
def GetStreamsFromF4m(url, proxy=None, headers=None): """ Parsers standard F4m lists and returns a list of tuples with streams and bitrates that can be used by other methods @type headers: dict - Possible HTTP Headers @param proxy: Proxy - The proxy to use for opening @param url: String - The url to download Can be used like this: part = item.CreateNewEmptyMediaPart() for s, b in F4m.GetStreamsFromF4m(url, self.proxy): item.complete = True # s = self.GetVerifiableVideoUrl(s) part.AppendMediaStream(s, b) """ streams = [] data = UriHandler.Open(url, proxy, additionalHeaders=headers) Logger.Trace(data) Logger.Debug("Processing F4M Streams: %s", url) needle = '<media href="([^"]+)"[^>]*bitrate="([^"]+)"' needles = Regexer.DoRegex(needle, data) baseUrlLogged = False baseUrl = url[:url.rindex("/")] for n in needles: # see if we need to append a server path Logger.Trace(n) if "://" not in n[0]: if not baseUrlLogged: Logger.Trace("Using baseUrl %s for F4M", baseUrl) baseUrlLogged = True stream = "%s/%s" % (baseUrl, n[0]) else: if not baseUrlLogged: Logger.Trace("Full url found in F4M") baseUrlLogged = True stream = n[0] bitrate = int(n[1]) streams.append((stream, bitrate)) Logger.Debug("Found %s substreams in F4M", len(streams)) return streams
def UpdateVideoItem(self, item): """Updates an existing MediaItem with more data. Arguments: item : MediaItem - the MediaItem that needs to be updated 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.Debug('Starting UpdateVideoItem for %s (%s)', item.name, self.channelName) metaData = UriHandler.Open(item.url, proxy=self.proxy, referer=self.baseUrl) meta = JsonHelper(metaData) streamParts = meta.GetValue("feed", "items") for streamPart in streamParts: streamUrl = streamPart["group"]["content"] # streamUrl = streamUrl.replace("{device}", "ipad") streamUrl = streamUrl.replace("{device}", "html5") streamUrl = "%s&format=json" % (streamUrl, ) streamData = UriHandler.Open(streamUrl, proxy=self.proxy) stream = JsonHelper(streamData) # subUrls = stream.GetValue("package", "video", "item", 0, "transcript", 0, "typographic") part = item.CreateNewEmptyMediaPart() # m3u8Url = stream.GetValue("package", "video", "item", 0, "rendition", 0, "src") # for s, b in M3u8.GetStreamsFromM3u8(m3u8Url, self.proxy): # item.complete = True # part.AppendMediaStream(s, b) rtmpDatas = stream.GetValue("package", "video", "item", 0, "rendition") for rtmpData in rtmpDatas: rtmpUrl = rtmpData["src"] rtmpUrl = rtmpUrl.replace("rtmpe://", "rtmp://") bitrate = rtmpData["bitrate"] part.AppendMediaStream(rtmpUrl, bitrate) item.complete = True Logger.Trace("Media url: %s", item) return item
def StievieCreateEpgItems(self, epg): Logger.Trace(epg) Logger.Debug("Processing EPG for channel %s", epg["id"]) items = [] summerTime = time.localtime().tm_isdst now = datetime.datetime.now() for resultSet in epg["items"]: # if not resultSet["parentSeriesOID"]: # continue # Does not always work # videoId = resultSet["epgId"].replace("-", "_") # url = "https://vod.medialaan.io/vod/v2/videos/%s_Stievie_free" % (videoId, ) videoId = resultSet["programOID"] url = "https://vod.medialaan.io/vod/v2/videos?episodeIds=%s&limit=10&offset=0&sort=broadcastDate&sortDirection=asc" % (videoId, ) title = resultSet["title"] if resultSet["episode"] and resultSet["season"]: title = "%s - s%02de%02d" % (title, resultSet["season"], resultSet["episode"]) if "startTime" in resultSet and resultSet["startTime"]: dateTime = resultSet["startTime"] dateValue = DateHelper.GetDateFromString(dateTime, dateFormat="%Y-%m-%dT%H:%M:%S.000Z") # Convert to Belgium posix time stamp dateValue2 = time.mktime(dateValue) + (1 + summerTime) * 60 * 60 # Conver the posix to a time stamp startTime = DateHelper.GetDateFromPosix(dateValue2) title = "%02d:%02d - %s" % (startTime.hour, startTime.minute, title) # Check for items in their black-out period if "blackout" in resultSet and resultSet["blackout"]["enabled"]: blackoutDuration = resultSet["blackout"]["duration"] blackoutStart = startTime + datetime.timedelta(seconds=blackoutDuration) if blackoutStart < now: Logger.Debug("Found item in Black-out period: %s (started at %s)", title, blackoutStart) continue # else: # startTime = self.parentItem.metaData["airDate"] item = MediaItem(title, url) item.type = "video" item.isGeoLocked = resultSet["geoblock"] item.description = resultSet["shortDescription"] # item.SetDate(startTime.year, startTime.month, startTime.day) if "images" in resultSet and resultSet["images"] and "styles" in resultSet["images"][0]: images = resultSet["images"][0]["styles"] # if "1520x855" in images: # item.fanart = images["1520x855"] if "400x225" in images: item.thumb = images["400x225"] items.append(item) return items
def CreateShowItem(self, resultSet): Logger.Trace(resultSet) if resultSet["targetUrl"].startswith("//"): resultSet["url"] = "https:%(targetUrl)s" % resultSet else: resultSet["url"] = resultSet["targetUrl"] resultSet["thumburl"] = resultSet["thumbnail"] return chn_class.Channel.CreateEpisodeItem(self, resultSet)
def CreateVideoItemNew(self, resultSet): """Creates a MediaItem of type 'video' using the resultSet from the regex. Arguments: resultSet : tuple (string) - the resultSet of the self.videoItemRegex Returns: A new MediaItem of type 'video' or 'audio' (despite the method's name) This method creates a new MediaItem from the Regular Expression or Json results <resultSet>. The method should be implemented by derived classes and are specific to the channel. If the item is completely processed an no further data needs to be fetched the self.complete property should be set to True. If not set to True, the self.UpdateVideoItem method is called if the item is focussed or selected for playback. """ Logger.Trace(resultSet) videos = self.__GetNestedValue(resultSet, "Assets", "Video") if not videos: Logger.Warning("No video information found.") return None videoInfos = filter(lambda vi: vi["fullLength"], videos) if len(videoInfos) > 0: videoInfo = videoInfos[0] else: Logger.Warning("No full length video found.") return None videoId = videoInfo["id"] url = "http://il.srgssr.ch/integrationlayer/1.0/ue/srf/video/play/%s.json" % ( videoId, ) item = mediaitem.MediaItem(resultSet["title"], url) item.type = "video" item.thumb = self.__GetNestedValue(videoInfo, "Image", "ImageRepresentations", "ImageRepresentation", 0, "url") item.description = self.__GetNestedValue(videoInfo, "AssetMetadatas", "AssetMetadata", 0, "description") dateValue = str(resultSet["publishedDate"]) dateValue = dateValue[0:-6] dateTime = DateHelper.GetDateFromString( dateValue, "%Y-%m-%dT%H:%M:%S") # 2015-01-20T22:17:59" item.SetDate(*dateTime[0:6]) item.icon = self.icon item.httpHeaders = self.httpHeaders item.complete = False return item
def CreateVideoItem(self, resultSet): """Creates a MediaItem of type 'video' using the resultSet from the regex. Arguments: resultSet : tuple (string) - the resultSet of the self.videoItemRegex Returns: A new MediaItem of type 'video' or 'audio' (despite the method's name) This method creates a new MediaItem from the Regular Expression or Json results <resultSet>. The method should be implemented by derived classes and are specific to the channel. If the item is completely processed an no further data needs to be fetched the self.complete property should be set to True. If not set to True, the self.UpdateVideoItem method is called if the item is focussed or selected for playback. """ Logger.Trace(resultSet) isSerieTitle = resultSet["seriesTitle"] if not isSerieTitle: return None if resultSet["mediaType"] == "game": return None elif resultSet["mediaType"] == "episode": title = "%(title)s (Episode)" % resultSet else: title = resultSet["title"] videoId = resultSet["id"] url = "http://media.mtvnservices.com/pmt/e1/access/index.html?uri=mgid:%s:%s&configtype=edge" \ % (self.__mgid, videoId, ) item = mediaitem.MediaItem(title, url) item.description = resultSet.get("description", None) item.type = "video" item.icon = self.icon item.fanart = self.fanart item.HttpHeaders = self.httpHeaders item.complete = False if "datePosted" in resultSet: date = DateHelper.GetDateFromPosix( float(resultSet["datePosted"]["unixOffset"]) / 1000) item.SetDate(date.year, date.month, date.day, date.hour, date.minute, date.second) if "images" in resultSet: images = resultSet.get("images", {}) thumbs = images.get("thumbnail", {}) item.thumb = thumbs.get("r16-9", self.noImage) return item
def UpdateUserAgent(): """ Creates a user agent for this instance of XOT this is a very slow action on lower end systems (ATV and rPi) so we minimize the number of runs @return: Nothing Actual: User-Agent: Kodi/16.1 (Windows NT 10.0; WOW64) App_Bitness/32 Version/16.1-Git:20160424-c327c53 Retro: User-Agent: Kodi/16.1 Git:20160424-c327c53 (Windows 10;AMD64; http://kodi.tv) Firefox: User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0 """ # there are slow imports, so only do them here import platform from envcontroller import EnvController # noinspection PyNoneFunctionAssignment version = AddonSettings.GetKodiVersion() Logger.Debug("Found Kodi version: %s", version) git = "" try: # noinspection PyNoneFunctionAssignment if "Git:" in version: version, git = version.split("Git:", 1) version = version.rstrip() # The platform.<method> are not working on rPi and IOS # kernel = platform.architecture() # Logger.Trace(kernel) # machine = platform.machine() # Logger.Trace(machine) uname = platform.uname() Logger.Trace(uname) if git: userAgent = "Kodi/%s (%s %s; %s; http://kodi.tv) Version/%s-Git:%s" % ( version, uname[0], uname[2], uname[4], version, git) else: userAgent = "Kodi/%s (%s %s; %s; http://kodi.tv) Version/%s" % ( version, uname[0], uname[2], uname[4], version) except: Logger.Warning("Error setting user agent", exc_info=True) currentEnv = EnvController.GetPlatform(True) # Kodi/14.2 (Windows NT 6.1; WOW64) App_Bitness/32 Version/14.2-Git:20150326-7cc53a9 userAgent = "Kodi/%s (%s; <unknown>; http://kodi.tv)" % ( version, currentEnv) # now we store it AddonSettings.SetSetting(AddonSettings.__USER_AGENT_SETTING, userAgent) AddonSettings.__UserAgent = userAgent Logger.Info("User agent set to: %s", userAgent) return
def CreateVideoItem_old(self, resultSet): """Creates a MediaItem of type 'video' using the resultSet from the regex. Arguments: resultSet : tuple (string) - the resultSet of the self.videoItemRegex Returns: A new MediaItem of type 'video' or 'audio' (despite the method's name) This method creates a new MediaItem from the Regular Expression or Json results <resultSet>. The method should be implemented by derived classes and are specific to the channel. If the item is completely processed an no further data needs to be fetched the self.complete property should be set to True. If not set to True, the self.UpdateVideoItem method is called if the item is focussed or selected for playback. """ Logger.Trace(resultSet) thumbUrl = resultSet[1] url = "%s%s" % (self.baseUrl, resultSet[2]) title = resultSet[6] item = mediaitem.MediaItem(title, url) item.thumb = self.noImage if thumbUrl: item.thumb = thumbUrl item.icon = self.icon item.type = 'video' if resultSet[3]: # set date day = resultSet[3] month = resultSet[4] year = resultSet[5] Logger.Trace("%s-%s-%s", year, month, day) month = datehelper.DateHelper.GetMonthFromName(month, "nl", True) item.SetDate(year, month, day) item.complete = False return item
def UpdateVideoItem(self, item): """ Accepts an item. It returns an updated item. Usually retrieves the MediaURL and the Thumb! It should return a completed item. """ Logger.Debug('Starting UpdateVideoItem for %s (%s)', item.name, self.channelName) data = UriHandler.Open(item.url, proxy=self.proxy) javascriptUrls = Regexer.DoRegex( '<script type="text/javascript" src="(http://l1.bbvms.com/p/standaard/c/\d+.js)">', data) dataUrl = None for javascriptUrl in javascriptUrls: dataUrl = javascriptUrl if not dataUrl: return item data = UriHandler.Open(dataUrl, proxy=self.proxy) jsonData = Regexer.DoRegex( 'clipData\W*:([\w\W]{0,10000}?\}),"playerWidth', data) Logger.Trace(jsonData) json = JsonHelper(jsonData[0], logger=Logger.Instance()) Logger.Trace(json) streams = json.GetValue("assets") item.MediaItemParts = [] part = item.CreateNewEmptyMediaPart() for stream in streams: url = stream.get("src", None) if "://" not in url: url = "http://static.l1.nl/bbw%s" % (url, ) bitrate = stream.get("bandwidth", None) if url: part.AppendMediaStream(url, bitrate) if not item.thumb and json.GetValue("thumbnails"): url = json.GetValue("thumbnails")[0].get("src", None) if url and "http:/" not in url: url = "%s%s" % (self.baseUrl, url) item.thumb = url item.complete = True return item
def CreateEpisodeItemJson(self, resultSet): """Creates a MediaItem of type 'video' using the resultSet from the regex. Arguments: resultSet : tuple (string) - the resultSet of the self.videoItemRegex Returns: A new MediaItem of type 'video' or 'audio' (despite the method's name) This method creates a new MediaItem from the Regular Expression or Json results <resultSet>. The method should be implemented by derived classes and are specific to the channel. If the item is completely processed an no further data needs to be fetched the self.complete property should be set to True. If not set to True, the self.UpdateVideoItem method is called if the item is focussed or selected for playback. """ Logger.Trace(resultSet) # add { to make it valid Json again. if it would be in the regex it would # not find all items # data = JsonHelper("{%s" % (resultSet,)) # title localTitle = resultSet.get("local_title") originalTitle = resultSet.get("original_name") if localTitle == "" or localTitle is None: title = originalTitle elif originalTitle != localTitle: title = "%s (%s)" % (localTitle, originalTitle) else: title = localTitle # the URL serieId = resultSet["id"] url = "%sepisodes.json?per=2147483647&franchise_id=%s" % ( self.mainListUri[0:43], serieId) item = mediaitem.MediaItem(title, url) item.icon = self.icon item.complete = True # thumbs if "image" in resultSet and resultSet["image"] is not None: thumb = resultSet["image"]["riptide_image_id"] thumb = "http://images.mtvnn.com/%s/original" % (thumb, ) item.thumb = thumb # others item.description = resultSet["local_long_description"] # http://www.mtv.nl/shows/195-16-pregnant return item
def http_response(self, request, response): # @UnusedVariables Logger.Trace("Processing HTTP response for possible decompression") # Logger.Trace("%s\n%s", response.url, response.info()) oldResponse = response # do the decompression contentEncoding = response.headers.get("content-encoding") if contentEncoding: responseEncoding = contentEncoding data = response.read() try: if "gzip" in contentEncoding: Logger.Debug("Decompressing '%s' response", contentEncoding) # the GzipFileReader expect a StringIO object gzipStream = StringIO(data) fileStream = gzip.GzipFile(fileobj=gzipStream) responseEncoding = "none" elif "deflate" in contentEncoding: Logger.Debug("Decompressing '%s' response", contentEncoding) fileStream = StringIO(zlib.decompress(data)) responseEncoding = "none" elif contentEncoding == "none": Logger.Debug( "Nothing to decompress. Content-encoding: '%s'", contentEncoding) # we have already used the response.read() so we need to create # a new filestream with the original data in it. fileStream = StringIO(data) else: Logger.Warning("Unknown Content-Encoding: '%s'", contentEncoding) # we have already used the response.read() so we need to create # a new filestream with the original data in it. fileStream = StringIO(data) except: Logger.Error("Cannot Decompress this response", exc_info=True) # we have already used the response.read() so we need to create # a new filestream with the original data in it. fileStream = StringIO(data) response = urllib2.addinfourl(fileStream, oldResponse.headers, oldResponse.url, oldResponse.code) response.msg = oldResponse.msg # Update the content-encoding header response.headers["content-encoding"] = responseEncoding return response else: Logger.Debug("No Content-Encoding header found") return oldResponse
def CreateVideoItemXml(self, resultSet): """Creates a MediaItem of type 'video' using the resultSet from the regex. Arguments: resultSet : tuple (string) - the resultSet of the self.videoItemRegex Returns: A new MediaItem of type 'video' or 'audio' (despite the method's name) This method creates a new MediaItem from the Regular Expression or Json results <resultSet>. The method should be implemented by derived classes and are specific to the channel. If the item is completely processed an no further data needs to be fetched the self.complete property should be set to True. If not set to True, the self.UpdateVideoItem method is called if the item is focussed or selected for playback. """ Logger.Trace(resultSet) xmlData = XmlHelper(resultSet) title = xmlData.GetSingleNodeContent("title") url = xmlData.GetTagAttribute("link", {"rel": "alternate"}, {"href": None}) description = xmlData.GetSingleNodeContent("description") date = xmlData.GetSingleNodeContent("updated") item = mediaitem.MediaItem(title, url) item.type = 'video' item.description = description thumbUrl = xmlData.GetTagAttribute("link", {"rel": "enclosure"}, {"href": None}) if thumbUrl: thumbUrl = thumbUrl.replace("/medium/", "/large/") # or extralarge if thumbUrl.startswith("//"): thumbUrl = "http:%s" % (thumbUrl, ) item.thumb = thumbUrl else: item.thumb = self.noImage item.complete = False Logger.Trace("%s - %s - %s - %s - %s", title, description, date, thumbUrl, url) return item
def __SwapToken(token): """ Swaps some chars of the token to make it a valid one. NPO introduced this in july 2015 @param token: the original token from their file. @return: the swapped version """ first = -1 second = -1 startAt = 5 Logger.Debug("Starting Token swap at position in: %s %s %s", token[0:startAt], token[startAt:len(token) - startAt], token[len(token) - startAt:]) for i in range(startAt, len(token) - startAt, 1): # Logger.Trace("Checking %s", token[i]) if token[i].isdigit(): if first < 0: first = i Logger.Trace("Storing first digit at position %s: %s", first, token[i]) elif second < 0: second = i Logger.Trace("Storing second digit at position %s: %s", second, token[i]) break # swap them newToken = list(token) if first < 0 or second < 0: Logger.Debug( "No number combo found in range %s. Swapping middle items", token[startAt:len(token) - startAt]) first = 12 second = 13 Logger.Debug("Swapping position %s with %s", first, second) newToken[first] = token[second] newToken[second] = token[first] newToken = ''.join(newToken) return newToken
def CookiePrint(self): """Prints out a list of registered cookies into the logfile""" cookies = "Content of the CookieJar:\n" for cookie in self.cookieJar: cookies = "%s%r\n" % (cookies, cookie) Logger.Trace( "cookieName=%s; cookieValue=%s; expires:%s; domain: %s", cookie.name, cookie.value, cookie.expires, cookie.domain) Logger.Debug(cookies.rstrip()) return
def __GetPBK(self, pin): salt = AddonSettings.GetClientId() pbk = pyscrypt.hash(password=pin, salt=salt, N=2 ** 7, # should be so that Raspberry Pi can handle it # N=1024, r=1, p=1, dkLen=32) Logger.Trace("Generated PBK with MD5: %s", hashlib.md5(pbk).hexdigest()) return pbk
def CreateVideoItem(self, resultSet): """Creates a MediaItem of type 'video' using the resultSet from the regex. Arguments: resultSet : tuple (string) - the resultSet of the self.videoItemRegex Returns: A new MediaItem of type 'video' or 'audio' (despite the method's name) This method creates a new MediaItem from the Regular Expression or Json results <resultSet>. The method should be implemented by derived classes and are specific to the channel. If the item is completely processed an no further data needs to be fetched the self.complete property should be set to True. If not set to True, the self.UpdateVideoItem method is called if the item is focussed or selected for playback. """ Logger.Trace(resultSet) # Validate the input and raise errors if not isinstance(resultSet, dict): Logger.Critical("No Dictionary as a resultSet. Implement a custom CreateVideoItem") raise NotImplementedError("No Dictionary as a resultSet. Implement a custom CreateVideoItem") # return None elif "title" not in resultSet or "url" not in resultSet: Logger.Warning("No ?P<title> or ?P<url> in resultSet") raise LookupError("No ?P<title> or ?P<url> in resultSet") # return None # The URL url = resultSet["url"] if not url.startswith("http"): url = "%s/%s" % (self.baseUrl.rstrip('/'), url.lstrip('/')) # The title if "subtitle" in resultSet: title = "%(title)s - %(subtitle)s" % resultSet else: title = resultSet["title"] if title.isupper(): title = title.title() item = mediaitem.MediaItem(title, url) item.description = resultSet.get("description", "") item.thumb = resultSet.get("thumburl", "") item.icon = self.icon item.type = 'video' item.fanart = self.fanart item.HttpHeaders = self.httpHeaders item.complete = False return item
def CreateEpisodeItem(self, resultSet): """ Accepts an arraylist of results. It returns an item. """ #<a class='nArrow' href='([^']+)' title='[^']*'>([^<]+)</a> # 0 1 item = mediaitem.MediaItem(resultSet[1], HtmlEntityHelper.StripAmp("%s%s" % (self.baseUrl, resultSet[0]))) item.icon = self.icon Logger.Trace("%s (%s)", item.name, item.url) return item
def UpdateAddOnSettingsWithChannels(channels, config): """ updats the settings.xml to include all the channels Arguments: channels : List<channels> - The channels to add to the settings.xml config : Config - The configuration object """ # sort the channels channels.sort() # Then we read the original file filenameTemplate = os.path.join(config.rootDir, "resources", "settings_template.xml") # noinspection PyArgumentEqualDefault settingsXml = open(filenameTemplate, "r") contents = settingsXml.read() settingsXml.close() newContents = AddonSettings.__UpdateAddOnSettingsWithLanguages( contents, channels) newContents = AddonSettings.__UpdateAddOnSettingsWithChannelSelection( newContents, channels) newContents, settingsOffsetForVisibility = \ AddonSettings.__UpdateAddOnSettingsWithChannelSettings(newContents, channels) newContents = AddonSettings.__UpdateAddOnSettingsWithProxies( newContents, channels, settingsOffsetForVisibility) # Finally we insert the new XML into the old one filename = os.path.join(config.rootDir, "resources", "settings.xml") try: Logger.Trace(newContents) settingsXml = open(filename, "w+") settingsXml.write(newContents) settingsXml.close() except: Logger.Error( "Something went wrong trying to update the settings.xml", exc_info=True) try: settingsXml.close() except: pass # restore original settings settingsXml = open(filename, "w+") settingsXml.write(contents) settingsXml.close() return Logger.Info("Settings.xml updated succesfully. Reloading settings.") AddonSettings.__LoadSettings() return
def CreateEpisodeItem(self, resultSet): """ Accepts an arraylist of results. It returns an item. """ Logger.Trace(resultSet) item = mediaitem.MediaItem(resultSet[1].title(), resultSet[0]) item.icon = self.icon item.type = "folder" item.complete = True return item
def FixCrappyJson(self, data): """ Fixes description JSON tags @param data: @return: """ items = [] data = re.sub("<[^>]+>", (lambda m: ""), data) # data = data.replace("\\u0022", "'") Logger.Trace(data) return data, items