-
-
Save intact/3d6af5f361c1a44fd878 to your computer and use it in GitHub Desktop.
import base64 | |
import json | |
import random | |
import re | |
import time | |
try: | |
from Crypto import Random | |
from Crypto.Cipher import AES, PKCS1_v1_5 | |
from Crypto.PublicKey import RSA | |
from Crypto.Util import number | |
HAS_CRYPTO = True | |
except ImportError as e: | |
HAS_CRYPTO = False | |
crypto_import_exception = str(e) | |
from livestreamer.compat import urljoin, urlparse, urlunparse | |
from livestreamer.exceptions import PluginError | |
from livestreamer.plugin import Plugin | |
from livestreamer.plugin.api import http, validate | |
from livestreamer.plugin.api.utils import parse_json | |
from livestreamer.stream import HLSStream | |
HDCORE_VERSION="3.2.0" | |
_url_re = re.compile(r"https?://www.daisuki.net/[^/]+/[^/]+/anime/watch\..+") | |
_flashvars_re = re.compile(r"var\s+flashvars\s*=\s*{([^}]*?)};", re.DOTALL) | |
_flashvar_re = re.compile(r"""(['"])(.*?)\1\s*:\s*(['"])(.*?)\3""") | |
_clientlibs_re = re.compile(r"""<script.*?src=(['"])(.*?/clientlibs_anime_watch.*?\.js)\1""") | |
_schema = validate.Schema( | |
validate.union({ | |
"flashvars": validate.all( | |
validate.transform(_flashvars_re.search), | |
validate.get(1), | |
validate.transform(_flashvar_re.findall), | |
validate.map(lambda v: (v[1], v[3])), | |
validate.transform(dict), | |
{ | |
"s": validate.text, | |
"country": validate.text, | |
"init": validate.text, | |
validate.optional("ss_id"): validate.text, | |
validate.optional("mv_id"): validate.text, | |
validate.optional("device_cd"): validate.text, | |
validate.optional("ss1_prm"): validate.text, | |
validate.optional("ss2_prm"): validate.text, | |
validate.optional("ss3_prm"): validate.text | |
} | |
), | |
"clientlibs": validate.all( | |
validate.transform(_clientlibs_re.search), | |
validate.get(2), | |
validate.text | |
) | |
}) | |
) | |
_language_schema = validate.Schema( | |
validate.xml_findtext("./country_code") | |
) | |
_init_schema = validate.Schema( | |
{ | |
"rtn": validate.all( | |
validate.text | |
) | |
}, | |
validate.get("rtn") | |
) | |
def aes_encrypt(key, plaintext): | |
plaintext = plaintext.encode("utf-8") | |
aes = AES.new(key, AES.MODE_CBC, number.long_to_bytes(0, AES.block_size)) | |
if len(plaintext) % AES.block_size != 0: | |
plaintext += b"\0" * (AES.block_size - len(plaintext) % AES.block_size) | |
return base64.b64encode(aes.encrypt(plaintext)) | |
def aes_decrypt(key, ciphertext): | |
aes = AES.new(key, AES.MODE_CBC, number.long_to_bytes(0, AES.block_size)) | |
plaintext = aes.decrypt(base64.b64decode(ciphertext)) | |
plaintext = plaintext.strip(b"\0") | |
return plaintext.decode("utf-8") | |
def rsa_encrypt(key, plaintext): | |
pubkey = RSA.importKey(key) | |
cipher = PKCS1_v1_5.new(pubkey) | |
return base64.b64encode(cipher.encrypt(plaintext)) | |
def get_public_key(cache, url): | |
headers = {} | |
cached = cache.get("clientlibs") | |
if cached and cached["url"] == url: | |
headers["If-Modified-Since"] = cached["modified"] | |
script = http.get(url, headers=headers) | |
if cached and script.status_code == 304: | |
return cached["pubkey"] | |
modified = script.headers.get("Last-Modified", "") | |
match = re.search(r"""\"(-----BEGIN PUBLIC KEY-----[^"]*?-----END PUBLIC KEY-----)\"""", script.text, re.DOTALL) | |
if match is None: | |
return None | |
pubkey = match.group(1).replace("\\n", "\n") | |
cache.set("clientlibs", dict(url=url, modified=modified, pubkey=pubkey)) | |
return pubkey | |
class Daisuki(Plugin): | |
@classmethod | |
def can_handle_url(cls, url): | |
return _url_re.match(url) | |
def _get_streams(self): | |
if not HAS_CRYPTO: | |
raise PluginError("pyCrypto needs to be installed (exception: {0})".format(crypto_import_exception)) | |
page = http.get(self.url, schema=_schema) | |
if not page: | |
return | |
pubkey_pem = get_public_key(self.cache, urljoin(self.url, page["clientlibs"])) | |
if not pubkey_pem: | |
raise PluginError("Unable to get public key") | |
flashvars = page["flashvars"] | |
params = { | |
"cashPath":int(time.time()*1000) | |
} | |
res = http.get(urljoin(self.url, flashvars["country"]), params=params) | |
if not res: | |
return | |
language = http.xml(res, schema=_language_schema) | |
api_params = {} | |
for key in ("ss_id", "mv_id", "device_cd", "ss1_prm", "ss2_prm", "ss3_prm"): | |
if flashvars.get(key, ""): | |
api_params[key] = flashvars[key] | |
aeskey = number.long_to_bytes(random.getrandbits(8*32), 32) | |
params = { | |
"s": flashvars["s"], | |
"c": language, | |
"e": self.url, | |
"d": aes_encrypt(aeskey, json.dumps(api_params)), | |
"a": rsa_encrypt(pubkey_pem, aeskey) | |
} | |
res = http.get(urljoin(self.url, flashvars["init"]), params=params) | |
if not res: | |
return | |
rtn = http.json(res, schema=_init_schema) | |
if not rtn: | |
return | |
init_data = parse_json(aes_decrypt(aeskey, rtn)) | |
parsed = urlparse(init_data["play_url"]) | |
if parsed.scheme != "https" or not parsed.path.startswith("/i/") or not parsed.path.endswith("/master.m3u8"): | |
return | |
hlsstream_url = init_data["play_url"] | |
if "caption_url" in init_data: | |
self.logger.info("Subtitles: {0}".format(init_data["caption_url"])) | |
return HLSStream.parse_variant_playlist(self.session, hlsstream_url) | |
__plugin__ = Daisuki |
@otaru1921 try new version
im having issues with this plugin. when I have the script in the right location, python 2.7 installed, and pycrypto 2.6 for python 2.7 properly installed, but when I copy-paste any daisuki url thru livestreamer, I get an error of "pyCrypto needs to be installed (exception: cannot import name Random)". Not sure what I am doing wrong. Is there a known version that works better than another?
@zaockle Livestreamer contains incomplete pyCrypto
got the same error as zaockle tried the fix above now i get
pyCrypto needs to be installed (exception: cannot import name winrandom)
You need compiled pyCrypto library. You can extract Crypto folder from pycrypto-2.6.1.win32-py2.7.exe (you can use p7zip)
would the pre-compiled files from here work?
http://www.voidspace.org.uk/python/modules.shtml#pycrypto
I have windows 10 64bit.
python 2.7.5 64bit
You can try pycrypto-2.6.1.win-amd64-py2.7.exe
Is is possible to seek? I tried --player-passthrough hls with no luck, mpv and VLC simply does not run.
Seeking is not supported for Akamai streams.
Daisuki has a new web-player and this plugin can't get the streams anymore, could you update the pligin?
apparently has the same flashvars with some little changes and probably a different location of the RSA Public Key
Try new version :)
Thanks! now is working again
Also apparently all new streams are restricted with a login system for premium users only
+1 for premium streams
C:\livestreamer-v1.12.2>livestreamer http://www.daisuki.net/us/en/anime/watch.TalesofZestiriatheX.13475.html 1080p -o 1080p.ts
[cli][info] Found matching plugin daisuki for URL http://www.daisuki.net/us/en/anime/watch.TalesofZestiriatheX.13475.html
error: Unable to validate response text: Unable to validate union 'flashvars': 'NoneType' object has no attribute '__getitem__'
Tales of Zestiria the X is Premium only in US.
It is possible to login daisuki premium?
No
Works with older animes, but recent ones it gives an error:
error: Unable to validate response text: Unable to validate union 'flashvars': 'NoneType' object has no attribute 'getitem'
All episodes (but Youtube trailers) works for me (some animes can be geolocked for me).
Hi, i'm getting the "PyCrypto needs to be installed (exception : No module named winrandom)" when i try to run it.
I did delete Delete Crypto.Cipher._AES.pyd in Livestreamer directory
Then Delete Crypto in Livestreamer\library.zip
then Copy Crypto folder from pycrypto-2.6.1.win32-py2.7.exe
I did theses steps and now i'm getting this error, any idea please?
I'm pretty new & bad to all this stuff tho.
Nevermind i fixed it, its because i put the Crypto folder in the livestreamer folder AND in library.zip, once i deleted the one on library, this error got fixed....just to shot me another one.
Now i'm getting this : "UnicodeDecodeError: 'ascii" codec can't decode byte 0x92 in position 64: ordiinal no in range<128>"
I had pycrypto 2.6 and not 2.6.1 apparently, at least i uninstalled everything & did something clean with 2.6.1 instead & its now working, thanks!
I just changed the code a little bit from:
from livestreamer.compat import urljoin, urlparse, urlunparse
from livestreamer.exceptions import PluginError
from livestreamer.plugin import Plugin
from livestreamer.plugin.api import http, validate
from livestreamer.plugin.api.utils import parse_json
from livestreamer.stream import HLSStream
To:
from streamlink.compat import urljoin, urlparse, urlunparse
from streamlink.exceptions import PluginError
from streamlink.plugin import Plugin
from streamlink.plugin.api import http, validate
from streamlink.plugin.api.utils import parse_json
from streamlink.stream import HLSStream
And it's working for my PC (Windows Vista SP2, Streamlink 0.3.2, pycryptodome-3.4.5) with Python 2.7 as shown below:
Is there a way to get that working for either Python 3.5 or 3.6 by any chance?
Portable version of Streamlink is embedded with Python 3.5.2 and that's why I would like to switch from Python 2.7 to Python 3.5 accordingly:
Thank you very much and have a great day.
Try new version
That's totally awesome, it's working great with WinPython 3.5.2.3 so I'm thrilled and thank you again for your help.
I just asked them to look into the portable version of Streamlink so let's see how it goes:
if the error:
error: Unable to validate response text: Unable to validate union 'flashvars': 'NoneType' object has no attribute 'getitem'
showed its because flashvars its not present ... check with
curl url | grep -i flashvars
It works on with mexico IP address.
the plugin directly not use proxy settings so --http-proxy not works. livestreamer use requests and it had support to HTTP_PROXY HTTPS_PROXY by enviroment so run:
HTTP_PROXY="" HTTPS_PROXY= livestreamer <args>
and works! yes you need https and http proxy
Now they're only streaming Dragon Ball Super for free and here's the direct link to the latest episode 114
http://motto.daisuki.net/framewatch/embed/embedDRAGONBALLSUPERUniverseSurvivalsaga/P2e/760/428
Main page:
http://motto.daisuki.net/information/
Could this plugin be updated with a few quick tweaks? Thanks a lot.
I am having trouble using this plugin since I am receiving the regional site for my country instead of the normal expected site.
Example of url :
http://www.daisuki.net/br/en/anime/watch.ONEPUNCHMAN.12517.html