diff --git a/controllers/cms.py b/controllers/cms.py index ff62444788de82fc064d11b70e843a73a7656ac3..791b8715962088842e96f61468929fc6e0bc2bfd 100644 --- a/controllers/cms.py +++ b/controllers/cms.py @@ -13,7 +13,8 @@ from utils.system import getHost from utils.config import playerConfig from utils.log import logger from utils.encode import base64Encode,baseDecode,fetch,post,request,getCryptoJS,getPreJs,buildUrl,getHome -from utils.encode import verifyCode,setDetail,join,urljoin2,parseText +from utils.encode import verifyCode,setDetail,join,urljoin2,parseText,requireCache +from utils.encode import md5 as mmd5 from utils.safePython import safePython from utils.parser import runPy,runJScode,JsObjectWrapper,PyJsObject,PyJsString from utils.htmlParser import jsoup @@ -60,12 +61,23 @@ def stringify(obj): obj = parseText(str(obj)) return json.dumps(obj, separators=(',', ':'), ensure_ascii=False) +def requireObj(url): + if isinstance(url,PyJsString): + url = parseText(str(url)) + return requireCache(url) + +def md5(text): + if isinstance(text,PyJsString): + text = parseText(str(text)) + return mmd5(text) + py_ctx = { 'requests':requests,'print':print,'base64Encode':base64Encode,'baseDecode':baseDecode, 'log':logger.info,'fetch':fetch,'post':post,'request':request,'getCryptoJS':getCryptoJS, 'buildUrl':buildUrl,'getHome':getHome,'setDetail':setDetail,'join':join,'urljoin2':urljoin2, 'PC_UA':PC_UA,'MOBILE_UA':MOBILE_UA,'UC_UA':UC_UA,'IOS_UA':IOS_UA, -'setItem':setItem,'getItem':getItem,'clearItem':clearItem,'stringify':stringify,'encodeUrl':encodeUrl +'setItem':setItem,'getItem':getItem,'clearItem':clearItem,'stringify':stringify,'encodeUrl':encodeUrl, +'requireObj':requireObj,'md5':md5 } # print(getCryptoJS()) @@ -963,6 +975,7 @@ class CMS: py_ctx.update({ 'input': url, 'TYPE': 'detail', # 海阔js环境标志 + # 'VID': id, # 传递的vod_id '二级': self.二级渲染, # 二级解析函数,可以解析dict 'cateID': fyclass, # 当前分类 'oheaders': self.d.oheaders, @@ -1046,6 +1059,7 @@ class CMS: 'oheaders': self.d.oheaders, 'fetch_params': {'headers': self.headers, 'timeout': self.d.timeout, 'encoding': self.d.encoding}, 'd': self.d, + 'MY_PAGE': fypage, 'KEY': key, # 搜索关键字 'TYPE': 'search', # 海阔js环境标志 'detailUrl': self.detailUrl or '', diff --git a/js/rules.py b/js/rules.py index 410ad81d9b302826ba78ff15059c600dd75dc2b2..67451d092a1855643a980edc70fc02d7839f1bcd 100644 --- a/js/rules.py +++ b/js/rules.py @@ -57,28 +57,32 @@ def getRules(path='cache'): codes.append(new_code) newCodes = before + '\n'+ '\n'.join(codes) # print(newCodes) - ctx.execute(newCodes) - for i in range(len(js_path)): - rule_codes.append(ctx.eval(f'rule{i}')) + try: + ctx.execute(newCodes) + for i in range(len(js_path)): + rule_codes.append(ctx.eval(f'rule{i}')) - # print(rule_codes) - # print(type(rule_codes[0]),rule_codes[0]) - # print(rule_codes[0].title) - # print(rule_codes[0].searchable) - # print(rule_codes[0].quickSearch) - new_rule_list = [] - for i in range(len(rule_list)): - tmpObj = { - 'name':rule_list[i], - 'searchable':rule_codes[i].searchable or 0, - 'quickSearch':rule_codes[i].quickSearch or 0, - 'filterable':rule_codes[i].filterable or 0, - } - if rule_codes[i].multi: - tmpObj['multi'] = 1 - new_rule_list.append(tmpObj) - # print(new_rule_list) - rules = {'list': new_rule_list, 'count': len(rule_list)} + # print(rule_codes) + # print(type(rule_codes[0]),rule_codes[0]) + # print(rule_codes[0].title) + # print(rule_codes[0].searchable) + # print(rule_codes[0].quickSearch) + new_rule_list = [] + for i in range(len(rule_list)): + tmpObj = { + 'name':rule_list[i], + 'searchable':rule_codes[i].searchable or 0, + 'quickSearch':rule_codes[i].quickSearch or 0, + 'filterable':rule_codes[i].filterable or 0, + } + if rule_codes[i].multi: + tmpObj['multi'] = 1 + new_rule_list.append(tmpObj) + # print(new_rule_list) + rules = {'list': new_rule_list, 'count': len(rule_list)} + except Exception as e: + logger.info(f'装载js内置源列表失败,置空内置源') + rules = [] logger.info(f'自动配置装载耗时:{get_interval(t1)}毫秒') return rules diff --git a/js/version.txt b/js/version.txt index ae94c935ccb6cae94f9706e49b5c32325689be32..cbbb5eea75404061b9226fddf29784ca42a73a36 100644 --- a/js/version.txt +++ b/js/version.txt @@ -1 +1 @@ -3.7.6 \ No newline at end of file +3.7.7 \ No newline at end of file diff --git "a/js/\347\214\253\344\272\206\344\270\252\345\222\252.js" "b/js/\347\214\253\344\272\206\344\270\252\345\222\252.js" new file mode 100644 index 0000000000000000000000000000000000000000..3da1d3b5efde53b84ffdd2dd163501f72b1737b6 --- /dev/null +++ "b/js/\347\214\253\344\272\206\344\270\252\345\222\252.js" @@ -0,0 +1,25 @@ +var rule = { + title:'猫了个咪', + host:'http://119.28.59.69:8089', + homeUrl:'/latest/', + url:'/api/video/index#class=fyclass&page=fypage', + searchUrl:'/api/special/video?params=#keyword=**&page=fypage', + headers:{ + 'User-Agent':'MOBILE_UA' + }, + // searchable:2, + quickSearch:0, + timeout:5000, + class_name:'全部&国产专区&欧美精品&动漫&中文字幕&人气女忧&不雅视频&韩三级&热剧大人版&抖音妹合集&猫咪自拍', + class_url:'0&32&16&31&34&35&37&39&40&41&42', + limit:5, + play_parse:true, + lazy:'js:log(input);', + lazy:'js:let VID=input.split(";")[1];let VURL=input.split(";")[0];var fn=rc("maomi_aes.js");let url=VURL+"?params="+fn.En(\'{"id":"\'+VID+\'"}\');input=JSON.parse(fn.De(request(url))).data.video_item[0].file;', + 一级:'', + 一级:'js:let d=[];let bodys={access_token:"",cate_id:MY_CATE,identifier:"ffffffff-c67a-899b-ffff-ffffef05ac4a",page:MY_PAGE,region:0,type_id:0,vip:0,year:""};var fn=rc("maomi_aes.js");bodys=fn.En(stringify(bodys));let obj={headers:{"Content-Type":"application/x-www-form-urlencoded"},method:"POST",body:"params="+bodys+"&version=26&sign="+md5("QEBBQADSwrXIXaNqBmMofjfRY/8Sxaxgparams"+bodys+"version26QEBBQADSwrXIXaNqBmMofjfRY/8Sxaxg")};let api=input.split("#")[0];let html=JSON.parse(fn.De(request(api,obj)));html.data.data.forEach(function(it){d.push({title:it.name,img:it.image,desc:it.rate,url:api.replace("index","detail")+";"+it.id})});setResult(d);', + 二级:'*', + 搜索:'', + // 搜索:'js:let bodys={keyword:KEY,page:MY_PAGE};var fn=rc("maomi_aes.js");bodys=fn.En(stringify(bodys));let url=input.split("#")[0];print(url);var html=JSON.parse(fn.De(request(url+bodys)));let d=html.data.data.map(function(data){return{title:data.video_name,img:data.image,desc:data.rate,url:"http://119.28.59.69:8089/api/video/detail?params=;"+fn.En(\'{"id":"\'+data.video_id+\'"}\')}});setResult(d);', + +} \ No newline at end of file diff --git a/libs/maomi_aes.js b/libs/maomi_aes.js new file mode 100644 index 0000000000000000000000000000000000000000..2b247385363495b3a2b2651f4398e28a32c1b60c --- /dev/null +++ b/libs/maomi_aes.js @@ -0,0 +1,25 @@ +eval(getCryptoJS()); +var a = CryptoJS.enc.Utf8.parse("625222f9149e961d"); +var t = CryptoJS.enc.Utf8.parse("5efdtf6060e2o330"); +function De(word) { + word = CryptoJS.enc.Hex.parse(word) + return CryptoJS.AES.decrypt(CryptoJS.enc.Base64.stringify(word), a, { + iv: t, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7 + }).toString(CryptoJS.enc.Utf8) +} +var En = function(word) { + // print(a); + // print(word); + var Encrypted = CryptoJS.AES.encrypt(word, a, { + iv: t, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7 + }); + return Encrypted.ciphertext.toString(); +} +$.exports = { + De:De, + En:En +} \ No newline at end of file diff --git a/libs/pre.js b/libs/pre.js index 2b83f0fafb8de6091380f72bbe57fe2cfc6f9b9e..31801243bf5615f527c4feab77c543db4054d7dd 100644 --- a/libs/pre.js +++ b/libs/pre.js @@ -1,4 +1,5 @@ var VODS = []; +var $ = {}; if (!String.prototype.includes) { String.prototype.includes = function (search, start) { @@ -233,6 +234,7 @@ function request(url,obj){ } // delete new_obj.headers['Referer']; // print(obj); + // print(new_obj); if(typeof(fetch)!==undefined){ let html = fetch(url,new_obj); if (/\?btwaf=/.test(html)) {//宝塔验证 @@ -245,9 +247,18 @@ function request(url,obj){ return '' } +function rc(url){// 系统已经有require方法了,再覆盖的话无法操作了 + res = eval(requireObj(url)); + // print(res); + return res; + // return eval.call(null, requireObj(url)); +} + +$.require = rc; + function urlencode (str) { str = (str + '').toString(); return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28'). replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+'); -} +} \ No newline at end of file diff --git "a/py/\347\214\253\344\272\206\344\270\252\345\222\252\344\270\200\347\272\247.js" "b/py/\347\214\253\344\272\206\344\270\252\345\222\252\344\270\200\347\272\247.js" new file mode 100644 index 0000000000000000000000000000000000000000..af73f62173d8823ead2035233ec500ab496843c0 --- /dev/null +++ "b/py/\347\214\253\344\272\206\344\270\252\345\222\252\344\270\200\347\272\247.js" @@ -0,0 +1,38 @@ +js: +let d = []; +let bodys = { + "access_token": "", + "cate_id": MY_CATE, + "identifier": "ffffffff-c67a-899b-ffff-ffffef05ac4a", + "page": MY_PAGE, + "region": 0, + "type_id": 0, + "vip": 0, + "year": "" +}; +// print(input); +// print(bodys); +var fn = rc('maomi_aes.js'); +bodys = fn.En(stringify(bodys)); +// print(bodys); +let obj = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + method: 'POST', + // body: 'params=' + bodys + '&version=26&sign=' + CryptoJS.MD5('QEBBQADSwrXIXaNqBmMofjfRY/8Sxaxgparams' + bodys + 'version26QEBBQADSwrXIXaNqBmMofjfRY/8Sxaxg') + body: 'params=' + bodys + '&version=26&sign=' + md5('QEBBQADSwrXIXaNqBmMofjfRY/8Sxaxgparams' + bodys + 'version26QEBBQADSwrXIXaNqBmMofjfRY/8Sxaxg') +}; +// print(obj); +let api = input.split('#')[0]; +let html = JSON.parse(fn.De(request(api, obj))); +// print(html); +html.data.data.forEach(function (it){ + d.push({ + title:it.name, + img:it.image, + desc:it.rate, + url:api.replace('index','detail')+';'+it.id + }); +}); +setResult(d); \ No newline at end of file diff --git "a/py/\347\214\253\344\272\206\344\270\252\345\222\252\345\205\215\345\227\205.js" "b/py/\347\214\253\344\272\206\344\270\252\345\222\252\345\205\215\345\227\205.js" new file mode 100644 index 0000000000000000000000000000000000000000..29132efeef1fbddc6a597384491ffce532b8d9e4 --- /dev/null +++ "b/py/\347\214\253\344\272\206\344\270\252\345\222\252\345\205\215\345\227\205.js" @@ -0,0 +1,8 @@ +js: +// log(input); +let VID = input.split(';')[1]; +let VURL = input.split(';')[0]; +var fn = rc('maomi_aes.js'); +let url = VURL + '?params='+fn.En('{"id":"' + VID + '"}'); +// print(url); +input = JSON.parse(fn.De(request(url))).data.video_item[0].file; \ No newline at end of file diff --git "a/py/\347\214\253\344\272\206\344\270\252\345\222\252\346\220\234\347\264\242.js" "b/py/\347\214\253\344\272\206\344\270\252\345\222\252\346\220\234\347\264\242.js" new file mode 100644 index 0000000000000000000000000000000000000000..de5953a939cfafe65b6d8a3e6655163ce17237d3 --- /dev/null +++ "b/py/\347\214\253\344\272\206\344\270\252\345\222\252\346\220\234\347\264\242.js" @@ -0,0 +1,16 @@ +js: +let bodys = {"keyword":KEY,"page":MY_PAGE}; +var fn = rc('maomi_aes.js'); +bodys = fn.En(stringify(bodys)); +let url = input.split('#')[0]; +print(url); +var html = JSON.parse(fn.De(request(url+bodys))); +let d = html.data.data.map(function (data){ + return { + title: data.video_name, + img: data.image, + desc:data.rate, + url: 'http://119.28.59.69:8089/api/video/detail?params=;'+fn.En('{"id":"'+data.video_id+'"}'), + } +}); +setResult(d); \ No newline at end of file diff --git a/readme.md b/readme.md index 804c3895b9ccae064005870797883713d25846bb..f37a9740e533f68babcd8052f14b20c8b16afd01 100644 --- a/readme.md +++ b/readme.md @@ -50,6 +50,7 @@ - [X] 1.v3.7.5 优化了首图2模板的搜索定位以及几个相关的源 - [X] 2.二级渲染功能拆分,js单独调用 - [X] 3.v3.7.6 新增优酷源(pluto专用) +- [X] 4.v3.7.7 新增酷云77源(pluto专用),新增猫了个咪源,优化request等方法的post参数传递,增加rc函数 ###### 2022/09/22 - [X] 1.v3.7.3修复静态文件阿里token没渲染的bug,修复数据库升级bug,优化app.py - [X] 2.v3.7.4修复自定义drives合并配置报错问题 diff --git a/utils/encode.py b/utils/encode.py index 5ee92766859e243aa5e15a13ef2edf0e1f57b1ff..fc7e68793aa47e09c2d6a202626435cb2d837cfd 100644 --- a/utils/encode.py +++ b/utils/encode.py @@ -14,10 +14,12 @@ from requests.packages import urllib3 urllib3.disable_warnings() import requests.utils +import hashlib from time import sleep import os from utils.web import UC_UA,PC_UA from ast import literal_eval +from utils.log import logger def getPreJs(): base_path = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) # 上级目 @@ -37,6 +39,41 @@ def getCryptoJS(): code = f.read() return code +def md5(str): + return hashlib.md5(str.encode(encoding='UTF-8')).hexdigest() + +def requireCache(lib:str): + base_path = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) # 上级目 + os.makedirs(os.path.join(base_path, f'libs'), exist_ok=True) + logger.info(f'开始加载:{lib}') + code = 'undefiend' + if not lib.startswith('http'): + lib_path = os.path.join(base_path, f'libs/{lib}') + if not os.path.exists(lib_path): + pass + else: + with open(lib_path, encoding='utf-8') as f: + code = f.read() + else: + lib_path = os.path.join(base_path, f'libs/{md5(lib)}.js') + if not os.path.exists(lib_path): + try: + r = requests.get(lib,headers={ + 'Referer': lib, + 'User-Agent': UC_UA, + },timeout=5) + with open(lib_path,mode='wb+') as f: + f.write(r.content) + code = r.text + except Exception as e: + print(f'获取远程依赖失败:{e}') + else: + with open(lib_path,encoding='utf-8') as f: + code = f.read() + # print(code) + return code + + def getHome(url): # http://www.baidu.com:9000/323 urls = url.split('//') @@ -95,6 +132,10 @@ def base64Encode(text): def baseDecode(text): return base64.b64decode(text).decode("utf-8") #base64解码 +def parseText(text:str): + text = text.replace('false','False').replace('true','True').replace('null','None') + return literal_eval(text) + def setDetail(title:str,img:str,desc:str,content:str,tabs:list=None,lists:list=None): vod = { "vod_name": title.split('/n')[0], @@ -142,10 +183,13 @@ def dealObj(obj=None): obj = {} encoding = obj.get('encoding') or 'utf-8' encoding = str(encoding).replace("'", "") + # encoding = parseText(str(encoding)) method = obj.get('method') or 'get' method = str(method).replace("'", "") + # method = parseText(str(method)) withHeaders = obj.get('withHeaders') or '' withHeaders = str(withHeaders).replace("'", "") + # withHeaders = parseText(str(withHeaders)) # print(type(url),url) # headers = dict(obj.get('headers')) if obj.get('headers') else {} # headers = obj.get('headers').to_dict() if obj.get('headers') else {} @@ -159,6 +203,16 @@ def dealObj(obj=None): timeout = float(obj.get('timeout').to_int()) if obj.get('timeout') else None # print(type(timeout), timeout) body = obj.get('body') if obj.get('body') else {} + # print(body) + # print(type(body)) + if isinstance(body,PyJsString): + body = parseText(str(body)) + new_dict = {} + new_tmp = body.split('&') + for i in new_tmp: + new_dict[i.split('=')[0]] = i.split('=')[1] + body = new_dict + new_body = {} for i in body: new_body[str(i).replace("'", "")] = str(body[i]).replace("'", "") @@ -173,6 +227,7 @@ def dealObj(obj=None): def base_request(url,obj): # verify=False 关闭证书验证 + # print(obj) url = str(url).replace("'", "") method = obj.get('method') or '' withHeaders = obj.get('withHeaders') or '' @@ -181,7 +236,7 @@ def base_request(url,obj): method = 'get' obj['method'] = 'method' # print(obj) - print(f"{method}:{url}:{obj['headers']}") + print(f"{method}:{url}:{obj['headers']}:{obj.get('body','')}") try: # r = requests.get(url, headers=headers, params=body, timeout=timeout) if method.lower() == 'get': @@ -207,6 +262,7 @@ def base_request(url,obj): return {} if withHeaders else '' def fetch(url,obj): + # print('fetch') obj = dealObj(obj) if not obj.get('headers') or not any([obj['headers'].get('User-Agent'),obj['headers'].get('user-agent')]): obj['headers']['User-Agent'] = obj['headers'].get('user-agent',PC_UA) @@ -257,8 +313,4 @@ def buildUrl(url,obj=None): # url = (url + prs).replace('"','').replace("'",'') url = url + prs # print(url) - return url - -def parseText(text:str): - text = text.replace('false','False').replace('true','True').replace('null','None') - return literal_eval(text) \ No newline at end of file + return url \ No newline at end of file diff --git a/utils/parser.py b/utils/parser.py index f824fa9b72104c2d543471d292348889920727ce..c3d0719071d5617602d1a958b7c051015b3cde5b 100644 --- a/utils/parser.py +++ b/utils/parser.py @@ -24,7 +24,7 @@ def runJScode(jscode,loader=None,ctx=None): if loader is None: if ctx is None: ctx = {} - loader = js2py.EvalJs(ctx) + loader = js2py.EvalJs(ctx,enable_require=False) # enable_require启用require关键字,会自动获取系统nodejs环境 loader.execute(jscode) return loader, jscode