Files
tvbox_collect/tbapi2/py/app/看客TV.py
T
2026-07-05 04:58:38 +00:00

334 lines
14 KiB
Python

# -*- coding: utf-8 -*-
# 本资源来源于互联网公开渠道,仅可用于个人学习爬虫技术。
# 严禁将其用于任何商业用途,下载后请于 24 小时内删除,搜索结果均来自源站,本人不承担任何责任。
from base.spider import Spider
from Crypto.Cipher import ARC4,AES
from urllib.parse import quote_plus
from Crypto.Util.Padding import unpad
import re,sys,time,uuid,json,base64,urllib3,hashlib,secrets,binascii
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
sys.path.append('..')
class Spider(Spider):
headers = {
'User-Agent': "Dalvik/2.1.0",
'Connection': "Keep-Alive",
'Accept-Encoding': "gzip"
}
headers2 = {**headers}
client_mode,max_client,app_id,pg_url,yry_url,client,base_path,pg_key,yry_key,token,user,pwd,markcode,login_mode,app_name,model,cache_key = 0,2,'','','','','','','','','','','','','','',''
def init(self, extend=''):
try:
ext = json.loads(extend)
except Exception:
ext = {}
self.user = ext.get('username')
self.pwd = ext.get('password')
self.markcode = ext.get('markcode')
self.app_name = ext.get('app_name', 'xiaomi')
self.model = ext.get('model', 'xiaomi')
cos_url = ext.get('CosUrl', 'http://2025-1329689796.cos.ap-guangzhou.myqcloud.com/kanke/app1.json')
self.cache_key = hashlib.md5(cos_url.encode('utf-8')).hexdigest()
try:
number1 = 'No00000'
number = self.md5(number1)
number_key = self.md5(f'{number1}SmtEk1')
payload = {'t': str(int(time.time())), 'key': self.rc4_encrypt(number, number_key)}
self.app_id = '10000'
res = self.fetch(cos_url, headers=self.headers, verify=False).json()
notice = res['msg']['notice']
main_host = self.decode(notice['content'])
self.headers2['Authorization'] = self.decode(notice['type'])
response = self.post(f'{main_host}?app={self.app_id}', data=payload, headers=self.headers2, verify=False).json()
data = response['data']
maink = self.rc4_decrypt(data['Maink'], number_key)
self.pg_key = self.rc4_decrypt(data['pg'], maink)
self.yry_key = self.rc4_decrypt(data['yry'], maink)
key_time = self.rc4_decrypt(data['MT'], maink)
pg_raw_url = data['pgUrl']
yry_raw_url = data['yryUrl']
aes_key = self.base64_encode(f"{key_time}{pg_raw_url[:14]}")
aes_iv = self.base64_encode(f'{key_time}{yry_raw_url[:2]}').ljust(16)
pg_url = self.aes_decrypt(self.base64_decode(pg_raw_url[32:]), aes_key, aes_iv)
yry_url = self.aes_decrypt(self.base64_decode(yry_raw_url[16:]), aes_key, aes_iv)
self.base_path = self.rc4_decrypt(data['HOST'])
self.client = self.rc4_decrypt(data['newClient'])
self.login_mode = data.get('Login',4)
self.pg_url = pg_url
self.yry_url = yry_url
except Exception:
self.pg_url = ''
def homeContent(self, filter):
if not self.pg_url: return None
response = self.fetch(f'{self.pg_url}/api.php/{self.base_path}/Category?{self.sign()}', headers=self.headers2, verify=False).text
try:
data = self.rc4_decrypt(response)
data2 = json.loads(data)
except Exception:
data2 = json.loads(response)
classes = []
for i in data2:
if isinstance(i,dict) and i['type_status'] == 1:
classes.append({'type_id': i['type_en'], 'type_name': i['type_name']})
return {'class': classes}
def homeVideoContent(self):
if not self.pg_url: return None
response = self.fetch(f'{self.pg_url}/api.php/{self.base_path}/top?{self.sign()}', headers=self.headers2, verify=False).json()
videos = self.arr2vods(response['data'])
return {'list': videos}
def categoryContent(self, tid, pg, filter, extend):
if not self.pg_url: return None
response = self.fetch(f'{self.pg_url}/api.php/{self.base_path}/vod/?ac=list&class={tid}&page={pg}&{self.sign()}', headers=self.headers2, verify=False).text
try:
data = self.rc4_decrypt(response)
data2 = json.loads(data)
except Exception:
data2 = json.loads(response)
videos = self.arr2vods(data2['data'])
return {'list': videos,'pagecount':data2['totalpage'], 'page': pg}
def searchContent(self, key, quick, pg='1'):
if not self.pg_url: return None
response = self.fetch(f'{self.pg_url}/api.php/{self.base_path}/So/?ac=list&zm={key}&page={pg}&{self.sign()}', headers=self.headers2, verify=False).text
try:
data = self.rc4_decrypt(response)
data2 = json.loads(data)
except Exception:
data2 = json.loads(response)
videos = self.arr2vods(data2['data'])
return {'list': videos, 'page': pg}
def detailContent(self, ids):
if not self.pg_url: return None
self.client_mode = 0
if not self.token: self.auto_logon()
req_data = f'token={self.token}&t={int(time.time())}'
payload = {'data': self.rc4_encrypt(req_data),'sign': self.md5(f'{req_data}&{self.pg_key}')}
res = self.post(f'{self.yry_url}/api.php?app={self.app_id}&act=motion',data=payload, headers=self.headers2, verify=False).json()
self.client_mode = int(res['msg']['Clientmode'])
if self.client_mode == 0 and res['msg']['Try'] != 1: return None
response = self.fetch(f'{self.pg_url}/api.php/{self.base_path}/vod/{ids[0]}&{self.sign()}', headers=self.headers2, verify=False).text
try:
data2 = json.loads(response)
except Exception:
data = self.rc4_decrypt(response)
data2 = json.loads(data)
try:
player_ = self.rc4_decrypt(data2['player'])
player = json.loads(player_)
except Exception:
player = json.loads(response['player'])
vod_name = data2['title']
shows, play_urls = [], []
for show, raw_urls in data2['videolist'].items():
name = None
for i in player:
if i['from'] == show and i['from'] != i['show']:
name = i['show']
break
urls = []
for j in raw_urls:
title = j['title']
series = quote_plus(f"{vod_name}-{title}")
urls.append(f"{title}${series}@{j['url']}")
play_urls.append('#'.join(urls))
if name:
shows.append(f'{name}\u2005({show})')
else:
shows.append(show)
video = {
'vod_id': ids[0],
'vod_name': vod_name,
'vod_pic': data2['img_url'],
'vod_remarks': data2['trunk'],
'vod_year': data2['pubtime'],
'vod_area': ','.join(data2['area']),
'vod_actor': ','.join(data2['actor']),
'vod_director': ','.join(data2['director']),
'vod_content': data2['intro'],
'vod_play_from': '$$$'.join(shows),
'vod_play_url': '$$$'.join(play_urls),
'type_name': ','.join(data2['type'])
}
return {'list': [video]}
def playerContent(self, flag, vid, vip_flags):
jx,url = 0,''
series, raw_url = vid.split('@',1)
self.client_mode = 1
base_path = f'&account={self.user}&password={self.pwd}&series={series}&edition=1.0'
cont = 0
for i in range(1,4):
if cont > self.max_client:
break
try:
if self.client.startswith('http'):
if i == 1:
path = f'{self.client}/?url={raw_url}'
else:
path = f'{self.client}{i}/?url={raw_url}'
if self.client_mode == 1:
payload = {'app': self.app_id,'key': self.rc4_encrypt(base_path),'':''}
response = self.post(path, data=payload, headers=self.headers2, verify=False).text
else:
response = self.post(f'{path}&app={self.app_id}{base_path}', headers=self.headers2, verify=False).text
try:
data = self.rc4_decrypt(response)
data2 = json.loads(data)
except Exception:
data2 = json.loads(response)
self.max_client = int(data2.get('maxClient'))
play_url = data2['url']
if play_url.startswith('http'):
url = play_url
break
cont += 1
except Exception:
url = ''
cont += 1
continue
if not url:
try:
play_url = self.rc4_decrypt(raw_url)
if re.search(r'(?:www\.iqiyi|v\.qq|v\.youku|www\.mgtv|www\.bilibili)\.com', play_url):
jx, url = 1, play_url
except Exception:
pass
return { 'jx': jx, 'parse': 0, 'url': url, 'header': {'User-Agent':'Windows'}}
def auto_logon(self):
if not self.pg_url: return
if self.user and self.pwd and self.markcode:
user, pwd, markcode = self.user, self.pwd, self.markcode
else:
account_cache_key = f'smtv_account_{self.cache_key}_V73xfmWkXa'
try:
account = self.getCache(account_cache_key)
user, pwd, markcode = account['username'], account['password'], account['markcode']
except Exception:
user, pwd, markcode = None, None, None
if not (user and pwd and markcode):
if self.login_mode == 2:
random_account = self.android_id()
user, pwd, markcode = random_account, random_account, random_account
elif self.login_mode == 3:
random_account = self.mac()
user, pwd, markcode = random_account, random_account, random_account
else:
random_account = self.uuid_number()
user, pwd, markcode = random_account, random_account, random_account
self.register(user, pwd, markcode)
self.setCache(account_cache_key, {'username': user, 'password': pwd, 'markcode': markcode})
self.login(user, pwd, markcode)
def login(self, user,pwd,markcode):
if not self.pg_url: return
req_data = f'account={user}&password={pwd}&markcode={markcode}&t={int(time.time())}'
payload = {'data': self.rc4_encrypt(req_data),'sign': self.md5(f'{req_data}&{self.pg_key}')}
response = self.post(f'{self.yry_url}/api.php?app={self.app_id}&act=user_logon', data=payload, headers=self.headers2, verify=False).json()
msg = response['msg']
try:
data = self.rc4_decrypt(msg, self.yry_key)
data2 = json.loads(data)
except Exception:
data2 = json.loads(msg)
self.token = data2['token']
self.user = user
self.pwd = pwd
def register(self, user,pwd,markcode):
if not self.pg_url: return
user_host = self.fetch(f'{self.yry_url}/ip.json', headers=self.headers).text
req_data = f'user={user}&password={pwd}&markcode={markcode}&t={int(time.time())}&name={self.app_name}&phone={self.model}'
payload = {'data': self.rc4_encrypt(req_data),'sign': self.md5(f'{req_data}&{self.pg_key}')}
self.post(f'http://{user_host}/api.php?app={self.app_id}&act=user_reg', data=payload, headers=self.headers2, verify=False)
def arr2vods(self, arr):
videos = []
if isinstance(arr,list):
for i in arr:
videos.append({
'vod_id': i.get('tjurl', i.get('nextlink')),
'vod_name': i.get('tjinfo', i.get('title')),
'vod_pic': i.get('tjpicurl', i.get('pic')),
'vod_remarks': i.get('state'),
'vod_year': None
})
return videos
def rc4_encrypt(self, plaintext, key=None):
if not key: key = self.yry_key
key_bytes = key.encode('utf-8')
plaintext_bytes = plaintext.encode('utf-8')
cipher = ARC4.new(key_bytes)
ciphertext = cipher.encrypt(plaintext_bytes)
return binascii.hexlify(ciphertext).decode('utf-8')
def rc4_decrypt(self,ciphertext_hex, key=None):
if not key: key = self.pg_key
key_bytes = key.encode('utf-8')
ciphertext_bytes = binascii.unhexlify(ciphertext_hex)
cipher = ARC4.new(key_bytes)
plaintext_bytes = cipher.decrypt(ciphertext_bytes)
return plaintext_bytes.decode('utf-8')
def aes_decrypt(self, data, key, iv):
try:
encrypted_data = base64.b64decode(data)
cipher = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
decrypted_padded = cipher.decrypt(encrypted_data)
decrypted_data = unpad(decrypted_padded, AES.block_size)
return decrypted_data.decode('utf-8')
except Exception:
raise ValueError
def uuid_number(self):
uuid_bytes = uuid.uuid4().bytes
result = []
for i in range(9):
value = uuid_bytes[i] % 10
result.append(str(value))
return ''.join(result)
def mac(self):
mac_bytes = [secrets.randbits(8) for _ in range(6)]
return ''.join(f"{byte:02X}" for byte in mac_bytes)
def android_id(self):
return ''.join(secrets.choice('0123456789abcdef') for _ in range(16))
def sign(self):
timestamp = str(int(time.time()))
return f'key={self.rc4_encrypt(timestamp, timestamp)}&tt={timestamp}'
def base64_encode(self, data):
return base64.b64encode(data.encode('utf-8')).decode('utf-8')
def base64_decode(self, data):
return base64.b64decode(data.encode('utf-8')).decode('utf-8')
def decode(self, data):
return self.base64_decode(self.base64_decode(data[16:]))
def md5(self, data):
return hashlib.md5(data.encode('utf-8')).hexdigest()
def getName(self):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def destroy(self):
pass
def localProxy(self, param):
pass