Closed dexter101010 closed 5 years ago
It seems that this m3u8 link requires decrypt key from URI k/timestamp
However https://cdn.spayee.in/spees/w/o/5b49b8f2e4b02ac9d5e71945/v/5bcd586ee4b04b639bfddcf2/u/5c28ab6fe4b0efa6ebda1830/t/857c9994539db0b48bd818abaa6bcaaa/p/assets/videos/2018/10/22/5bcd586ee4b04b639bfddcf2/k/timestamp
just return 200 ok with no content.
So maybe this site has some protection or authorization for this link.
It seems that this m3u8 link requires decrypt key from URI
k/timestamp
Howeverhttps://cdn.spayee.in/spees/w/o/5b49b8f2e4b02ac9d5e71945/v/5bcd586ee4b04b639bfddcf2/u/5c28ab6fe4b0efa6ebda1830/t/857c9994539db0b48bd818abaa6bcaaa/p/assets/videos/2018/10/22/5bcd586ee4b04b639bfddcf2/k/timestamp
just return 200 ok with no content.So maybe this site has some protection or authorization for this link.
Thank you for your answer. I have the credentials for login and the cookies but i don't know how to use pass them to streamlink.
Thanks!
You could try --http-cookie to pass your cookies.
You could try --http-cookie to pass your cookies.
I've tried but still get the error :
streamlink --http-cookie "Cookie: c_user=4d8ab70dea91890fae57afacd83b3432zxYzzdoJteLK783PZ4YB8zbeZ6rx6cAs1Tb5U/+u80KxpJ36d84V1bqZ4KhkwjRhe1bb63beb815d54c46d3fa02da3e6eed; c_p=daf2bebbba9bb71895658b8cddfe367aRuD4Po96H8HHa9/arUGIvA==efc0aa751a4cc28541b34fd3b8ffb9ae; id=0eff6a49-1374-4913-90b7-77482d73fd8e; _ga=GA1.2.970484282.1546776087; JSESSIONID=FE882976C062C66271CEBCF437FE4B6E; __extfc=1" https://cdn.spayee.in/spees/w/o/5b49b8f2e4b02ac9d5e71945/v/5bf7d067e4b068ec781593db/u/5c28ab6fe4b0efa6ebda1830/t/6316a8da0fb034daa0bd5d745ccb12f7/p/assets/videos/2018/11/23/5bf7d067e4b068ec781593db/hls_1M_.m3u8 best [cli][info] Found matching plugin hls for URL https://cdn.spayee.in/spees/w/o/5b49b8f2e4b02ac9d5e71945/v/5bf7d067e4b068ec781593db/u/5c28ab6fe4b0efa6ebda1830/t/6316a8da0fb034daa0bd5d745ccb12f7/p/assets/videos/2018/11/23/5bf7d067e4b068ec781593db/hls_1M_.m3u8 [cli][info] Available streams: live (worst, best) [cli][info] Opening stream: live (hls) Exception in thread Thread-HLSStreamWriter: Traceback (most recent call last): File "c:\python3\lib\threading.py", line 917, in _bootstrap_inner self.run() File "c:\python3\lib\site-packages\streamlink\stream\segmented.py", line 167, in run self.write(segment, result) File "c:\python3\lib\site-packages\streamlink\stream\hls.py", line 119, in write sequence.num) File "c:\python3\lib\site-packages\streamlink\stream\hls.py", line 75, in create_decryptor return AES.new(self.key_data, AES.MODE_CBC, iv) File "c:\python3\lib\site-packages\Crypto\Cipher\AES.py", line 232, in new return _create_cipher(sys.modules[name], key, mode, *args, kwargs) File "c:\python3\lib\site-packages\Crypto\Cipher__init__.py", line 79, in _create_cipher return modes[mode](factory, kwargs) File "c:\python3\lib\site-packages\Crypto\Cipher_mode_cbc.py", line 274, in _create_cbc_cipher cipher_state = factory._create_base_cipher(kwargs) File "c:\python3\lib\site-packages\Crypto\Cipher\AES.py", line 93, in _create_base_cipher raise ValueError("Incorrect AES key length (%d bytes)" % len(key)) ValueError: Incorrect AES key length (48 bytes)
Thanks!
After some investigation, I found that i provided a wrong anwser before.
Here's update:
AES-128 's key is 128 bit == 16 bytes.
However streamlink 's log show that the key is 48bytes
ValueError: Incorrect AES key length (48 bytes)
So this site encrypts the key.
Found encrypt method in /resources/scripts/scoursePlayer.js
az.load = function (aB, aA, aC) {
var aE = [
'/key',
'endsWith',
'url',
'/timestamp',
'onSuccess',
'data',
'subarray',
'parse',
'u8array',
'enc',
'ECB',
'mode',
'NoPadding',
'pad',
'decrypt',
'AES',
'stringify',
'buffer'
];
if (aB[aE[2]][aE[1]](aE[0]) || aB[aE[2]][aE[1]](aE[3])) {
var aD = aC[aE[4]];
aC[aE[4]] = function (aK, aJ, aI) {
var aH = new Uint8Array(aK[aE[5]]);
var aG = aH[aE[6]](0, 16),
aF = aH[aE[6]](32, 48);
aH = cjs[aE[15]][aE[14]](convertArrayToBase64(aG), cjs[aE[9]][aE[8]][aE[7]](aF), {
mode: cjs[aE[11]][aE[10]],
padding: cjs[aE[13]][aE[12]]
});
aH = cjs[aE[9]][aE[8]][aE[16]](cjs[aE[15]][aE[14]](convertArrayToBase64(aF), aH, {
mode: cjs[aE[11]][aE[10]],
padding: cjs[aE[13]][aE[12]]
}));
aK[aE[5]] = aH[aE[17]];
aD(aK, aJ, aI)
}
}
ay(aB, aA, aC)
};
After some simple deobufscation
var aH = new Uint8Array(resp.data);
var aG = aH[subarray](0, 16),
aF = aH[subarray](32, 48);
aH = cjs[aes.decrypt](convertArrayToBase64(aG), cjs[enc.u8array.parse](aF), {
mode: cjs[mode.ecb],
padding: cjs[pad.nopadding]
});
aH = cjs[enc.u8array.stringify](cjs[aes.decrypt](convertArrayToBase64(aF), aH, {
mode: cjs[mode.ecb],
padding: cjs[pad.nopadding]
}));
resp.data = aH[buffer];
So you may need to write a plugin for this site and override create_decryptor
function to get real key.
After some investigation, I found that i provided a wrong anwser before.
Here's update:
AES-128 's key is 128 bit == 16 bytes. However streamlink 's log show that the key is 48bytes
ValueError: Incorrect AES key length (48 bytes)
So this site encrypts the key.Found encrypt method in
/resources/scripts/scoursePlayer.js
az.load = function (aB, aA, aC) { var aE = [ '/key', 'endsWith', 'url', '/timestamp', 'onSuccess', 'data', 'subarray', 'parse', 'u8array', 'enc', 'ECB', 'mode', 'NoPadding', 'pad', 'decrypt', 'AES', 'stringify', 'buffer' ]; if (aB[aE[2]][aE[1]](aE[0]) || aB[aE[2]][aE[1]](aE[3])) { var aD = aC[aE[4]]; aC[aE[4]] = function (aK, aJ, aI) { var aH = new Uint8Array(aK[aE[5]]); var aG = aH[aE[6]](0, 16), aF = aH[aE[6]](32, 48); aH = cjs[aE[15]][aE[14]](convertArrayToBase64(aG), cjs[aE[9]][aE[8]][aE[7]](aF), { mode: cjs[aE[11]][aE[10]], padding: cjs[aE[13]][aE[12]] }); aH = cjs[aE[9]][aE[8]][aE[16]](cjs[aE[15]][aE[14]](convertArrayToBase64(aF), aH, { mode: cjs[aE[11]][aE[10]], padding: cjs[aE[13]][aE[12]] })); aK[aE[5]] = aH[aE[17]]; aD(aK, aJ, aI) } } ay(aB, aA, aC) };
After some simple deobufscation
var aH = new Uint8Array(resp.data); var aG = aH[subarray](0, 16), aF = aH[subarray](32, 48); aH = cjs[aes.decrypt](convertArrayToBase64(aG), cjs[enc.u8array.parse](aF), { mode: cjs[mode.ecb], padding: cjs[pad.nopadding] }); aH = cjs[enc.u8array.stringify](cjs[aes.decrypt](convertArrayToBase64(aF), aH, { mode: cjs[mode.ecb], padding: cjs[pad.nopadding] })); resp.data = aH[buffer];
So you may need to write a plugin for this site and override
create_decryptor
function to get real key.
Thanks for your help and answer. Anyway i am not a programmer. I am just a network engineer.Maybe someone smarter than me will be able to write that plugin. I wish that...
A simple plugin implemention
import re
import logging
from Crypto.Cipher import AES
from streamlink import StreamError
from streamlink.plugin import Plugin
from streamlink.stream import HLSStream
from streamlink.stream.hls import HLSStreamWriter, HLSStreamReader
log = logging.getLogger(__name__)
class SpayeeStreamWriter(HLSStreamWriter):
def _decrypt_key(self,data):
tmp1 = data[0:16]
tmp2 = data[32:48]
dec1 = AES.new(tmp2,AES.MODE_ECB)
tmp3 = dec1.decrypt(tmp1)
dec2 = AES.new(tmp3,AES.MODE_ECB)
return dec2.decrypt(tmp2)
def create_decryptor(self, key, sequence):
if key.method != "AES-128":
raise StreamError("Unable to decrypt cipher {0}", key.method)
if not self.key_uri_override and not key.uri:
raise StreamError("Missing URI to decryption key")
key_uri = self.key_uri_override if self.key_uri_override else key.uri
if self.key_uri != key_uri:
res = self.session.http.get(key_uri, exception=StreamError,
retries=self.retries,
**self.reader.request_params)
res.encoding = "binary/octet-stream"
self.key_data = self._decrypt_key(res.content)
self.key_uri = key_uri
iv = key.iv or num_to_iv(sequence)
# Pad IV if needed
iv = b"\x00" * (16 - len(iv)) + iv
return AES.new(self.key_data, AES.MODE_CBC, iv)
class SpayeeStreamReader(HLSStreamReader):
__writer__ = SpayeeStreamWriter
class SpayeeStream(HLSStream):
def open(self):
reader = SpayeeStreamReader(self)
reader.open()
return reader
class Spayee(Plugin):
url_re = re.compile(r"""https://cdn.spayee.in/.*.m3u8""")
def __init__(self, url):
super(Spayee, self).__init__(url)
@classmethod
def can_handle_url(cls, url):
return cls.url_re.match(url) is not None
def _get_streams(self):
return {"live":SpayeeStream(self.session,self.url)}
__plugin__ = Spayee
save it to streamlink\plugins\spayee.py
Only tested under python 2.7
A simple plugin implemention
import re import logging from Crypto.Cipher import AES from streamlink import StreamError from streamlink.plugin import Plugin from streamlink.stream import HLSStream from streamlink.stream.hls import HLSStreamWriter, HLSStreamReader log = logging.getLogger(__name__) class SpayeeStreamWriter(HLSStreamWriter): def _decrypt_key(self,data): tmp1 = data[0:16] tmp2 = data[32:48] dec1 = AES.new(tmp2,AES.MODE_ECB) tmp3 = dec1.decrypt(tmp1) dec2 = AES.new(tmp3,AES.MODE_ECB) return dec2.decrypt(tmp2) def create_decryptor(self, key, sequence): if key.method != "AES-128": raise StreamError("Unable to decrypt cipher {0}", key.method) if not self.key_uri_override and not key.uri: raise StreamError("Missing URI to decryption key") key_uri = self.key_uri_override if self.key_uri_override else key.uri if self.key_uri != key_uri: res = self.session.http.get(key_uri, exception=StreamError, retries=self.retries, **self.reader.request_params) res.encoding = "binary/octet-stream" self.key_data = self._decrypt_key(res.content) self.key_uri = key_uri iv = key.iv or num_to_iv(sequence) # Pad IV if needed iv = b"\x00" * (16 - len(iv)) + iv return AES.new(self.key_data, AES.MODE_CBC, iv) class SpayeeStreamReader(HLSStreamReader): __writer__ = SpayeeStreamWriter class SpayeeStream(HLSStream): def open(self): reader = SpayeeStreamReader(self) reader.open() return reader class Spayee(Plugin): url_re = re.compile(r"""https://cdn.spayee.in/.*.m3u8""") def __init__(self, url): super(Spayee, self).__init__(url) @classmethod def can_handle_url(cls, url): return cls.url_re.match(url) is not None def _get_streams(self): return {"live":SpayeeStream(self.session,self.url)} __plugin__ = Spayee
save it to streamlink\plugins\spayee.py
Only tested under python 2.7
Thanks a lot sir. I hope it works. I will test it and i will come back with a reply to you.Thanks again for a million times.
A simple plugin implemention
import re import logging from Crypto.Cipher import AES from streamlink import StreamError from streamlink.plugin import Plugin from streamlink.stream import HLSStream from streamlink.stream.hls import HLSStreamWriter, HLSStreamReader log = logging.getLogger(__name__) class SpayeeStreamWriter(HLSStreamWriter): def _decrypt_key(self,data): tmp1 = data[0:16] tmp2 = data[32:48] dec1 = AES.new(tmp2,AES.MODE_ECB) tmp3 = dec1.decrypt(tmp1) dec2 = AES.new(tmp3,AES.MODE_ECB) return dec2.decrypt(tmp2) def create_decryptor(self, key, sequence): if key.method != "AES-128": raise StreamError("Unable to decrypt cipher {0}", key.method) if not self.key_uri_override and not key.uri: raise StreamError("Missing URI to decryption key") key_uri = self.key_uri_override if self.key_uri_override else key.uri if self.key_uri != key_uri: res = self.session.http.get(key_uri, exception=StreamError, retries=self.retries, **self.reader.request_params) res.encoding = "binary/octet-stream" self.key_data = self._decrypt_key(res.content) self.key_uri = key_uri iv = key.iv or num_to_iv(sequence) # Pad IV if needed iv = b"\x00" * (16 - len(iv)) + iv return AES.new(self.key_data, AES.MODE_CBC, iv) class SpayeeStreamReader(HLSStreamReader): __writer__ = SpayeeStreamWriter class SpayeeStream(HLSStream): def open(self): reader = SpayeeStreamReader(self) reader.open() return reader class Spayee(Plugin): url_re = re.compile(r"""https://cdn.spayee.in/.*.m3u8""") def __init__(self, url): super(Spayee, self).__init__(url) @classmethod def can_handle_url(cls, url): return cls.url_re.match(url) is not None def _get_streams(self): return {"live":SpayeeStream(self.session,self.url)} __plugin__ = Spayee
save it to streamlink\plugins\spayee.py
Only tested under python 2.7
Here is what i get :
streamlink --http-cookie "Cookie: c_user=2c6bf6dbacac303d72edcc5cd38afafdXfOIISNZp8b40r2V2xCU6tsulxvffMqoWxgi5x4HLPzJrZox1UvVTuPk66RrSjrJdf5c366881e766b6e88ba03343e10dc2; c_p=82e07fa2298c41ff73f6d4137998d90auPgDJ0EfI6id4IwhiuRSQQ==43d466565a11448f52fd7671a78e6004; id=0eff6a49-1374-4913-90b7-77482d73fd8e; _ga=GA1.2.970484282.1546776087; JSESSIONID=7C53A52AF3CBD3ECD89B346F710E7373; __extfc=1" https://cdn.spayee.in/spees/w/o/5b49b8f2e4b02ac9d5e71945/v/5bf7d067e4b068ec781593db/u/5c28ab6fe4b0efa6ebda1830/t/f8a99530b420bd8a80f939b023a83794/p/assets/videos/2018/11/23/5bf7d067e4b068ec781593db/hls_350k_.m3u8 best [cli][info] Found matching plugin spayee for URL https://cdn.spayee.in/spees/w/o/5b49b8f2e4b02ac9d5e71945/v/5bf7d067e4b068ec781593db/u/5c28ab6fe4b0efa6ebda1830/t/f8a99530b420bd8a80f939b023a83794/p/assets/videos/2018/11/23/5bf7d067e4b068ec781593db/hls_350k_.m3u8 [cli][info] Available streams: live (worst, best) [cli][info] Opening stream: live (hls) Exception in thread Thread-SpayeeStreamWriter: Traceback (most recent call last): File "threading.py", line 914, in _bootstrap_inner File "C:\Program Files (x86)\Streamlink\pkgs\streamlink\stream\segmented.py", line 167, in run self.write(segment, result) File "C:\Program Files (x86)\Streamlink\pkgs\streamlink\stream\hls.py", line 119, in write sequence.num) File "C:\Program Files (x86)\Streamlink\pkgs\streamlink\plugins\spayee.py", line 26, in create_decryptor if not self.key_uri_override and not key.uri: AttributeError: 'SpayeeStreamWriter' object has no attribute 'key_uri_override'
[cli][error] Try 1/1: Could not open stream <HLSStream('https://cdn.spayee.in/spees/w/o/5b49b8f2e4b02ac9d5e71945/v/5bf7d067e4b068ec781593db/u/5c28ab6fe4b0efa6ebda1830/t/f8a99530b420bd8a80f939b023a83794/p/assets/videos/2018/11/23/5bf7d067e4b068ec781593db/hls_350k_.m3u8')> (Failed to read data from stream: Read timeout) error: Could not open stream <HLSStream('https://cdn.spayee.in/spees/w/o/5b49b8f2e4b02ac9d5e71945/v/5bf7d067e4b068ec781593db/u/5c28ab6fe4b0efa6ebda1830/t/f8a99530b420bd8a80f939b023a83794/p/assets/videos/2018/11/23/5bf7d067e4b068ec781593db/hls_350k_.m3u8')>, tried 1 times, exiting [cli][info] Closing currently open stream...
I am using streamlink 0.14.2 and Python 3.7.2 also i've tried with python 2.7.0
Thanks!
You'd better using the lastest streamlink (branch master
) from github instead of windows installer version. And i tested that it also works under python 3.
You'd better using the lastest streamlink (branch
master
) from github instead of windows installer version. And i tested that it also works under python 3.
Thank you man! I will do that. Thanks again!
I will be great @dexter101010 if you do a video
You'd better using the lastest streamlink (branch
master
) from github instead of windows installer version. And i tested that it also works under python 3.
This doesn't work. I have tested, its not working. Can you please help?
You'd better using the lastest streamlink (branch
master
) from github instead of windows installer version. And i tested that it also works under python 3.Thank you man! I will do that. Thanks again!
Have you tried it? Is it working for you?
You'd better using the lastest streamlink (branch
master
) from github instead of windows installer version. And i tested that it also works under python 3.Thank you man! I will do that. Thanks again!
Can you help me? @dexter101010 I'm stuck with the same issue.
Any update on this one? I have same issue with same domain, perhaps need to apply plugin manually if that is not automatically applied.
@jackyzy823 Can this Spayee plugin you wrote above be updated possibly? I have a qcdn.spayee.in m3u8 and have updated the plugin with a qcdn.spayee return but it still errors as so:
[session][info] Resolved plugin spayee with deprecated can_handle_url API [cli][info] Found matching plugin spayee for URL https://qcdn.spayee.in/spees/w/o/xxxxxxxxxxxx/index.m3u8 [cli][info] Available streams: live (worst, best) [cli][info] Opening stream: live (hls) [cli][info] Starting player: "C:\Program Files\VideoLAN\VLC\vlc.exe" [stream.hls][error] Attempted to play a variant playlist, use 'hls://https://qcdn.spayee.in/spees/w/o/xxxxxxxxxxxxxx/index.m3u8' instead [cli][error] Try 1/1: Could not open stream <HLSStream('https://qcdn.spayee.in/spees/w/o/xxxxxxxxxxxxx/index.m3u8', None)> (No data returned from stream) error: Could not open stream <HLSStream('https://qcdn.spayee.in/spees/w/o/xxxxxxxxxxxxxxxx/index.m3u8', None)>, tried 1 times, exiting [cli][info] Closing currently open stream...
Though when I copy paste the m3u8 link that says no data returned it starts downloading the m3u8 in my browser and its a valid m3u8. Any way this could possibly be updated? I can send you the m3u8 and key file if you need so.
Thanks!
the decrypt_key method is changed. (Note: pseudocode)
def _decrypt_key(self,data):
tmp1 = data[0:16]
tmp2 = data[32:48]
dec1 = AES.new(base64.b64decode(spka),AES.MODE_ECB)
tmp3 = dec1.decrypt(tmp1)
dec2 = AES.new(tmp3,AES.MODE_ECB)
return dec2.decrypt(tmp2)
And the spka key is from web page's javascript and may be dynamically generated.
Sample
<script type="text/javascript" id="dsf239df">
var ctx = "/s",
isFirstLogin = "", cjs = CryptoJS;
var defaultCoreColor = "#5755d9", theme1CoreColor = "#572b7a", theme2CoreColor = "#3f51b5", theme3CoreColor = "#009051",
theme4CoreColor = "#596439", theme5CoreColor = "#F0591D", theme6CoreColor = "#28a745", theme7CoreColor = "#1bbc9b",
theme8CoreColor = "#f38f20", theme9CoreColor = "#c0af01", theme10CoreColor = "#e8d3a4", spka = "YjM3ZGVhNWU4N2I1MTI2Yw==",
webColor = defaultCoreColor,
spka = "YjM3ZGVhNWU4N2I1MTI2Yw=="
You can make a option like "--spayee-spka=xxx" to pass spka key to the this plugin.
Hello all,
I have the following problem when i am trying to download an encrypted m3u8 link(AES 128) :
I hope somebody from here can help me.
Thanks!