-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
51 changed files
with
6,192 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
""" | ||
$description Live TV channels from SBS, a South Korean public broadcaster. | ||
$url www.sbs.co.kr/live | ||
$type live | ||
$region South Korea | ||
""" | ||
|
||
import argparse | ||
import logging | ||
import re | ||
|
||
from streamlink.plugin import Plugin, pluginargument, pluginmatcher | ||
from streamlink.plugin.api import validate | ||
from streamlink.stream.hls import HLSStream | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
@pluginmatcher(re.compile( | ||
r"https?://www\.sbs\.co\.kr/live/(?P<channel>[^/?]+)", | ||
)) | ||
@pluginargument( | ||
"id", | ||
help=argparse.SUPPRESS, | ||
) | ||
class SBScokr(Plugin): | ||
_URL_API_CHANNELS = "https://static.apis.sbs.co.kr/play-api/1.0/onair{virtual}/channels" | ||
_URL_API_CHANNEL = "https://apis.sbs.co.kr/play-api/1.0/onair{virtual}/channel/{channel}" | ||
|
||
def _get_streams(self): | ||
channel = self.match["channel"] | ||
|
||
for virtual in ("", "/virtual"): | ||
channels = self.session.http.get( | ||
self._URL_API_CHANNELS.format(virtual=virtual), | ||
schema=validate.Schema( | ||
validate.parse_json(), | ||
{ | ||
"list": [{ | ||
"channelid": str, | ||
}], | ||
}, | ||
validate.get("list"), | ||
validate.map(lambda item: item["channelid"]), | ||
), | ||
) | ||
if channel in channels: | ||
break | ||
else: | ||
return | ||
|
||
info, hls_url = self.session.http.get( | ||
self._URL_API_CHANNEL.format(virtual=virtual, channel=channel), | ||
params={ | ||
"v_type": "2", | ||
"platform": "pcweb", | ||
"protocol": "hls", | ||
"jwt-token": "", | ||
"ssl": "Y", | ||
"rscuse": "", | ||
}, | ||
schema=validate.Schema( | ||
validate.parse_json(), | ||
{ | ||
"onair": { | ||
"info": { | ||
"channelid": str, | ||
"channelname": str, | ||
"title": str, | ||
"onair_yn": str, | ||
"overseas_yn": str, | ||
"overseas_text": str, | ||
}, | ||
"source": { | ||
"mediasource": { | ||
validate.optional("mediaurl"): validate.url(path=validate.endswith(".m3u8")), | ||
}, | ||
}, | ||
}, | ||
}, | ||
validate.get("onair"), | ||
validate.union_get( | ||
"info", | ||
("source", "mediasource", "mediaurl"), | ||
), | ||
), | ||
) | ||
|
||
if info["overseas_yn"] != "Y": | ||
log.error(f"Geo-restricted content: {info['overseas_text']}") | ||
return | ||
if info["onair_yn"] != "Y": | ||
log.error("This channel is currently unavailable") | ||
return | ||
|
||
self.id = info["channelid"] | ||
self.author = info["channelname"] | ||
self.title = info["title"] | ||
|
||
if hls_url: | ||
return HLSStream.parse_variant_playlist(self.session, hls_url) | ||
|
||
|
||
__plugin__ = SBScokr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
""" | ||
$description Japanese live-streaming service used primarily by Japanese idols & voice actors and their fans. | ||
$url showroom-live.com | ||
$type live | ||
""" | ||
|
||
import logging | ||
import re | ||
|
||
from streamlink.plugin import Plugin, pluginmatcher | ||
from streamlink.plugin.api import validate | ||
from streamlink.stream.hls import HLSStream | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
@pluginmatcher(re.compile( | ||
r"https?://(?:\w+\.)?showroom-live\.com/", | ||
)) | ||
class Showroom(Plugin): | ||
LIVE_STATUS = 2 | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self.session.set_option("hls-playlist-reload-time", "segment") | ||
|
||
def _get_streams(self): | ||
room_id = self.session.http.get( | ||
self.url, | ||
schema=validate.Schema( | ||
validate.parse_html(), | ||
validate.xml_xpath_string(".//script[contains(text(),'share_url:\"https:')][1]/text()"), | ||
validate.none_or_all( | ||
re.compile(r"share_url:\"https:[^?]+?\?room_id=(?P<room_id>\d+)\""), | ||
validate.any(None, validate.get("room_id")), | ||
), | ||
), | ||
) | ||
if not room_id: | ||
return | ||
|
||
live_status, self.title = self.session.http.get( | ||
"https://www.showroom-live.com/api/live/live_info", | ||
params={ | ||
"room_id": room_id, | ||
}, | ||
schema=validate.Schema( | ||
validate.parse_json(), | ||
{ | ||
"live_status": int, | ||
"room_name": str, | ||
}, | ||
validate.union_get( | ||
"live_status", | ||
"room_name", | ||
), | ||
), | ||
) | ||
if live_status != self.LIVE_STATUS: | ||
log.info("This stream is currently offline") | ||
return | ||
|
||
url = self.session.http.get( | ||
"https://www.showroom-live.com/api/live/streaming_url", | ||
params={ | ||
"room_id": room_id, | ||
"abr_available": 1, | ||
}, | ||
schema=validate.Schema( | ||
validate.parse_json(), | ||
{"streaming_url_list": [{ | ||
"type": str, | ||
"url": validate.url(), | ||
}]}, | ||
validate.get("streaming_url_list"), | ||
validate.filter(lambda p: p["type"] == "hls_all"), | ||
validate.get((0, "url")), | ||
), | ||
) | ||
|
||
res = self.session.http.get(url, acceptable_status=(200, 403, 404)) | ||
if res.headers["Content-Type"] != "application/x-mpegURL": | ||
log.error("This stream is restricted") | ||
return | ||
|
||
return HLSStream.parse_variant_playlist(self.session, url) | ||
|
||
|
||
__plugin__ = Showroom |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
""" | ||
$description Sporting channel live stream owned by Sportal, a Bulgarian sports media website. | ||
$url sportal.bg | ||
$type live | ||
""" | ||
|
||
import logging | ||
import re | ||
|
||
from streamlink.plugin import Plugin, pluginmatcher | ||
from streamlink.stream.hls import HLSStream | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
@pluginmatcher(re.compile( | ||
r"https?://(?:www\.)?sportal\.bg/sportal_live_tv\.php", | ||
)) | ||
class Sportal(Plugin): | ||
_hls_re = re.compile(r"""["'](?P<url>[^"']+\.m3u8[^"']*?)["']""") | ||
|
||
def _get_streams(self): | ||
res = self.session.http.get(self.url) | ||
m = self._hls_re.search(res.text) | ||
if not m: | ||
return | ||
|
||
hls_url = m.group("url") | ||
log.debug("URL={0}".format(hls_url)) | ||
log.warning("SSL certificate verification is disabled.") | ||
return HLSStream.parse_variant_playlist( | ||
self.session, hls_url, verify=False).items() | ||
|
||
|
||
__plugin__ = Sportal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
""" | ||
$description German sports magazine live stream, owned by ARD. | ||
$url sportschau.de | ||
$type live | ||
""" | ||
|
||
import logging | ||
import re | ||
|
||
from streamlink.plugin import Plugin, pluginmatcher | ||
from streamlink.plugin.api import validate | ||
from streamlink.stream.hls import HLSStream | ||
from streamlink.stream.http import HTTPStream | ||
from streamlink.utils.url import update_scheme | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
@pluginmatcher(re.compile( | ||
r"https?://(?:\w+\.)*sportschau\.de/", | ||
)) | ||
class Sportschau(Plugin): | ||
def _get_streams(self): | ||
player_js = self.session.http.get(self.url, schema=validate.Schema( | ||
re.compile(r"https?:(//deviceids-medp.wdr.de/ondemand/\S+\.js)"), | ||
validate.none_or_all( | ||
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.regex(re.compile(r"\$mediaObject\.jsonpHelper\.storeAndPlay\(({.+})\);?")), | ||
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"))) | ||
|
||
|
||
__plugin__ = Sportschau |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
""" | ||
$description Global live streaming platform. | ||
$url ssh101.com | ||
$type live | ||
""" | ||
|
||
import logging | ||
import re | ||
|
||
from streamlink.plugin import Plugin, pluginmatcher | ||
from streamlink.plugin.api import validate | ||
from streamlink.stream.hls import HLSStream | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
@pluginmatcher(re.compile( | ||
r"https?://(?:www\.)?ssh101\.com/(?:(?:secure)?live/|detail\.php\?id=\w+)", | ||
)) | ||
class SSH101(Plugin): | ||
def _get_streams(self): | ||
hls_url = self.session.http.get(self.url, schema=validate.Schema( | ||
validate.parse_html(), | ||
validate.xml_xpath_string(".//source[contains(@src,'.m3u8')]/@src"), | ||
)) | ||
if not hls_url: | ||
return | ||
|
||
res = self.session.http.get(hls_url, acceptable_status=(200, 403, 404)) | ||
if res.status_code != 200 or len(res.text) <= 10: | ||
log.error("This stream is currently offline") | ||
return | ||
|
||
return {"live": HLSStream(self.session, hls_url)} | ||
|
||
|
||
__plugin__ = SSH101 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
""" | ||
$description Sporting live stream and video content, owned by Silver Chalice and Sinclair Broadcast Group. | ||
$url watchstadium.com | ||
$type live, vod | ||
""" | ||
|
||
import logging | ||
import re | ||
|
||
from streamlink.plugin import Plugin, PluginError, pluginmatcher | ||
from streamlink.plugin.api import validate | ||
from streamlink.stream.hls import HLSStream | ||
from streamlink.utils.url import update_qsd | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
@pluginmatcher(re.compile( | ||
r"https?://(?:www\.)?watchstadium\.com/", | ||
)) | ||
class Stadium(Plugin): | ||
_API_URL = "https://edge.api.brightcove.com/playback/v1/accounts/{data_account}/videos/{data_video_id}" | ||
_PLAYER_URL = "https://players.brightcove.net/{data_account}/{data_player}_default/index.min.js" | ||
|
||
def _get_streams(self): | ||
try: | ||
data = self.session.http.get(self.url, schema=validate.Schema( | ||
validate.parse_html(), | ||
validate.xml_find(".//video[@id='brightcove_video_player']"), | ||
validate.union_get("data-video-id", "data-account", "data-ad-config-id", "data-player"), | ||
)) | ||
except PluginError: | ||
return | ||
data_video_id, data_account, data_ad_config_id, data_player = data | ||
|
||
url = self._PLAYER_URL.format(data_account=data_account, data_player=data_player) | ||
policy_key = self.session.http.get(url, schema=validate.Schema( | ||
re.compile(r"""options:\s*{.+policyKey:\s*"([^"]+)""", re.DOTALL), | ||
validate.any(None, validate.get(1)), | ||
)) | ||
if not policy_key: | ||
return | ||
|
||
url = self._API_URL.format(data_account=data_account, data_video_id=data_video_id) | ||
if data_ad_config_id is not None: | ||
url = update_qsd(url, dict(ad_config_id=data_ad_config_id)) | ||
|
||
streams = self.session.http.get( | ||
url, | ||
headers={"Accept": f"application/json;pk={policy_key}"}, | ||
schema=validate.Schema( | ||
validate.parse_json(), | ||
{ | ||
"sources": [{ | ||
validate.optional("type"): str, | ||
"src": validate.url(), | ||
}], | ||
}, | ||
validate.get("sources"), | ||
validate.filter(lambda source: source.get("type") == "application/x-mpegURL"), | ||
), | ||
) | ||
|
||
for stream in streams: | ||
return HLSStream.parse_variant_playlist(self.session, stream["src"]) | ||
|
||
|
||
__plugin__ = Stadium |
Oops, something went wrong.