def _get_streams(self): (channelid, swfurl) = self._get_channel_info(self.url) if not (channelid and swfurl): raise NoStreamsError(self.url) self.logger.debug("Fetching stream info") res = urlget(self.ConfigURL.format(channelid)) try: dom = xml.dom.minidom.parseString(res.text) except Exception as err: raise PluginError(("Unable to parse config XML: {0})").format(err)) streams = {} channels = dom.getElementsByTagName("channels")[0] clip = channels.getElementsByTagName("clip")[0] self.logger.debug("Verifying SWF: {0}", swfurl) swfhash, swfsize = swfverify(swfurl) for item in clip.getElementsByTagName("item"): 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"): altcount = 1 name = streamel.getAttribute("label").lower().replace(" ", "_") playpath = streamel.getAttribute("name") stream = RTMPStream( self.session, { "rtmp": ("{0}/{1}").format(base, playpath), "live": True, "swfhash": swfhash, "swfsize": swfsize, "pageUrl": self.url, }, ) if not name in streams: streams[name] = stream else: if altcount == 1: streams[name + "_alt"] = stream else: streams[name + "_alt" + str(altcount)] = stream altcount += 1 return streams
def _get_streams(self): (channelid, swfurl) = self._get_channel_info(self.url) if not (channelid and swfurl): raise NoStreamsError(self.url) self.logger.debug("Fetching stream info") res = urlget(self.ConfigURL.format(channelid)) try: dom = xml.dom.minidom.parseString(res.text) except Exception as err: raise PluginError(("Unable to parse config XML: {0})").format(err)) streams = {} channels = dom.getElementsByTagName("channels")[0] clip = channels.getElementsByTagName("clip")[0] self.logger.debug("Verifying SWF: {0}", swfurl) swfhash, swfsize = swfverify(swfurl) for item in clip.getElementsByTagName("item"): 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"): altcount = 1 name = streamel.getAttribute("label").lower().replace(" ", "_") playpath = streamel.getAttribute("name") stream = RTMPStream(self.session, { "rtmp": ("{0}/{1}").format(base, playpath), "live": True, "swfhash": swfhash, "swfsize": swfsize, "pageUrl": self.url }) if not name in streams: streams[name] = stream else: if altcount == 1: streams[name + "_alt"] = stream else: streams[name + "_alt" + str(altcount)] = stream altcount += 1 return streams
def _verify_swf(self): swfurl = urlresolve(self.SWFURL) cachekey = "swf:{0}".format(swfurl) swfhash, swfsize = self.cache.get(cachekey, (None, None)) if not (swfhash and swfsize): self.logger.debug("Verifying SWF") swfhash, swfsize = swfverify(swfurl) self.cache.set(cachekey, (swfhash, swfsize)) return swfurl, swfhash, swfsize
def _get_streaminfo(self, channelname): def clean_tag(tag): if tag[0] == "_": return tag[1:] else: return tag metadata = self._get_metadata(channelname) randomp = int(random.random() * 999999) if "chansub_guid" in metadata: url = self.StreamInfoURLSub.format(channelname, randomp, metadata["chansub_guid"]) else: url = self.StreamInfoURL.format(channelname, randomp) data = urlget(url) # fix invalid xml data = re.sub(b"<(\d+)", b"<_\g<1>", data) data = re.sub(b"</(\d+)", b"</_\g<1>", data) streams = {} try: dom = xml.dom.minidom.parseString(data) except Exception as err: raise PluginError(("Unable to parse config XML: {0})").format(err)) nodes = dom.getElementsByTagName("nodes")[0] swfhash, swfsize = swfverify(self.SWFURL) for node in nodes.childNodes: info = {} for child in node.childNodes: info[child.tagName] = self._get_node_text(child) stream = RTMPStream({ "rtmp": ("{0}/{1}").format(info["connect"], info["play"]), "swfUrl": self.SWFURL, "swfhash": swfhash, "swfsize": swfsize, "live": 1 }) if "token" in info: stream.params["jtv"] = info["token"] sname = clean_tag(node.tagName) streams[sname] = stream return streams
def stream_cmdline(self, stream, filename): swfhash, swfsize = swfverify(self.SWFURL) cmd = CommandLine("rtmpdump") cmd.arg("rtmp", ("{0}/{1}").format(stream["connect"], stream["play"])) cmd.arg("swfUrl", self.SWFURL) cmd.arg("swfhash", swfhash) cmd.arg("swfsize", swfsize) cmd.arg("live", True) cmd.arg("flv", filename) if "token" in stream: cmd.arg("jtv", stream["token"]) return cmd.format()
def _verify_swf(self): swfurl = urlresolve(self.SWFURL) # For some reason the URL returned sometimes contain random # user-agent/referer query parameters, let's strip them # so we actually cache. if "?" in swfurl: swfurl = swfurl[:swfurl.find("?")] cachekey = "swf:{0}".format(swfurl) swfhash, swfsize = self.cache.get(cachekey, (None, None)) if not (swfhash and swfsize): self.logger.debug("Verifying SWF") swfhash, swfsize = swfverify(swfurl) self.cache.set(cachekey, (swfhash, swfsize)) return swfurl, swfhash, swfsize
def _get_streams(self): self.logger.debug("Fetching stream info") res = urlget(self.url, params=dict(output="json")) if res.json is None: raise PluginError("No JSON data in stream info") streams = {} video = verifyjson(res.json, "video") videos = verifyjson(video, "videoReferences") swfhash, swfsize = (None, None) for video in videos: if not ("url" in video and "playerType" in video): continue if video["playerType"] == "flash": if video["url"].startswith("rtmp"): if not swfhash: self.logger.debug("Verifying SWF: {0}", self.SWFURL) swfhash, swfsize = swfverify(self.SWFURL) stream = RTMPStream(self.session, { "rtmp": video["url"], "pageUrl": self.PageURL, "swfhash": swfhash, "swfsize": swfsize, "live": True }) streams[str(video["bitrate"]) + "k"] = stream elif video["playerType"] == "ios": try: hlsstreams = HLSStream.parse_variant_playlist(self.session, video["url"]) streams.update(hlsstreams) except IOError as err: self.logger.warning("Failed to get variant playlist: {0}", err) return streams
def _get_streams(self): channelid = self._get_channel_id(self.url) if not channelid: raise NoStreamsError(self.url) self.logger.debug("Fetching stream info") data = urlget(self.JSONURL.format(channelid)) try: info = json.loads(str(data, "utf8")) except ValueError as err: raise PluginError(("Unable to parse JSON: {0})").format(err)) streams = {} video = verifyjson(info, "video") videos = verifyjson(video, "videoReferences") self.logger.debug("Verifying SWF: {0}", self.SWFURL) swfhash, swfsize = swfverify(self.SWFURL) for video in videos: if not ("url" in video and "playerType" in video and video["playerType"] == "flash"): continue stream = RTMPStream(self.session, { "rtmp": video["url"], "pageUrl": self.PageURL, "swfhash": swfhash, "swfsize": swfsize, "live": True }) streams[str(video["bitrate"]) + "k"] = stream return streams
def _get_streaminfo(self): def clean_tag(tag): if tag[0] == "_": return tag[1:] else: return tag chansub = self._authenticate() url = self.StreamInfoURL.format(self.channelname) params = dict(b_id="true", group="", private_code="null", p=int(random.random() * 999999), channel_subscription=chansub, type="any") self.logger.debug("Fetching stream info") res = urlget(url, params=params) data = res.text # fix invalid xml data = re.sub("<(\d+)", "<_\g<1>", data) data = re.sub("</(\d+)", "</_\g<1>", data) streams = {} try: dom = xml.dom.minidom.parseString(data) except Exception as err: raise PluginError(("Unable to parse config XML: {0})").format(err)) nodes = dom.getElementsByTagName("nodes")[0] if len(nodes.childNodes) == 0: return streams self.logger.debug("Verifying SWF: {0}", self.SWFURL) swfhash, swfsize = swfverify(self.SWFURL) for node in nodes.childNodes: info = {} for child in node.childNodes: info[child.tagName] = self._get_node_text(child) if not ("connect" in info and "play" in info): continue stream = RTMPStream(self.session, { "rtmp": ("{0}/{1}").format(info["connect"], info["play"]), "swfUrl": self.SWFURL, "swfhash": swfhash, "swfsize": swfsize, "live": True }) sname = clean_tag(node.tagName) if "token" in info: stream.params["jtv"] = info["token"] else: self.logger.warning("No token found for stream {0}, this stream may fail to play", sname) streams[sname] = stream return streams
def _get_streaminfo(self, channelname): def clean_tag(tag): if tag[0] == "_": return tag[1:] else: return tag chansub = None if self.options.get("cookie") is not None: self.logger.debug("Attempting to authenticate using cookie") metadata = self._get_metadata(channelname) chansub = metadata["access_guid"] if "login" in metadata and metadata["login"] is not None: self.logger.debug("Successfully logged in as {0}", metadata["login"]) randomp = int(random.random() * 999999) url = self.StreamInfoURL.format(channelname, randomp, chansub) self.logger.debug("Fetching stream info") data = urlget(url) # fix invalid xml data = re.sub(b"<(\d+)", b"<_\g<1>", data) data = re.sub(b"</(\d+)", b"</_\g<1>", data) streams = {} try: dom = xml.dom.minidom.parseString(data) except Exception as err: raise PluginError(("Unable to parse config XML: {0})").format(err)) nodes = dom.getElementsByTagName("nodes")[0] self.logger.debug("Verifying SWF: {0}", self.SWFURL) swfhash, swfsize = swfverify(self.SWFURL) for node in nodes.childNodes: info = {} for child in node.childNodes: info[child.tagName] = self._get_node_text(child) stream = RTMPStream(self.session, { "rtmp": ("{0}/{1}").format(info["connect"], info["play"]), "swfUrl": self.SWFURL, "swfhash": swfhash, "swfsize": swfsize, "live": True }) sname = clean_tag(node.tagName) if "token" in info: stream.params["jtv"] = info["token"] else: self.logger.warning("No token found for stream {0}, this stream may fail to play", sname) streams[sname] = stream return streams