Files
addon/lib/megaserver/client.py
marco 8a8d1e4f5e KoD 1.4
- completato il supporto al futuro Kodi 19\n- ridisegnato infoplus\n- fix vari ed eventuali\n
2020-09-29 21:08:25 +02:00

203 lines
7.8 KiB
Python

import base64, json, random, struct, time, sys, traceback
if sys.version_info[0] >= 3:
PY3 = True
import urllib.request as urllib
xrange = range
else:
PY3 = False
import urllib
from core import httptools
from threading import Thread
from lib.megaserver.file import File
from lib.megaserver.handler import Handler
from platformcode import logger
from lib.megaserver.server import Server
class Client(object):
VIDEO_EXTS = {'.avi': 'video/x-msvideo', '.mp4': 'video/mp4', '.mkv': 'video/x-matroska',
'.m4v': 'video/mp4', '.mov': 'video/quicktime', '.mpg': 'video/mpeg','.ogv': 'video/ogg',
'.ogg': 'video/ogg', '.webm': 'video/webm', '.ts': 'video/mp2t', '.3gp': 'video/3gpp'}
def __init__(self, url, port=None, ip=None, auto_shutdown=True, wait_time=20, timeout=5, is_playing_fnc=None):
self.port = port if port else random.randint(8000,8099)
self.ip = ip if ip else "127.0.0.1"
self.connected = False
self.start_time = None
self.last_connect = None
self.is_playing_fnc = is_playing_fnc
self.auto_shutdown = auto_shutdown
self.wait_time = wait_time
self.timeout = timeout
self.running = False
self.file = None
self.files = []
self._server = Server((self.ip, self.port), Handler, client=self)
self.add_url(url)
self.start()
def start(self):
self.start_time = time.time()
self.running = True
self._server.run()
t= Thread(target=self._auto_shutdown)
t.setDaemon(True)
t.start()
logger.info("MEGA Server Started")
def _auto_shutdown(self):
while self.running:
time.sleep(1)
if self.file and self.file.cursor:
self.last_connect = time.time()
if self.is_playing_fnc and self.is_playing_fnc():
self.last_connect = time.time()
if self.auto_shutdown:
#shudown por haber cerrado el reproductor
if self.connected and self.last_connect and self.is_playing_fnc and not self.is_playing_fnc():
if time.time() - self.last_connect - 1 > self.timeout:
self.stop()
#shutdown por no realizar ninguna conexion
if (not self.file or not self.file.cursor) and self.start_time and self.wait_time and not self.connected:
if time.time() - self.start_time - 1 > self.wait_time:
self.stop()
#shutdown tras la ultima conexion
if (not self.file or not self.file.cursor) and self.timeout and self.connected and self.last_connect and not self.is_playing_fnc:
if time.time() - self.last_connect - 1 > self.timeout:
self.stop()
def stop(self):
self.running = False
self._server.stop()
logger.info("MEGA Server Stopped")
def get_play_list(self):
if len(self.files) > 1:
return "http://" + self.ip + ":" + str(self.port) + "/playlist.pls"
else:
return "http://" + self.ip + ":" + str(self.port) + "/" + urllib.quote(self.files[0].name.encode("utf8"))
def get_files(self):
files = []
enc_url = None
if self.files:
for file in self.files:
n = file.name.encode("utf8")
u = "http://" + self.ip + ":" + str(self.port) + "/" + urllib.quote(n)
s = file.size
file_id = file.file_id
enc_url = file.url
files.append({"name":n,"url":u,"size":s, "id": file_id})
if len(self.files) == 1:
try:
code = httptools.downloadpage(enc_url, only_headers=True).code
if code > 300:
return code
else:
return files
except:
logger.info(traceback.format_exc())
pass
return files
def add_url(self, url):
url = url.split("#")[1]
id_video = None
if "|" in url:
url, id_video = url.split("|")
if url.startswith("F!"):
if len(url.split("!")) ==3:
folder_id = url.split("!")[1]
folder_key = url.split("!")[2]
master_key = self.base64_to_a32(folder_key)
files = self.api_req({"a":"f","c":1,"r":1},"&n="+folder_id)
for file in files["f"]:
if file["t"] == 0:
if id_video and id_video != file["h"]:
continue
key = file['k'][file['k'].index(':') + 1:]
key = self.decrypt_key(self.base64_to_a32(key), master_key)
k = (key[0] ^ key[4], key[1] ^ key[5], key[2] ^ key[6], key[3] ^ key[7])
attributes = self.base64urldecode(file['a'])
attributes = self.dec_attr(attributes, k)
self.files.append(File(info=attributes, file_id=file["h"], key=key, folder_id=folder_id, file= file, client = self ))
else:
raise Exception("Enlace no valido")
elif url.startswith("!") or url.startswith("N!"):
if len(url.split("!")) ==3:
file_id = url.split("!")[1]
file_key = url.split("!")[2]
file = self.api_req({'a': 'g', 'g': 1, 'p': file_id})
key = self.base64_to_a32(file_key)
k = (key[0] ^ key[4], key[1] ^ key[5], key[2] ^ key[6], key[3] ^ key[7])
attributes = self.base64urldecode(file['at'])
attributes = self.dec_attr(attributes, k)
self.files.append(File(info=attributes, file_id=file_id, key=key, file= file, client = self))
else:
raise Exception("Enlace no valido")
else:
raise Exception("Enlace no valido")
def api_req(self, req, get=""):
seqno = random.randint(0, 0xFFFFFFFF)
url = 'https://g.api.mega.co.nz/cs?id=%d%s' % (seqno, get)
page = httptools.downloadpage(url, post=json.dumps([req])).data
return json.loads(page)[0]
def base64urldecode(self,data):
data += '=='[(2 - len(data) * 3) % 4:]
for search, replace in (('-', '+'), ('_', '/'), (',', '')):
data = data.replace(search, replace)
return base64.b64decode(data)
def base64urlencode(self,data):
data = base64.b64encode(data)
for search, replace in (('+', '-'), ('/', '_'), ('=', '')):
data = data.replace(search, replace)
return data
def a32_to_str(self,a):
return struct.pack('>%dI' % len(a), *a)
def str_to_a32(self,b):
if len(b) % 4: # Add padding, we need a string with a length multiple of 4
b += '\0' * (4 - len(b) % 4)
return struct.unpack('>%dI' % (len(b) / 4), b)
def base64_to_a32(self,s):
return self.str_to_a32(self.base64urldecode(s))
def a32_to_base64(self,a):
return self.base64urlencode(self.a32_to_str(a))
def aes_cbc_decrypt(self, data, key):
try:
from Cryptodome.Cipher import AES
except:
from Crypto.Cipher import AES
decryptor = AES.new(key, AES.MODE_CBC, b'\0' * 16)
return decryptor.decrypt(data)
def aes_cbc_decrypt_a32(self,data, key):
return self.str_to_a32(self.aes_cbc_decrypt(self.a32_to_str(data), self.a32_to_str(key)))
def decrypt_key(self,a, key):
return sum((self.aes_cbc_decrypt_a32(a[i:i+4], key) for i in xrange(0, len(a), 4)), ())
def dec_attr(self, attr, key):
attr = self.aes_cbc_decrypt(attr, self.a32_to_str(key)).rstrip(b'\0')
if not attr.endswith(b"}"):
attr = attr.rsplit(b"}", 1)[0] + b"}"
return json.loads(attr[4:]) if attr[:6] == b'MEGA{"' else False