Sync all projects
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 本资源收集自互联网,仅供个人学习与测试用途。
|
||||
# 严禁用于商业目的,请于下载后 24 小时内删除。
|
||||
|
||||
from Crypto.Cipher import AES
|
||||
from base.spider import Spider
|
||||
from Crypto.Util.Padding import unpad, pad
|
||||
import re,sys,time,json,base64,urllib3,hashlib,binascii
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
sys.path.append('..')
|
||||
|
||||
class Spider(Spider):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.headers = {
|
||||
'User-Agent': "Dart/2.10 (dart:io)",
|
||||
'Accept-Encoding': "gzip",
|
||||
}
|
||||
self.host = ''
|
||||
self.key = ''
|
||||
self.iv = ''
|
||||
self.ckkey = ''
|
||||
self.ckiv = ''
|
||||
self.config = {}
|
||||
|
||||
def init(self, extend=""):
|
||||
try:
|
||||
ext = json.loads(extend.strip())
|
||||
host = ext['host']
|
||||
self.key = ext['key']
|
||||
self.iv = ext['iv']
|
||||
self.ckkey = ext.get('ckkey','ygcnbcrvaervztmw')
|
||||
self.ckiv = ext.get('ckiv','1212164105143708')
|
||||
if not host.startswith('http'):
|
||||
return None
|
||||
if not re.match(r'^https?://[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(:\d+)?/?$', host):
|
||||
host = self.fetch(host,headers=self.headers,verify=False).text.strip()
|
||||
self.host = host.rstrip('/')
|
||||
if len(self.key) != 16 or len(self.iv) != 16:
|
||||
self.host = ''
|
||||
return None
|
||||
payload = {
|
||||
"sign": hashlib.md5(f'{self.key}{self.iv}'.encode('utf-8')).hexdigest(),
|
||||
"ck": self.ck_encrypt(f'{self.host}##5483##{int(time.time() * 1000)}##ckzmbc')
|
||||
}
|
||||
headers = self.headers.copy()
|
||||
headers.update({'Content-Type': "application/json",'content-type': "application/json; charset=utf-8"})
|
||||
response = self.post(f'{self.host}/get_config', data=json.dumps(payload), headers=headers, verify=False).text
|
||||
if response:
|
||||
token = self.sk_decrypt(response)
|
||||
if token:
|
||||
self.headers['authorization'] = 'Bearer ' + token
|
||||
config_ = self.fetch(f'{self.host}/app/config', headers=self.headers, verify=False).text
|
||||
config = self.sk_decrypt(config_)
|
||||
data = json.loads(config)
|
||||
direct_link = data.get('direct_link')
|
||||
direct_json_link = data.get('direct_json_link')
|
||||
app_trans_name = data.get('app_trans_name')
|
||||
if direct_link and isinstance(direct_link, str):
|
||||
if '|' in direct_link:
|
||||
direct_link_list = direct_link.split('|')
|
||||
else:
|
||||
direct_link_list = [direct_link]
|
||||
self.config['direct_link'] = direct_link_list
|
||||
if direct_json_link and isinstance(direct_json_link,str):
|
||||
if '|' in direct_json_link:
|
||||
direct_json_link_list = direct_json_link.split('|')
|
||||
else:
|
||||
direct_json_link_list = [direct_json_link]
|
||||
self.config['direct_json_link'] = direct_json_link_list
|
||||
if app_trans_name and isinstance(app_trans_name,list):
|
||||
self.config['app_trans_name'] = app_trans_name
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def homeContent(self, filter):
|
||||
if not self.host: return None
|
||||
try:
|
||||
response = self.fetch(f'{self.host}/sk-api/type/list', headers=self.headers, verify=False).text
|
||||
data_ = self.sk_decrypt(response)
|
||||
data = json.loads(data_)['data']
|
||||
classes = []
|
||||
for i in data:
|
||||
if isinstance(i, dict):
|
||||
classes.append({'type_id': i['type_id'], 'type_name': i['type_name']})
|
||||
except Exception:
|
||||
return {'class': []}
|
||||
filters = {}
|
||||
def fetch_filter(tid):
|
||||
try:
|
||||
url = f'{self.host}/sk-api/type/alltypeextend?typeId={tid}'
|
||||
resp = self.fetch(url, headers=self.headers, verify=False).text
|
||||
decrypted = self.sk_decrypt(resp)
|
||||
f_data = json.loads(decrypted)
|
||||
if f_data.get('code') == 200 and f_data.get('data'):
|
||||
data_obj = f_data['data']
|
||||
type_filters = []
|
||||
mappings = {
|
||||
'class': ('extendtype', '类型'),
|
||||
'area': ('area', '地区'),
|
||||
'lang': ('lang', '语言'),
|
||||
'year': ('year', '年份')
|
||||
}
|
||||
for api_key, val in mappings.items():
|
||||
filter_key, filter_name = val
|
||||
if data_obj.get(api_key):
|
||||
options = [x.strip() for x in data_obj[api_key].split(',') if x.strip()]
|
||||
if options:
|
||||
value_list = [{'n': '全部', 'v': ''}]
|
||||
for opt in options:
|
||||
value_list.append({'n': opt, 'v': opt})
|
||||
type_filters.append({'key': filter_key, 'name': filter_name, 'init': '', 'value': value_list})
|
||||
type_filters.append({
|
||||
'key': 'sort',
|
||||
'name': '排序',
|
||||
'init': 'updateTime',
|
||||
'value': [
|
||||
{'n': '最新', 'v': 'updateTime'},
|
||||
{'n': '人气', 'v': 'hot'},
|
||||
{'n': '评分', 'v': 'score'}
|
||||
]
|
||||
})
|
||||
return str(tid), type_filters
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
with ThreadPoolExecutor(max_workers=5) as executor:
|
||||
futures = [executor.submit(fetch_filter, c['type_id']) for c in classes]
|
||||
for future in as_completed(futures):
|
||||
res = future.result()
|
||||
if res:
|
||||
filters[res[0]] = res[1]
|
||||
return {'class': classes, 'filters': filters}
|
||||
|
||||
def homeVideoContent(self):
|
||||
response = self.fetch(f'{self.host}/sk-api/vod/list?page=1&limit=12&type=randomlikeindex&area=&lang=&year=&mtype=',headers=self.headers, verify=False).text
|
||||
data_ = self.sk_decrypt(response)
|
||||
data = json.loads(data_)['data']
|
||||
return {'list': data}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
sort = extend.get('sort', 'updateTime')
|
||||
area = extend.get('area', '')
|
||||
lang = extend.get('lang', '')
|
||||
year = extend.get('year', '')
|
||||
extendtype = extend.get('extendtype', '')
|
||||
response = self.fetch(f"{self.host}/sk-api/vod/list?typeId={tid}&page={pg}&limit=18&type={sort}&area={area}&lang={lang}&year={year}&mtype=&extendtype={extendtype}", headers=self.headers, verify=False).text
|
||||
data_ = self.sk_decrypt(response)
|
||||
data = json.loads(data_)['data']
|
||||
return {'list': data, 'page': pg}
|
||||
|
||||
def searchContent(self, key, quick, pg='1'):
|
||||
response = self.fetch(f"{self.host}/sk-api/search/pages?keyword={key}&page={pg}&limit=10&typeId=-1", headers=self.headers, verify=False).text
|
||||
data_ = self.sk_decrypt(response)
|
||||
data = json.loads(data_)['data']
|
||||
return {'list': data, 'page': pg}
|
||||
|
||||
def detailContent(self, ids):
|
||||
response = self.fetch(f"{self.host}/sk-api/vod/one?vodId={ids[0]}",headers=self.headers, verify=False).text
|
||||
data_ = self.sk_decrypt(response)
|
||||
data = json.loads(data_)['data']
|
||||
return {'list': [data]}
|
||||
|
||||
def playerContent(self, flag, id, vipflags):
|
||||
jx,url,direct_link = 0,'',0
|
||||
config = self.config
|
||||
direct_json_links = config.get('direct_json_link',[])
|
||||
direct_links = config.get('direct_link',[])
|
||||
direct_json = 0
|
||||
for i in direct_json_links:
|
||||
if i in id:
|
||||
direct_json = 1
|
||||
for i in direct_links:
|
||||
if i in id and i.startswith('http'):
|
||||
direct_link = 1
|
||||
if direct_json or not direct_link or not(id.startswith('http')):
|
||||
try:
|
||||
response = self.fetch(f'{self.host}/sk-api/vod/skjson?url={id}&skjsonindex=0', headers=self.headers, verify=False).text
|
||||
data_ = self.sk_decrypt(response)
|
||||
data = json.loads(data_)['data']
|
||||
play_url = data.get('url')
|
||||
if play_url.startswith('http'):
|
||||
url = play_url
|
||||
except Exception:
|
||||
pass
|
||||
if not url:
|
||||
url = id
|
||||
if re.search(r'(?:www\.iqiyi|v\.qq|v\.youku|www\.mgtv|www\.bilibili)\.com', id):
|
||||
jx = 1
|
||||
return { 'jx': jx, 'parse': 0, 'url': url, 'header': {'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'}}
|
||||
|
||||
def ck_encrypt(self, str):
|
||||
key = self.ckkey.encode('utf-8')
|
||||
iv = self.ckiv.encode('utf-8')
|
||||
b64_1 = base64.b64encode(str.encode("utf-8"))
|
||||
b64_2 = base64.b64encode(b64_1)
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
padded_data = pad(b64_2, AES.block_size)
|
||||
encrypted_bytes = cipher.encrypt(padded_data)
|
||||
hex_encoded = encrypted_bytes.hex()
|
||||
hex_bytes = hex_encoded.encode('utf-8')
|
||||
final_ciphertext = base64.b64encode(hex_bytes).decode('utf-8')
|
||||
return final_ciphertext
|
||||
|
||||
def sk_decrypt(self,data):
|
||||
prefix = "FROMSKZZJM"
|
||||
if data.startswith('FROMSKZZJM'):
|
||||
try:
|
||||
encrypted_hex = data[len(prefix):]
|
||||
key = self.key.encode('utf-8')
|
||||
iv = self.iv.encode('utf-8')
|
||||
encrypted_data = binascii.unhexlify(encrypted_hex)
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)
|
||||
return decrypted_data.decode('utf-8')
|
||||
except Exception:
|
||||
return None
|
||||
else:
|
||||
return data
|
||||
|
||||
def getName(self):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
||||
Reference in New Issue
Block a user