mirror of
https://github.com/cluntop/tvbox.git
synced 2026-01-11 18:08:34 +01:00
192 lines
No EOL
6.2 KiB
Python
Executable file
192 lines
No EOL
6.2 KiB
Python
Executable file
# -*- coding: utf-8 -*-
|
|
# by @汤圆
|
|
import re
|
|
import sys
|
|
from pyquery import PyQuery as pq
|
|
sys.path.append('..')
|
|
from base.spider import Spider
|
|
|
|
|
|
class Spider(Spider):
|
|
|
|
def init(self, extend=""):
|
|
pass
|
|
|
|
def getName(self):
|
|
return "DB563"
|
|
|
|
def isVideoFormat(self, url):
|
|
pass
|
|
|
|
def manualVideoCheck(self):
|
|
pass
|
|
|
|
def destroy(self):
|
|
pass
|
|
|
|
host = "https://javdb563.com"
|
|
|
|
headers = {
|
|
'User-Agent': 'Mozilla/5.0 (Linux; Android 15; 23113RKC6C Build/AQ3A.240912.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/140.0.7339.207 Mobile Safari/537.36',
|
|
'Cookie': '',
|
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
|
|
}
|
|
|
|
def _fix_mojibake(self, s):
|
|
if not s:
|
|
return s
|
|
# Detect common mojibake markers like 'Ã', 'Â', 'ä', 'å', 'æ' from UTF-8 decoded as Latin-1
|
|
try:
|
|
if re.search(r'[ÃÂäåæçèéìíòóùúÄÅÆÇÈÉÌÍÒÓÙÚ]', s):
|
|
return s.encode('latin1', 'ignore').decode('utf-8', 'ignore')
|
|
except Exception:
|
|
pass
|
|
return s
|
|
|
|
def homeContent(self, filter):
|
|
data = self.getpq("/")
|
|
result = {}
|
|
|
|
# 分类信息
|
|
classes = [
|
|
{'type_name': '全部', 'type_id': ''},
|
|
{'type_name': '无码', 'type_id': 'uncensored'},
|
|
{'type_name': '人气标题', 'type_id': 'tags/uncensored?c5=117&c10=1'},
|
|
{'type_name': '欧美', 'type_id': 'western'},
|
|
{'type_name': '捆绑', 'type_id': 'tags/uncensored?c10=1&c2=14'},
|
|
{'type_name': '束缚', 'type_id': 'tags/uncensored?c2=7&c10=1'},
|
|
{'type_name': '潮吹', 'type_id': 'tags/uncensored?c2=29&c10=1'},
|
|
{'type_name': '性奴', 'type_id': 'tags/uncensored?c10=1&c2=32'}
|
|
]
|
|
|
|
result['class'] = classes
|
|
result['list'] = self.getlist(data)
|
|
return result
|
|
|
|
def homeVideoContent(self):
|
|
pass
|
|
|
|
def categoryContent(self, tid, pg, filter, extend):
|
|
# 构建URL
|
|
if tid == '':
|
|
# 全部分类
|
|
if pg == 1:
|
|
url = "/"
|
|
else:
|
|
url = f"/?page={pg}"
|
|
else:
|
|
# 其他分类
|
|
if pg == 1:
|
|
url = f"/{tid}"
|
|
else:
|
|
# 检查是否已经包含查询参数
|
|
if '?' in tid:
|
|
url = f"/{tid}&page={pg}"
|
|
else:
|
|
url = f"/{tid}?page={pg}"
|
|
|
|
data = self.getpq(url)
|
|
result = {}
|
|
result['list'] = self.getlist(data)
|
|
result['page'] = pg
|
|
result['pagecount'] = 9999
|
|
result['limit'] = 90
|
|
result['total'] = 999999
|
|
return result
|
|
|
|
def detailContent(self, ids):
|
|
data = self.getpq(ids[0])
|
|
|
|
# 获取基本信息
|
|
title = data('.video-title strong').text()
|
|
if not title:
|
|
title = data('h1').text()
|
|
title = self._fix_mojibake((title or '').strip())
|
|
|
|
vod = {
|
|
'vod_id': ids[0],
|
|
'vod_name': title,
|
|
'vod_pic': data('.cover img').attr('src'),
|
|
'vod_year': self._fix_mojibake((data('.meta').text() or '').strip()),
|
|
'vod_remarks': self._fix_mojibake((data('.score .value').text() or '').strip()),
|
|
'vod_content': self._fix_mojibake((data('.video-title').text() or '').strip())
|
|
}
|
|
|
|
# 获取磁力链接
|
|
magnets = []
|
|
magnet_items = data('#magnets-content .item')
|
|
|
|
for item in magnet_items.items():
|
|
magnet_name_elem = item('.magnet-name a')
|
|
magnet_url = magnet_name_elem.attr('href')
|
|
magnet_title = self._fix_mojibake((magnet_name_elem.text() or '').strip())
|
|
|
|
if magnet_url and magnet_url.startswith('magnet:'):
|
|
magnets.append(f"{magnet_title}${magnet_url}")
|
|
|
|
vod["vod_play_from"] = "磁力链接"
|
|
vod["vod_play_url"] = "#".join(magnets) if magnets else f"{title}${ids[0]}"
|
|
|
|
result = {"list": [vod]}
|
|
return result
|
|
|
|
def searchContent(self, key, quick, pg="1"):
|
|
# 构建搜索URL
|
|
search_url = f"/search?q={key}"
|
|
if pg != "1":
|
|
search_url += f"&page={pg}"
|
|
|
|
data = self.getpq(search_url)
|
|
result = {}
|
|
result['list'] = self.getlist(data)
|
|
result['page'] = int(pg)
|
|
result['pagecount'] = 9999
|
|
result['limit'] = 90
|
|
result['total'] = 999999
|
|
return result
|
|
|
|
def playerContent(self, flag, id, vipFlags):
|
|
# 直接返回磁力链接,播放器会处理
|
|
return {'parse': 0, 'url': id, 'header': self.headers}
|
|
|
|
def localProxy(self, param):
|
|
pass
|
|
|
|
def getlist(self, data):
|
|
videos = []
|
|
items = data('.movie-list .item')
|
|
|
|
for item in items.items():
|
|
link_elem = item('a.box')
|
|
if not link_elem:
|
|
continue
|
|
|
|
href = link_elem.attr('href')
|
|
title = self._fix_mojibake((link_elem.attr('title') or '').strip())
|
|
img_src = item('img').attr('src')
|
|
meta_text = self._fix_mojibake((item('.meta').text() or '').strip())
|
|
|
|
videos.append({
|
|
'vod_id': href,
|
|
'vod_name': title,
|
|
'vod_pic': img_src,
|
|
'vod_remarks': meta_text,
|
|
'vod_year': meta_text # 使用日期作为年份
|
|
})
|
|
|
|
return videos
|
|
|
|
def getpq(self, path=''):
|
|
url = f"{self.host}{path}" if not path.startswith('http') else path
|
|
rsp = self.fetch(url, headers=self.headers)
|
|
# Prefer raw bytes to avoid wrong intermediate decoding
|
|
content = rsp.content
|
|
try:
|
|
return pq(content)
|
|
except Exception as e:
|
|
print(f"解析错误: {str(e)}")
|
|
try:
|
|
return pq(content.decode('utf-8', 'ignore'))
|
|
except Exception:
|
|
return pq(rsp.text) |