def convert_video_xml(res): dom = res_xml(res) data = dict(play_offset=0, start_offset=0, end_offset=0, chunks=defaultdict(list), restrictions={}) total_duration = 0 for archive in dom.findall("archive"): duration = int(archive.findtext("length", 0)) total_duration += duration # Add 'source' chunk chunk = dict(url=archive.findtext("video_file_url"), length=duration) data["chunks"]["source"].append(chunk) # Find transcode chunks for transcode in archive.find("transcode_file_urls"): match = re.match("transcode_(\w+)", transcode.tag) if match: name = match.group(1) chunk = dict(url=transcode.text, length=duration) data["chunks"][name].append(chunk) data["play_offset"] = dom.findtext("bracket_start") or 0 data["start_offset"] = dom.findtext("bracket_start") or 0 data["end_offset"] = dom.findtext("bracket_end") or total_duration restrictions = dom.findtext("archive_restrictions/restriction") if restrictions == "archives": data["restrictions"] = dict((n, "chansub") for n in data["chunks"]) return data
def _get_rtmp_streams(self, channelname): options = dict(l="info", a="xmlClipPath", clip_id=channelname, rid=time()) res = urlget(self.APIURL, params=options) dom = res_xml(res) rtmpurl = dom.getElementsByTagName("url") rtmp = None if len(rtmpurl) > 0: rtmp = get_node_text(rtmpurl[0]) else: raise PluginError( ("No RTMP Streams found on URL {0}").format(self.url)) rtmplist = {} rtmplist["live"] = RTMPStream(self.session, { "rtmp": rtmp, "swfVfy": self.SWFURL, "live": True }) return rtmplist
def _is_live(self, liveid): res = urlget(self.StatusAPIURL.format(liveid)) dom = res_xml(res, "status XML") live = dom.getElementsByTagName("live_is_live") if len(live) > 0: return get_node_text(live[0]) == "1" return False
def _get_streams(self): (liveid, swfurl) = self._get_channel_info(self.url) if not (liveid and swfurl): raise NoStreamsError(self.url) if not self._is_live(liveid): raise NoStreamsError(self.url) self.logger.debug("Fetching stream info") res = urlget(self.ConfigURL.format(liveid)) dom = res_xml(res, "config XML") streams = {} channels = dom.getElementsByTagName("channels")[0] clip = channels.getElementsByTagName("clip")[0] items = clip.getElementsByTagName("item") for item in items: base = item.getAttribute("base") if not base: continue if base[0] == "$": ref = re.match("\${(.+)}", base).group(1) base = self.CDN[ref] for streamel in item.getElementsByTagName("stream"): name = streamel.getAttribute("label").lower().replace(" ", "_") playpath = streamel.getAttribute("name") stream = RTMPStream(self.session, { "rtmp": ("{0}/{1}").format(base, playpath), "live": True, "swfVfy": swfurl, "pageUrl": self.url }) if not name in streams: streams[name] = stream else: index = items.index(item) if index == 1: streams[name + "_alt"] = stream else: streams[name + "_alt" + str(index)] = stream return streams
def call(self, path, format="json", host=None, **extra_params): params = dict(as3="t", **extra_params) if self.oauth_token: params["oauth_token"] = self.oauth_token url = "https://api.{0}{1}.{2}".format(host or self.host, path, format) res = urlget(url, params=params, session=self.session) if format == "json": return res_json(res) elif format == "xml": return res_xml(res) else: return res
def _limelight_soap_playlist_items(self, channelid): payload = """<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <tns:getPlaylistWithNItemsByChannelId xmlns:tns="http://service.data.media.pluggd.com"> <tns:in0>{0}</tns:in0> <tns:in1>0</tns:in1> <tns:in2>7</tns:in2> </tns:getPlaylistWithNItemsByChannelId> </SOAP-ENV:Body> </SOAP-ENV:Envelope>""".format(channelid) headers = { "Content-Type": "text/xml; charset=utf-8", "Referer": "http://assets.delvenetworks.com/player/loader.swf", "x-page-url": self.url } res = urlopen(self.LimelightSOAPURL, data=payload, headers=headers) dom = res_xml(res) streams = {} for item in dom.getElementsByTagName("PlaylistItem"): for stream in dom.getElementsByTagName("Stream"): for url in stream.getElementsByTagName("url"): url = get_node_text(url) break else: continue for height in stream.getElementsByTagName( "videoHeightInPixels"): height = get_node_text(height) break else: continue streamname = "{0}p".format(height) parsed = urlparse(url) if parsed.scheme.startswith("rtmp"): params = dict(rtmp=url, live=True) streams[streamname] = RTMPStream(self.session, params) return streams
def _limelight_soap_playlist_items(self, channelid): payload = """<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <tns:getPlaylistWithNItemsByChannelId xmlns:tns="http://service.data.media.pluggd.com"> <tns:in0>{0}</tns:in0> <tns:in1>0</tns:in1> <tns:in2>7</tns:in2> </tns:getPlaylistWithNItemsByChannelId> </SOAP-ENV:Body> </SOAP-ENV:Envelope>""".format(channelid) headers = { "Content-Type": "text/xml; charset=utf-8", "Referer": "http://assets.delvenetworks.com/player/loader.swf", "x-page-url": self.url } res = urlopen(self.LimelightSOAPURL, data=payload, headers=headers) dom = res_xml(res) streams = {} for item in dom.getElementsByTagName("PlaylistItem"): for stream in dom.getElementsByTagName("Stream"): for url in stream.getElementsByTagName("url"): url = get_node_text(url) break else: continue for height in stream.getElementsByTagName("videoHeightInPixels"): height = get_node_text(height) break else: continue streamname = "{0}p".format(height) parsed = urlparse(url) if parsed.scheme.startswith("rtmp"): params = dict(rtmp=url, live=True) streams[streamname] = RTMPStream(self.session, params) return streams
def _limelight_soap_playlist_items(self, channelid): payload = """<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <tns:getPlaylistWithNItemsByChannelId xmlns:tns="http://service.data.media.pluggd.com"> <tns:in0>{0}</tns:in0> <tns:in1>0</tns:in1> <tns:in2>7</tns:in2> </tns:getPlaylistWithNItemsByChannelId> </SOAP-ENV:Body> </SOAP-ENV:Envelope>""".format(channelid) headers = { "Content-Type": "text/xml; charset=utf-8", "Referer": "http://assets.delvenetworks.com/player/loader.swf", "x-page-url": self.url } res = urlopen(self.LimelightSOAPURL, data=payload, headers=headers) playlist = res_xml(res) streams = {} items = playlist.findall( ".//*{http://service.data.media.pluggd.com}playlistItems/") for item in items: streams_ = item.findall( "./{http://service.data.media.pluggd.com}streams/") for stream in streams_: url = stream.findtext( "{http://service.data.media.pluggd.com}url") height = stream.findtext( "{http://service.data.media.pluggd.com}videoHeightInPixels" ) streamname = "{0}p".format(height) parsed = urlparse(url) if parsed.scheme.startswith("rtmp"): params = dict(rtmp=url, live=True) streams[streamname] = RTMPStream(self.session, params) return streams
def _get_metadata(self): url = self.MetadataURL.format(self.channelname) headers = {} cookie = self.options.get("cookie") if cookie: headers["Cookie"] = cookie res = urlget(url, headers=headers) dom = res_xml(res, "metadata XML") metadata = {} metadata["title"] = self._get_node_if_exists(dom, "title") metadata["access_guid"] = self._get_node_if_exists(dom, "access_guid") metadata["login"] = self._get_node_if_exists(dom, "login") return metadata
def _get_rtmp_streams(self, channelname): options = dict(l="info", a="xmlClipPath", clip_id=channelname, rid=time()) res = urlget(self.APIURL, params=options) clip = res_xml(res) rtmpurl = clip.findtext("./info/url") if rtmpurl is None: raise PluginError(("No RTMP Streams found on URL {0}").format(self.url)) rtmplist = {} rtmplist["live"] = RTMPStream(self.session, { "rtmp": rtmpurl, "swfVfy": self.SWFURL, "live": True }) return rtmplist
def _get_metadata(self): url = self.MetadataURL.format(self.channelname) headers = {} cookie = self.options.get("cookie") if cookie: headers["Cookie"] = cookie res = urlget(url, headers=headers) meta = res_xml(res, "metadata XML") metadata = {} metadata["access_guid"] = meta.findtext("access_guid") metadata["login"] = meta.findtext("login") metadata["title"] = meta.findtext("title") return metadata
def _get_streams(self): cubeid = self._get_live_cubeid() if not cubeid: return res = urlget(API_URL_LIVE, params=dict(cubeid=cubeid)) root = res_xml(res) streams = {} for entry in root.findall("./ENTRY/*/[@reftype='live'][@href]"): url = entry.get("href") try: hls_streams = HLSStream.parse_variant_playlist(self.session, url) streams.update(hls_streams) except IOError as err: self.logger.error("Failed to open playlist: {0}", err) return streams
def _get_streams(self): cubeid = self._get_live_cubeid() if not cubeid: return res = urlget(API_URL_LIVE, params=dict(cubeid=cubeid)) root = res_xml(res) streams = {} for entry in root.findall("./ENTRY/*/[@reftype='live'][@href]"): url = entry.get("href") try: hls_streams = HLSStream.parse_variant_playlist( self.session, url) streams.update(hls_streams) except IOError as err: self.logger.error("Failed to open playlist: {0}", err) return streams
def _get_metadata(self): url = METADATA_URL.format(self.channel) cookies = {} for cookie in self.options.get("cookie").split(";"): try: name, value = cookie.split("=") except ValueError: continue cookies[name.strip()] = value.strip() res = urlget(url, cookies=cookies) meta = res_xml(res, "metadata XML") metadata = {} metadata["access_guid"] = meta.findtext("access_guid") metadata["login"] = meta.findtext("login") metadata["title"] = meta.findtext("title") return metadata
def _get_rtmp_streams(self, channelname): options = dict(l="info", a="xmlClipPath", clip_id=channelname, rid=time()) res = urlget(self.APIURL, params=options) clip = res_xml(res) rtmpurl = clip.findtext("./info/url") if rtmpurl is None: raise PluginError( ("No RTMP Streams found on URL {0}").format(self.url)) rtmplist = {} rtmplist["live"] = RTMPStream(self.session, { "rtmp": rtmpurl, "swfVfy": self.SWFURL, "live": True }) return rtmplist
def _parse_smil(self, url): res = urlget(url) dom = res_xml(res, "config XML") httpbase = None streams = {} for meta in dom.getElementsByTagName("meta"): if meta.getAttribute("name") == "httpBase": httpbase = meta.getAttribute("content") break if not httpbase: raise PluginError("Missing HTTP base in SMIL") for video in dom.getElementsByTagName("video"): url = "{0}/{1}".format(httpbase, video.getAttribute("src")) bitrate = int(video.getAttribute("system-bitrate")) streams[bitrate] = AkamaiHDStream(self.session, url) return streams
def _limelight_soap_playlist_items(self, channelid): payload = """<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <tns:getPlaylistWithNItemsByChannelId xmlns:tns="http://service.data.media.pluggd.com"> <tns:in0>{0}</tns:in0> <tns:in1>0</tns:in1> <tns:in2>7</tns:in2> </tns:getPlaylistWithNItemsByChannelId> </SOAP-ENV:Body> </SOAP-ENV:Envelope>""".format(channelid) headers = { "Content-Type": "text/xml; charset=utf-8", "Referer": "http://assets.delvenetworks.com/player/loader.swf", "x-page-url": self.url } res = urlopen(self.LimelightSOAPURL, data=payload, headers=headers) playlist = res_xml(res) streams = {} items = playlist.findall(".//*{http://service.data.media.pluggd.com}playlistItems/") for item in items: streams_ = item.findall("./{http://service.data.media.pluggd.com}streams/") for stream in streams_: url = stream.findtext("{http://service.data.media.pluggd.com}url") height = stream.findtext("{http://service.data.media.pluggd.com}videoHeightInPixels") streamname = "{0}p".format(height) parsed = urlparse(url) if parsed.scheme.startswith("rtmp"): params = dict(rtmp=url, live=True) streams[streamname] = RTMPStream(self.session, params) return streams
def _get_rtmp_streams(self, channelname): options = dict(l="info", a="xmlClipPath", clip_id=channelname, rid=time()) res = urlget(self.APIURL, params=options) dom = res_xml(res) rtmpurl = dom.getElementsByTagName("url") rtmp = None if len(rtmpurl) > 0: rtmp = get_node_text(rtmpurl[0]) else: raise PluginError(("No RTMP Streams found on URL {0}").format(self.url)) rtmplist = {} rtmplist["live"] = RTMPStream(self.session, { "rtmp": rtmp, "swfVfy": self.SWFURL, "live": True }) return rtmplist
def _get_metadata(self): url = self.MetadataURL.format(self.channelname) cookies = {} for cookie in self.options.get("cookie").split(";"): try: name, value = cookie.split("=") except ValueError: continue cookies[name.strip()] = value.strip() res = urlget(url, cookies=cookies) meta = res_xml(res, "metadata XML") metadata = {} metadata["access_guid"] = meta.findtext("access_guid") metadata["login"] = meta.findtext("login") metadata["title"] = meta.findtext("title") return metadata
def _parse_smil(self, url): res = urlget(url) smil = res_xml(res, "SMIL config") streams = {} httpbase = smil.find("{http://www.w3.org/2001/SMIL20/Language}head/" "{http://www.w3.org/2001/SMIL20/Language}meta[@name='httpBase']") if not (httpbase is not None and httpbase.attrib.get("content")): raise PluginError("Missing HTTP base in SMIL") httpbase = httpbase.attrib.get("content") videos = smil.findall("{http://www.w3.org/2001/SMIL20/Language}body/" "{http://www.w3.org/2001/SMIL20/Language}switch/" "{http://www.w3.org/2001/SMIL20/Language}video") for video in videos: url = urljoin(httpbase, video.attrib.get("src")) bitrate = int(video.attrib.get("system-bitrate")) streams[bitrate] = AkamaiHDStream(self.session, url) return streams
def _get_live_cubeid(self): res = urlget(API_URL_APP, params=dict(mode="get_live")) root = res_xml(res) return root.findtext("./cube/cubeid")