def _create_adaptive_streams(self, adaptive_formats):
        streams = {}
        adaptive_streams = {}
        best_audio_itag = None

        # Extract audio streams from the adaptive format list
        for url, label, itag, mimeType in adaptive_formats:
            if url is None:
                continue
            # extract any high quality streams only available in adaptive formats
            adaptive_streams[itag] = url
            stream_type, stream_codecs = mimeType

            if stream_type == "audio":
                streams[f"audio_{stream_codecs}"] = HTTPStream(self.session, url)

                # find the best quality audio stream m4a, opus or vorbis
                if best_audio_itag is None or self.adp_audio[itag] > self.adp_audio[best_audio_itag]:
                    best_audio_itag = itag

        if best_audio_itag and adaptive_streams and MuxedStream.is_usable(self.session):
            aurl = adaptive_streams[best_audio_itag]
            for itag, name in self.adp_video.items():
                if itag not in adaptive_streams:
                    continue
                vurl = adaptive_streams[itag]
                log.debug(f"MuxedStream: v {itag} a {best_audio_itag} = {name}")
                streams[name] = MuxedStream(
                    self.session,
                    HTTPStream(self.session, vurl),
                    HTTPStream(self.session, aurl)
                )

        return streams
def test_http_stream(session, common_args):
    stream = HTTPStream(session, "http://host/stream?foo=bar", **common_args)
    assert stream.to_url(
    ) == "http://host/stream?foo=bar&queryparamkey=queryparamval"
    with pytest.raises(TypeError) as cm:
        stream.to_manifest_url()
    assert str(
        cm.value
    ) == "<HTTPStream [http]> cannot be translated to a manifest URL"
Exemple #3
0
    def _get_streams(self):
        if "player.vimeo.com" in self.url:
            data = self.session.http.get(self.url, schema=self._player_schema)
        else:
            api_url = self.session.http.get(self.url,
                                            schema=self._config_url_schema)
            if not api_url:
                return
            data = self.session.http.get(api_url, schema=self._config_schema)

        videos = data["request"]["files"]
        streams = []

        for stream_type in ("hls", "dash"):
            if stream_type not in videos:
                continue
            for _, video_data in videos[stream_type]["cdns"].items():
                log.trace("{0!r}".format(video_data))
                url = video_data.get("url")
                if stream_type == "hls":
                    for stream in HLSStream.parse_variant_playlist(
                            self.session, url).items():
                        streams.append(stream)
                elif stream_type == "dash":
                    p = urlparse(url)
                    if p.path.endswith("dash.mpd"):
                        # LIVE
                        url = self.session.http.get(url).json()["url"]
                    elif p.path.endswith("master.json"):
                        # VOD
                        url = url.replace("master.json", "master.mpd")
                    else:
                        log.error("Unsupported DASH path: {0}".format(p.path))
                        continue

                    for stream in DASHStream.parse_manifest(self.session,
                                                            url).items():
                        streams.append(stream)

        for stream in videos.get("progressive", []):
            streams.append(
                (stream["quality"], HTTPStream(self.session, stream["url"])))

        if self.get_option("mux_subtitles") and data["request"].get(
                "text_tracks"):
            substreams = {
                s["lang"]: HTTPStream(self.session,
                                      "https://vimeo.com" + s["url"])
                for s in data["request"]["text_tracks"]
            }
            for quality, stream in streams:
                yield quality, MuxedStream(self.session,
                                           stream,
                                           subtitles=substreams)
        else:
            for stream in streams:
                yield stream
Exemple #4
0
def test_http_stream(session, common_args, expected_headers):
    stream = HTTPStream(session, "http://host/path?foo=bar", **common_args)
    assert stream.__json__() == {
        "type": "http",
        "url":
        "http://host/path?foo=bar&sessionqueryparamkey=sessionqueryparamval&queryparamkey=queryparamval",
        "method": "GET",
        "body": None,
        "headers": expected_headers,
    }
Exemple #5
0
    def _get_streams(self):
        if "empty" in self.url:
            return

        if "UnsortableStreamNames" in self.url:
            def gen():
                for i in range(3):
                    yield "vod", HTTPStream(self.session, "http://test.se/stream")

            return gen()

        if "NoStreamsError" in self.url:
            raise NoStreamsError(self.url)

        streams = {}
        streams["test"] = TestStream(self.session)
        streams["hls"] = HLSStream(self.session, "http://test.se/playlist.m3u8")
        streams["http"] = HTTPStream(self.session, "http://test.se/stream")

        streams["240p"] = HTTPStream(self.session, "http://test.se/stream")
        streams["360p"] = HTTPStream(self.session, "http://test.se/stream")
        streams["1080p"] = HTTPStream(self.session, "http://test.se/stream")

        streams["350k"] = HTTPStream(self.session, "http://test.se/stream")
        streams["800k"] = HTTPStream(self.session, "http://test.se/stream")
        streams["1500k"] = HTTPStream(self.session, "http://test.se/stream")
        streams["3000k"] = HTTPStream(self.session, "http://test.se/stream")

        streams["480p"] = [
            HTTPStream(self.session, "http://test.se/stream"),
            HLSStream(self.session, "http://test.se/playlist.m3u8")
        ]

        return streams
Exemple #6
0
 def __init__(self,
              session_,
              url,
              force_restart=False,
              start_offset=0,
              duration=None,
              **args):
     HTTPStream.__init__(self, session_, url, **args)
     self.force_restart = force_restart
     self.start_offset = start_offset
     self.duration = duration
Exemple #7
0
    def _get_streams(self):
        res = self.session.http.get(self.url)
        m = self._re_idAsset.search(res.text)
        if m:
            content_id = m.group(1)
            log.debug(f"Found content with id: {content_id}")
            stream_data = self.zclient.get_cdn_list(content_id,
                                                    schema=self.cdn_schema)
            quality_map = None

            streams = []
            for stream in stream_data:
                # only use one stream
                _one_m3u8 = False
                _one_mp4 = False
                for url in stream["urls"]:
                    p_url = urlparse(url)
                    if p_url.path.endswith(".m3u8"):
                        if _one_m3u8:
                            continue
                        try:
                            streams.extend(
                                HLSStream.parse_variant_playlist(
                                    self.session, url).items())
                            _one_m3u8 = True
                        except OSError as err:
                            log.error(str(err))
                    elif p_url.path.endswith(".mp4"):
                        if _one_mp4:
                            continue
                        if quality_map is None:  # only make the request when it is necessary
                            quality_map = self._get_quality_map(content_id)
                        # rename the HTTP sources to match the HLS sources
                        quality = quality_map.get(stream["quality"],
                                                  stream["quality"])
                        streams.append((quality, HTTPStream(self.session,
                                                            url)))
                        _one_mp4 = True

            subtitles = None
            if self.get_option("mux_subtitles"):
                subtitles = self._get_subtitles(content_id)
            if subtitles:
                substreams = {}
                for i, subtitle in enumerate(subtitles):
                    substreams[subtitle["lang"]] = HTTPStream(
                        self.session, subtitle["src"])

                for q, s in streams:
                    yield q, MuxedStream(self.session, s, subtitles=substreams)
            else:
                for s in streams:
                    yield s
Exemple #8
0
    def _parse_streams(self, res):
        stream_url = validate.Schema(
            validate.parse_html(),
            validate.xml_xpath_string(
                ".//head/meta[@property='og:video:url'][@content][1]/@content")
        ).validate(res.text)
        if not stream_url:
            log.debug("No meta og:video:url")
        else:
            if ".mpd" in stream_url:
                for s in DASHStream.parse_manifest(self.session,
                                                   stream_url).items():
                    yield s
                return
            elif ".mp4" in stream_url:
                yield "vod", HTTPStream(self.session, stream_url)
                return

        for match in self._src_re.finditer(res.text):
            stream_url = match.group("url")
            if "\\/" in stream_url:
                # if the URL is json encoded, decode it
                stream_url = parse_json("\"{}\"".format(stream_url))
            if ".mpd" in stream_url:
                for s in DASHStream.parse_manifest(self.session,
                                                   stream_url).items():
                    yield s
            elif ".mp4" in stream_url:
                yield match.group(1), HTTPStream(self.session, stream_url)
            else:
                log.debug("Non-dash/mp4 stream: {0}".format(stream_url))

        match = self._dash_manifest_re.search(res.text)
        if match:
            # facebook replaces "<" characters with the substring "\\x3C"
            manifest = match.group("manifest").replace("\\/", "/")
            if is_py3:
                manifest = bytes(unquote_plus(manifest),
                                 "utf-8").decode("unicode_escape")
            else:
                manifest = unquote_plus(manifest).decode("string_escape")
            # Ignore unsupported manifests until DASH SegmentBase support is implemented
            if "SegmentBase" in manifest:
                log.error("Skipped DASH manifest with SegmentBase streams")
            else:
                for s in DASHStream.parse_manifest(self.session,
                                                   manifest).items():
                    yield s
Exemple #9
0
 def test_http_stream(self):
     url = "http://test.se/stream"
     stream = HTTPStream(self.session, url, headers={"User-Agent": "Test"})
     self.assertEqual(
         {"type": "http",
          "url": url,
          "method": "GET",
          "body": None,
          "headers": {
              "User-Agent": "Test",
              "Accept": "*/*",
              "Accept-Encoding": DEFAULT_ACCEPT_ENCODING,
              "Connection": "keep-alive",
          }},
         stream.__json__()
     )
Exemple #10
0
    def _get_streams(self):
        player_js = self.session.http.get(
            self.url,
            schema=validate.Schema(
                validate.transform(self._re_player.search),
                validate.any(
                    None,
                    validate.Schema(
                        validate.get(1),
                        validate.transform(
                            lambda url: update_scheme("https:", url))))))
        if not player_js:
            return

        log.debug(f"Found player js {player_js}")
        data = self.session.http.get(
            player_js,
            schema=validate.Schema(
                validate.transform(self._re_json.match), validate.get(1),
                validate.parse_json(), validate.get("mediaResource"),
                validate.get("dflt"), {
                    validate.optional("audioURL"): validate.url(),
                    validate.optional("videoURL"): validate.url()
                }))

        if data.get("videoURL"):
            yield from HLSStream.parse_variant_playlist(
                self.session, update_scheme("https:",
                                            data.get("videoURL"))).items()
        if data.get("audioURL"):
            yield "audio", HTTPStream(
                self.session, update_scheme("https:", data.get("audioURL")))
Exemple #11
0
    def _get_streams(self):
        data = self.match.groupdict()
        url = update_scheme("https://", data.get("url"), force=False)
        params = parse_params(data.get("params"))
        log.debug("URL={0}; params={1}".format(url, params))

        return {"live": HTTPStream(self.session, url, **params)}
Exemple #12
0
    def _get_streams(self):
        streams = self.session.http.get(self.url, schema=self._stream_schema)
        if streams is None:
            return

        if streams['type'] != 'STATION':
            return

        stream_urls = set()
        for stream in streams['streams']:
            log.trace('{0!r}'.format(stream))
            url = stream['url']

            url_no_scheme = urlunparse(urlparse(url)._replace(scheme=''))
            if url_no_scheme in stream_urls:
                continue
            stream_urls.add(url_no_scheme)

            if stream['contentFormat'] in ('audio/mpeg', 'audio/aac'):
                yield 'live', HTTPStream(self.session, url, allow_redirects=True)
            elif stream['contentFormat'] == 'video/MP2T':
                streams = HLSStream.parse_variant_playlist(self.session, stream["url"])
                if not streams:
                    yield stream["quality"], HLSStream(self.session, stream["url"])
                else:
                    for s in streams.items():
                        yield s
Exemple #13
0
    def _get_streams(self):
        # Construct manifest URL for this program.
        program_type, program_id = self.match.groups()
        manifest_type = self._program_type_map.get(program_type)
        if manifest_type is None:
            log.error(f"Unknown program type '{program_type}'")
            return None

        # Fetch program_id.
        res = self.session.http.get(self.url)
        m = self._program_id_re.search(res.text)
        if m is not None:
            program_id = m.group(1)
        elif program_id is None:
            log.error("Could not extract program ID from URL")
            return None

        manifest_url = urljoin(
            self._psapi_url, f"playback/manifest/{manifest_type}/{program_id}")

        # Extract media URL.
        res = self.session.http.get(manifest_url)
        manifest = self.session.http.json(res, schema=self._playable_schema)
        if 'nonPlayable' in manifest:
            reason = manifest["nonPlayable"]["reason"]
            log.error(f"Not playable ({reason})")
            return None
        self._set_metadata(manifest)
        asset = manifest['playable']['assets'][0]

        # Some streams such as podcasts are not HLS but plain files.
        if asset['format'] == 'HLS':
            return HLSStream.parse_variant_playlist(self.session, asset['url'])
        else:
            return [("live", HTTPStream(self.session, asset['url']))]
Exemple #14
0
    def _get_vod(self, root):
        schema_vod = validate.Schema(
            validate.xml_xpath_string(
                ".//script[@type='application/ld+json'][contains(text(),'VideoObject')][1]/text()"
            ), str,
            validate.transform(
                lambda jsonlike: re.sub(r"[\r\n]+", "", jsonlike)),
            validate.parse_json(),
            validate.any(
                validate.all(
                    {"@graph": [dict]}, validate.get("@graph"),
                    validate.filter(lambda obj: obj["@type"] == "VideoObject"),
                    validate.get(0)), dict), {"contentUrl": validate.url()},
            validate.get("contentUrl"),
            validate.transform(
                lambda content_url: update_scheme("https://", content_url)))
        try:
            vod = schema_vod.validate(root)
        except PluginError:
            return

        if urlparse(vod).path.endswith(".m3u8"):
            return HLSStream.parse_variant_playlist(self.session, vod)

        return {"vod": HTTPStream(self.session, vod)}
Exemple #15
0
    def __json__(self):
        json = HTTPStream.__json__(self)

        # Pretty sure HLS is GET only.
        del json["method"]
        del json["body"]

        return json
Exemple #16
0
    def __json__(self):
        json = HTTPStream.__json__(self)

        # Pretty sure HLS is GET only.
        del json["method"]
        del json["body"]

        return json
Exemple #17
0
    def _get_streams(self):
        data = self.session.http.get(self.url, schema=self.config_schema)

        for info in data["files"].values():
            stream_url = update_scheme("https://", info["url"])
            # pick the smaller of the two dimensions, for landscape v. portrait videos
            res = min(info["width"], info["height"])
            yield "{0}p".format(res), HTTPStream(self.session, stream_url)
Exemple #18
0
    def _get_clips(self):
        try:
            sig, token, streams = self.api.clips(self.clip_name)
        except (PluginError, TypeError):
            return

        for quality, stream in streams:
            yield quality, HTTPStream(self.session, update_qsd(stream, {"sig": sig, "token": token}))
Exemple #19
0
    def _get_streams(self):
        res = self._get_res(self.url)

        if self.match.group(
                "channel") and not self.match.group("channel_live"):
            initial = self._get_data_from_regex(res, self._re_ytInitialData,
                                                "initial data")
            video_id = self._data_video_id(initial)
            if video_id is None:
                log.error("Could not find videoId on channel page")
                return
            self.url = self._url_canonical.format(video_id=video_id)
            res = self._get_res(self.url)

        data = self._get_data_from_regex(res, self._re_ytInitialPlayerResponse,
                                         "initial player response")
        if not self._data_status(data):
            data = self._get_data_from_api(res)
            if not self._data_status(data, True):
                return

        self.id, self.author, self.category, self.title, is_live = self._schema_videodetails(
            data)
        log.debug(f"Using video ID: {self.id}")

        if is_live:
            log.debug("This video is live.")

        streams = {}
        hls_manifest, formats, adaptive_formats = self._schema_streamingdata(
            data)

        protected = next(
            (True for url, *_ in formats + adaptive_formats if url is None),
            False)
        if protected:
            log.debug("This video may be protected.")

        for url, label in formats:
            if url is None:
                continue
            streams[label] = HTTPStream(self.session, url)

        if not is_live:
            streams.update(self._create_adaptive_streams(adaptive_formats))

        if hls_manifest:
            streams.update(
                HLSStream.parse_variant_playlist(self.session,
                                                 hls_manifest,
                                                 name_key="pixels"))

        if not streams and protected:
            raise PluginError(
                "This plugin does not support protected videos, try youtube-dl instead"
            )

        return streams
Exemple #20
0
    def _get_video_streams(self):
        res = self.session.http.get(self.url)
        match = self._video_player_re.search(res.text)
        if match is None:
            return
        player_url = match.group('player_url')
        stream_data = self.session.http.get(player_url, schema=self._video_stream_schema)
        if stream_data is None:
            return

        # Check geolocation to prevent further errors when stream is parsed
        if not self.check_geolocation(stream_data['geoLocRestriction']):
            log.error('Stream is geo-restricted')
            return

        # Check whether streams are DRM-protected
        if stream_data.get('drm', False):
            log.error('Stream is DRM-protected')
            return

        now = datetime.datetime.now()
        try:
            if isinstance(stream_data['sources'], dict):
                urls = []
                for profile, url in stream_data['sources'].items():
                    if not url or url in urls:
                        continue
                    match = self._stream_size_re.match(url)
                    if match is not None:
                        quality = match.group('size')
                    else:
                        quality = profile
                    yield quality, HTTPStream(self.session, url)
                    urls.append(url)

            hls_url = stream_data.get('urlHls') or stream_data.get('streamUrlHls')
            if hls_url:
                if stream_data.get('isLive', False):
                    # Live streams require a token
                    hls_url = self.tokenize_stream(hls_url)
                yield from HLSStream.parse_variant_playlist(self.session, hls_url).items()

            dash_url = stream_data.get('urlDash') or stream_data.get('streamUrlDash')
            if dash_url:
                if stream_data.get('isLive', False):
                    # Live streams require a token
                    dash_url = self.tokenize_stream(dash_url)
                yield from DASHStream.parse_manifest(self.session, dash_url).items()

        except OSError as err:
            if '403 Client Error' in str(err):
                # Check whether video is expired
                if 'startDate' in stream_data:
                    if now < self.iso8601_to_epoch(stream_data['startDate']):
                        log.error('Stream is not yet available')
                elif 'endDate' in stream_data:
                    if now > self.iso8601_to_epoch(stream_data['endDate']):
                        log.error('Stream has expired')
Exemple #21
0
    def _parse_streams(self, res):
        _found_stream_url = False
        for meta in itertags(res.text, "meta"):
            if meta.attributes.get("property") == "og:video:url":
                stream_url = html_unescape(meta.attributes.get("content"))
                if ".mpd" in stream_url:
                    for s in DASHStream.parse_manifest(self.session,
                                                       stream_url).items():
                        yield s
                        _found_stream_url = True
                elif ".mp4" in stream_url:
                    yield "vod", HTTPStream(self.session, stream_url)
                    _found_stream_url = True
                break
        else:
            log.debug("No meta og:video:url")

        if _found_stream_url:
            return

        for match in self._src_re.finditer(res.text):
            stream_url = match.group("url")
            if "\\/" in stream_url:
                # if the URL is json encoded, decode it
                stream_url = parse_json("\"{}\"".format(stream_url))
            if ".mpd" in stream_url:
                yield from DASHStream.parse_manifest(self.session,
                                                     stream_url).items()
            elif ".mp4" in stream_url:
                yield match.group(1), HTTPStream(self.session, stream_url)
            else:
                log.debug("Non-dash/mp4 stream: {0}".format(stream_url))

        match = self._dash_manifest_re.search(res.text)
        if match:
            # facebook replaces "<" characters with the substring "\\x3C"
            manifest = match.group("manifest").replace("\\/", "/")
            manifest = bytes(unquote_plus(manifest),
                             "utf-8").decode("unicode_escape")
            # Ignore unsupported manifests until DASH SegmentBase support is implemented
            if "SegmentBase" in manifest:
                log.error("Skipped DASH manifest with SegmentBase streams")
            else:
                yield from DASHStream.parse_manifest(self.session,
                                                     manifest).items()
Exemple #22
0
    def _get_http_streams(self, info):
        name = QUALITY_MAP.get(info["_quality"], "vod")
        urls = info["_stream"]
        if not isinstance(info["_stream"], list):
            urls = [urls]

        for url in urls:
            stream = HTTPStream(self.session, update_scheme("https://", url))
            yield name, stream
Exemple #23
0
    def _get_streams(self):
        channel = self.match.group("channel")
        vod_id = self.match.group("vod_id")
        is_group = self.match.group("is_group")

        if is_py3:
            adapter = TLSSecLevel1Adapter()
            self.session.http.mount("https://filmon.com", adapter)
            self.session.http.mount("https://www.filmon.com", adapter)
            self.session.http.mount("https://vms-admin.filmon.com/", adapter)

        # get cookies
        self.session.http.get(self.url)

        if vod_id:
            data = self.api.vod(vod_id)
            for _, stream in data["streams"].items():
                if stream["url"].endswith(".m3u8"):
                    streams = HLSStream.parse_variant_playlist(self.session, stream["url"])
                    if not streams:
                        yield stream["quality"], HLSStream(self.session, stream["url"])
                    else:
                        for s in streams.items():
                            yield s
                elif stream["url"].endswith(".mp4"):
                    yield stream["quality"], HTTPStream(self.session, stream["url"])
                else:
                    log.error("Unsupported stream type")
                    return
        else:
            if channel and not channel.isdigit():
                _id = self.cache.get(channel)
                if _id is None:
                    _id = self.session.http.get(self.url, schema=self._channel_id_schema)
                    log.debug("Found channel ID: {0}".format(_id))
                    # do not cache a group url
                    if _id and not is_group:
                        self.cache.set(channel, _id, expires=self.TIME_CHANNEL)
                else:
                    log.debug("Found cached channel ID: {0}".format(_id))
            else:
                _id = channel

            if _id is None:
                raise PluginError("Unable to find channel ID: {0}".format(channel))

            try:
                data = self.api.channel(_id)
                for stream in data["streams"]:
                    yield stream["quality"], FilmOnHLS(self.session, channel=_id, quality=stream["quality"])
            except Exception:
                if channel and not channel.isdigit():
                    self.cache.set(channel, None, expires=0)
                    log.debug("Reset cached channel: {0}".format(channel))

                raise
Exemple #24
0
    def _get_streams(self):
        self.session.set_option("ffmpeg-start-at-zero", True)
        self.session.http.headers.update({"Accept-Language": "en-US"})

        done = False
        res = self.session.http.get(self.url)
        log.trace(f"{res.url}")
        for title in itertags(res.text, "title"):
            if title.text.startswith("Log into Facebook"):
                log.error("Video is not available, You must log in to continue.")
                return

        for s in self._parse_streams(res):
            done = True
            yield s
        if done:
            return

        # fallback on to playlist
        log.debug("Falling back to playlist regex")
        match = self._playlist_re.search(res.text)
        playlist = match and match.group(1)
        if playlist:
            match = self._plurl_re.search(playlist)
            if match:
                url = match.group(1)
                yield "sd", HTTPStream(self.session, url)
                return

        # fallback to tahoe player url
        log.debug("Falling back to tahoe player")
        video_id = self.match.group("video_id")
        url = self._TAHOE_URL.format(video_id)
        data = {
            "__a": 1,
            "__pc": self._DEFAULT_PC,
            "__rev": self._DEFAULT_REV,
            "fb_dtsg": "",
        }
        match = self._pc_re.search(res.text)
        if match:
            data["__pc"] = match.group(1)
        match = self._rev_re.search(res.text)
        if match:
            data["__rev"] = match.group(1)
        match = self._dtsg_re.search(res.text)
        if match:
            data["fb_dtsg"] = match.group(1)
        res = self.session.http.post(
            url,
            headers={"Content-Type": "application/x-www-form-urlencoded"},
            data=urlencode(data).encode("ascii")
        )

        for s in self._parse_streams(res):
            yield s
Exemple #25
0
    def get_streams(self, video_id):
        log.debug(f"Finding streams for video: {video_id}")

        player_url = self.URL_PLAYER.format(
            account_id=self.account_id,
            player_id=self.player_id,
            video_id=video_id
        )

        policy_key = self.session.http.get(
            player_url,
            params={"videoId": video_id},
            schema=validate.Schema(
                validate.transform(re.compile(r"""policyKey\s*:\s*(?P<q>['"])(?P<key>[\w-]+)(?P=q)""").search),
                validate.any(None, validate.get("key"))
            )
        )
        if not policy_key:
            raise PluginError("Could not find Brightcove policy key")
        log.debug(f"Found policy key: {policy_key}")

        self.session.http.headers.update({"Referer": player_url})
        sources, self.title = self.session.http.get(
            self.URL_API.format(account_id=self.account_id, video_id=video_id),
            headers={"Accept": f"application/json;pk={policy_key}"},
            schema=validate.Schema(
                validate.parse_json(),
                {
                    "sources": [{
                        "src": validate.url(),
                        validate.optional("type"): str,
                        validate.optional("container"): str,
                        validate.optional("height"): int,
                        validate.optional("avg_bitrate"): int,
                    }],
                    validate.optional("name"): str,
                },
                validate.union_get("sources", "name")
            )
        )

        for source in sources:
            if source.get("type") in ("application/vnd.apple.mpegurl", "application/x-mpegURL"):
                yield from HLSStream.parse_variant_playlist(self.session, source.get("src")).items()

            elif source.get("container") == "MP4":
                # determine quality name
                if source.get("height"):
                    q = f"{source.get('height')}p"
                elif source.get("avg_bitrate"):
                    q = f"{source.get('avg_bitrate') // 1000}k"
                else:
                    q = "live"

                yield q, HTTPStream(self.session, source.get("src"))
Exemple #26
0
    def __json__(self):
        json = HTTPStream.__json__(self)

        if self.url_master:
            json["master"] = self.to_manifest_url()

        # Pretty sure HLS is GET only.
        del json["method"]
        del json["body"]

        return json
Exemple #27
0
    def _get_streams(self):
        try:
            data_url = self.session.http.get(
                self.url,
                schema=validate.Schema(
                    validate.parse_html(),
                    validate.xml_find(".//*[@data-ctrl-player]"),
                    validate.get("data-ctrl-player"),
                    validate.transform(lambda s: s.replace("'", "\"")),
                    validate.parse_json(), {"url": validate.text},
                    validate.get("url")))
        except PluginError:
            return

        data_url = urljoin(self._URL_DATA_BASE, data_url)
        log.debug("Player URL: '{0}'", data_url)

        self.title, media = self.session.http.get(
            data_url,
            schema=validate.Schema(
                validate.parse_json(name="MEDIAINFO"), {
                    "mc": {
                        validate.optional("_title"):
                        validate.text,
                        "_mediaArray": [
                            validate.all(
                                {
                                    "_mediaStreamArray": [
                                        validate.all(
                                            {
                                                "_quality":
                                                validate.any(
                                                    validate.text, int),
                                                "_stream": [validate.url()],
                                            },
                                            validate.union_get(
                                                "_quality", ("_stream", 0)))
                                    ]
                                }, validate.get("_mediaStreamArray"),
                                validate.transform(dict))
                        ]
                    }
                }, validate.get("mc"),
                validate.union_get("_title", ("_mediaArray", 0))))

        if media.get("auto"):
            for s in HLSStream.parse_variant_playlist(
                    self.session, media.get("auto")).items():
                yield s
        else:
            for quality, stream in media.items():
                yield self._QUALITY_MAP.get(quality, quality), HTTPStream(
                    self.session, stream)
Exemple #28
0
    def _get_clips(self):
        try:
            (((sig, token), streams), (self.author, self.category),
             self.title) = self.api.clips(self.clip_name)
        except (PluginError, TypeError):
            return

        for quality, stream in streams:
            yield quality, HTTPStream(
                self.session, update_qsd(stream, {
                    "sig": sig,
                    "token": token
                }))
Exemple #29
0
    def _get_streams(self):
        channel = self.match.group("channel")
        self.session.http.headers.update({"Referer": self.url})
        data = self.session.http.post(
            "https://wap-api.17app.co/api/v1/lives/{0}/viewers/alive".format(
                channel),
            data={"liveStreamID": channel},
            schema=validate.Schema(
                validate.parse_json(),
                validate.any(
                    {
                        "rtmpUrls": [{
                            validate.optional("provider"):
                            validate.any(int, None),
                            "url":
                            validate.url(path=validate.endswith(".flv")),
                        }]
                    },
                    {
                        "errorCode": int,
                        "errorMessage": str
                    },
                ),
            ),
            acceptable_status=(200, 403, 404, 420))
        log.trace("{0!r}".format(data))
        if data.get("errorCode"):
            log.error("{0} - {1}".format(
                data['errorCode'],
                data['errorMessage'].replace('Something wrong: ', '')))
            return

        flv_url = data["rtmpUrls"][0]["url"]
        yield "live", HTTPStream(self.session, flv_url)

        if "wansu-" in flv_url:
            hls_url = flv_url.replace(".flv", "/playlist.m3u8")
        else:
            hls_url = flv_url.replace("live-hdl",
                                      "live-hls").replace(".flv", ".m3u8")

        s = HLSStream.parse_variant_playlist(self.session, hls_url)
        if not s:
            yield "live", HLSStream(self.session, hls_url)
        else:
            if len(s) == 1:
                for _n, _s in s.items():
                    yield "live", _s
            else:
                for _s in s.items():
                    yield _s
Exemple #30
0
    def _get_streams(self):
        docid = self.match.group(1)
        log.debug("Google Docs ID: {0}".format(docid))
        res = self.session.http.get(self.api_url, params=dict(docid=docid))
        data = dict(parse_qsl(res.text))

        if data["status"] == "ok":
            fmts = dict([s.split('/')[:2] for s in data["fmt_list"].split(",")])
            streams = [s.split('|') for s in data["fmt_stream_map"].split(",")]
            for qcode, url in streams:
                _, h = fmts[qcode].split("x")
                yield "{0}p".format(h), HTTPStream(self.session, url)
        else:
            log.error("{0} (ID: {1})".format(data["reason"], docid))
Exemple #31
0
    def _get_streams(self):
        video_id = self.match.group('video_id')
        if video_id is not None:
            # VOD
            live = False
            player_url = self.VOD_PLAYER_URL.format(video_id)
        else:
            # Live
            live = True
            player_url = self.LIVE_PLAYER_URL

        res = self.session.http.get(player_url)
        playlist = re.findall(self._playlist_re, res.text)
        index = 0
        if not live:
            # Get the index for the video on the playlist
            match = self._vod_video_index_re.search(res.text)
            if match is None:
                return
            index = int(match.group('video_index'))

        if not playlist:
            return
        videos = self._video_schema.validate(playlist[index])

        for video in videos:
            video_url = video['file']

            # Ignore non-supported MSS streams
            if 'isml/Manifest' in video_url:
                continue

            try:
                if '.m3u8' in video_url:
                    for stream in HLSStream.parse_variant_playlist(
                            self.session, video_url).items():
                        yield stream
                elif '.mp4' in video_url:
                    match = self._mp4_bitrate_re.match(video_url)
                    if match is not None:
                        bitrate = '%sk' % match.group('bitrate')
                    else:
                        bitrate = 'vod'
                    yield bitrate, HTTPStream(self.session, video_url)
            except IOError as err:
                if '403 Client Error' in str(err):
                    log.error(
                        'Failed to access stream, may be due to geo-restriction'
                    )
                raise
Exemple #32
0
 def __init__(self, session_, url, force_restart=False, start_offset=0, duration=None, **args):
     HTTPStream.__init__(self, session_, url, **args)
     self.force_restart = force_restart
     self.start_offset = start_offset
     self.duration = duration