-
-
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 |
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.



+1 for premium streams