mirror of https://github.com/streamlink/streamlink
176 lines
5.4 KiB
Python
176 lines
5.4 KiB
Python
import re
|
|
|
|
from streamlink.plugin import Plugin
|
|
from streamlink.plugin import PluginArguments, PluginArgument
|
|
from streamlink.plugin.api import validate
|
|
from streamlink.stream import HLSStream
|
|
|
|
CHANNEL_API_URL = "http://live.afreecatv.com:8057/afreeca/player_live_api.php"
|
|
STREAM_INFO_URLS = "{rmd}/broad_stream_assign.html"
|
|
|
|
CHANNEL_RESULT_ERROR = 0
|
|
CHANNEL_RESULT_OK = 1
|
|
|
|
QUALITYS = ["original", "hd", "sd"]
|
|
|
|
QUALITY_WEIGHTS = {
|
|
"original": 1080,
|
|
"hd": 720,
|
|
"sd": 480
|
|
}
|
|
|
|
_url_re = re.compile(r"https?://play\.afreecatv\.com/(?P<username>\w+)(?:/\d+)?")
|
|
|
|
_channel_schema = validate.Schema(
|
|
{
|
|
"CHANNEL": {
|
|
"RESULT": validate.transform(int),
|
|
validate.optional("BPWD"): validate.text,
|
|
validate.optional("BNO"): validate.text,
|
|
validate.optional("RMD"): validate.text,
|
|
validate.optional("AID"): validate.text,
|
|
validate.optional("CDN"): validate.text
|
|
}
|
|
},
|
|
validate.get("CHANNEL")
|
|
)
|
|
|
|
_stream_schema = validate.Schema(
|
|
{
|
|
validate.optional("view_url"): validate.url(
|
|
scheme=validate.any("rtmp", "http")
|
|
),
|
|
"stream_status": validate.text
|
|
}
|
|
)
|
|
|
|
|
|
class AfreecaTV(Plugin):
|
|
login_url = "https://member.afreecatv.com:8111/login/LoginAction.php"
|
|
|
|
arguments = PluginArguments(
|
|
PluginArgument(
|
|
"username",
|
|
requires=["password"],
|
|
metavar="USERNAME",
|
|
help="The username used to register with afreecatv.com."
|
|
),
|
|
PluginArgument(
|
|
"password",
|
|
sensitive=True,
|
|
metavar="PASSWORD",
|
|
help="A afreecatv.com account password to use with --afreeca-username."
|
|
)
|
|
)
|
|
|
|
@classmethod
|
|
def can_handle_url(self, url):
|
|
return _url_re.match(url)
|
|
|
|
@classmethod
|
|
def stream_weight(cls, key):
|
|
weight = QUALITY_WEIGHTS.get(key)
|
|
if weight:
|
|
return weight, "afreeca"
|
|
|
|
return Plugin.stream_weight(key)
|
|
|
|
def _get_channel_info(self, username):
|
|
data = {
|
|
"bid": username,
|
|
"mode": "landing",
|
|
"player_type": "html5"
|
|
}
|
|
|
|
res = self.session.http.post(CHANNEL_API_URL, data=data)
|
|
return self.session.http.json(res, schema=_channel_schema)
|
|
|
|
def _get_hls_key(self, broadcast, username, quality):
|
|
data = {
|
|
"bid": username,
|
|
"bno": broadcast,
|
|
"pwd": "",
|
|
"quality": quality,
|
|
"type": "pwd"
|
|
}
|
|
res = self.session.http.post(CHANNEL_API_URL, data=data)
|
|
return self.session.http.json(res, schema=_channel_schema)
|
|
|
|
def _get_stream_info(self, broadcast, quality, cdn, rmd):
|
|
params = {
|
|
"return_type": cdn,
|
|
"broad_key": "{broadcast}-flash-{quality}-hls".format(**locals())
|
|
}
|
|
res = self.session.http.get(STREAM_INFO_URLS.format(rmd=rmd), params=params)
|
|
return self.session.http.json(res, schema=_stream_schema)
|
|
|
|
def _get_hls_stream(self, broadcast, username, quality, cdn, rmd):
|
|
keyjson = self._get_hls_key(broadcast, username, quality)
|
|
|
|
if keyjson["RESULT"] != CHANNEL_RESULT_OK:
|
|
return
|
|
key = keyjson["AID"]
|
|
|
|
info = self._get_stream_info(broadcast, quality, cdn, rmd)
|
|
|
|
if "view_url" in info:
|
|
return HLSStream(self.session, info["view_url"], params=dict(aid=key))
|
|
|
|
def _login(self, username, password):
|
|
data = {
|
|
"szWork": "login",
|
|
"szType": "json",
|
|
"szUid": username,
|
|
"szPassword": password,
|
|
"isSaveId": "true",
|
|
"isSavePw": "false",
|
|
"isSaveJoin": "false"
|
|
}
|
|
|
|
res = self.session.http.post(self.login_url, data=data)
|
|
res = self.session.http.json(res)
|
|
if res["RESULT"] == 1:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def _get_streams(self):
|
|
self.session.http.headers.update({"Referer": self.url})
|
|
if not self.session.get_option("hls-segment-ignore-names"):
|
|
ignore_segment = ["preloading"]
|
|
self.session.set_option("hls-segment-ignore-names", ignore_segment)
|
|
|
|
login_username = self.get_option("username")
|
|
login_password = self.get_option("password")
|
|
if login_username and login_password:
|
|
self.logger.debug("Attempting login as {0}".format(login_username))
|
|
if self._login(login_username, login_password):
|
|
self.logger.info("Successfully logged in as {0}".format(login_username))
|
|
else:
|
|
self.logger.info("Failed to login as {0}".format(login_username))
|
|
|
|
match = _url_re.match(self.url)
|
|
username = match.group("username")
|
|
|
|
channel = self._get_channel_info(username)
|
|
if channel.get("BPWD") == "Y":
|
|
self.logger.error("Stream is Password-Protected")
|
|
return
|
|
elif channel.get("RESULT") == -6:
|
|
self.logger.error("Login required")
|
|
return
|
|
elif channel.get("RESULT") != CHANNEL_RESULT_OK:
|
|
return
|
|
|
|
(broadcast, rmd, cdn) = (channel["BNO"], channel["RMD"], channel["CDN"])
|
|
if not (broadcast and rmd and cdn):
|
|
return
|
|
|
|
for qkey in QUALITYS:
|
|
hls_stream = self._get_hls_stream(broadcast, username, qkey, cdn, rmd)
|
|
if hls_stream:
|
|
yield qkey, hls_stream
|
|
|
|
|
|
__plugin__ = AfreecaTV
|