Files
a/PY1/103.py
2026-03-24 18:40:17 +08:00

266 lines
9.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# coding=utf-8
import re
import sys
import urllib.parse
import json
from pyquery import PyQuery as pq
import requests
sys.path.append('..')
from base.spider import Spider as BaseSpider
class Spider(BaseSpider):
def __init__(self):
super().__init__()
self.base_url = "http://oxax.tv"
self.session = requests.Session()
self.session.headers.update({
'User-Agent': (
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/120.0.0.0 Safari/537.36'
),
'Referer': self.base_url,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
})
# 完整的频道列表从实际页面提取的40个频道
self.all_channels = [
{"title": "ОХ-АХ HD", "href": "/oh-ah.html"},
{"title": "CineMan XXX HD", "href": "/sl-hot1.html"},
{"title": "CineMan XXX2 HD", "href": "/sl-hot2.html"},
{"title": "Brazzers TV Europe", "href": "/brazzers-tv-europe.html"},
{"title": "Brazzers TV", "href": "/brazzers-tv.html"},
{"title": "Red Lips", "href": "/red-lips.html"},
{"title": "KinoXXX", "href": "/kino-xxx.html"},
{"title": "XY Max HD", "href": "/xy-max-hd.html"},
{"title": "XY Plus HD", "href": "/xy-plus-hd.html"},
{"title": "XY Mix HD", "href": "/xy-mix-hd.html"},
{"title": "Barely legal", "href": "/barely-legal.html"},
{"title": "Playboy TV", "href": "/playboy-tv.html"},
{"title": "Vivid Red HD", "href": "/vivid-red.html"},
{"title": "Exxxotica HD", "href": "/hot-pleasure.html"},
{"title": "Babes TV", "href": "/babes-tv.html"},
{"title": "Русская ночь", "href": "/russkaya-noch.html"},
{"title": "Pink O TV", "href": "/pink-o.html"},
{"title": "Erox HD", "href": "/erox-hd.html"},
{"title": "Eroxxx HD", "href": "/eroxxx-hd.html"},
{"title": "Hustler HD", "href": "/hustler-hd.html"},
{"title": "Private TV", "href": "/private-tv.html"},
{"title": "Redlight HD", "href": "/redlight-hd.html"},
{"title": "Penthouse Gold HD", "href": "/penthouse-gold.html"},
{"title": "Penthouse Quickies", "href": "/penthouse-2.html"},
{"title": "O-la-la", "href": "/o-la-la.html"},
{"title": "Blue Hustler", "href": "/blue-hustler.html"},
{"title": "Шалун", "href": "/shalun.html"},
{"title": "Dorcel TV", "href": "/dorcel-tv.html"},
{"title": "Extasy HD", "href": "/extasyhd.html"},
{"title": "XXL", "href": "/xxl.html"},
{"title": "FAP TV 2", "href": "/fap-tv-2.html"},
{"title": "FAP TV 3", "href": "/fap-tv-3.html"},
{"title": "FAP TV 4", "href": "/fap-tv-4.html"},
{"title": "FAP TV Parody", "href": "/fap-tv-parody.html"},
{"title": "FAP TV Compilation", "href": "/fap-tv-compilation.html"},
{"title": "FAP TV Anal", "href": "/fap-tv-anal.html"},
{"title": "FAP TV Teens", "href": "/fap-tv-teens.html"},
{"title": "FAP TV Lesbian", "href": "/fap-tv-lesbian.html"},
{"title": "FAP TV BBW", "href": "/fap-tv-bbw.html"},
{"title": "FAP TV Trans", "href": "/fap-tv-trans.html"},
]
# ========= 工具方法 =========
def _abs_url(self, base, url):
"""转换为绝对URL"""
if not url:
return ''
if url.startswith('http'):
return url
if url.startswith('//'):
return 'http:' + url
if url.startswith('/'):
return self.base_url + url
return base.rsplit('/', 1)[0] + '/' + url
def _get_channel_image(self, channel_name):
"""根据频道名称生成图片URL使用占位图"""
# 为每个频道生成唯一的颜色
color_map = {
'brazzers': 'FFD700', 'playboy': 'FF69B4', 'hustler': 'DC143C',
'penthouse': '9370DB', 'vivid': 'FF1493', 'private': '8B008B',
'dorcel': 'FF6347', 'cineman': '4169E1', 'fap': 'FF4500',
'xy': 'DA70D6', 'erox': 'FF00FF', 'kino': '8A2BE2',
}
color = '1E90FF' # 默认蓝色
name_lower = channel_name.lower()
for key, col in color_map.items():
if key in name_lower:
color = col
break
text = urllib.parse.quote(channel_name[:20])
return f"https://via.placeholder.com/400x225/{color}/FFFFFF?text={text}"
# ========= Spider接口实现 =========
def getName(self):
return "OXAX直播"
def init(self, extend):
pass
def homeContent(self, filter):
"""返回分类列表"""
return {
'class': [
{'type_name': '全部频道', 'type_id': 'all'},
{'type_name': 'HD频道', 'type_id': 'hd'},
{'type_name': 'FAP系列', 'type_id': 'fap'},
]
}
def homeVideoContent(self):
"""首页推荐 - 显示所有频道"""
videos = []
for ch in self.all_channels:
videos.append({
'vod_id': ch['href'],
'vod_name': ch['title'],
'vod_pic': self._get_channel_image(ch['title']),
'vod_remarks': '直播',
})
return {'list': videos}
def categoryContent(self, tid, pg, filter, extend):
"""分类内容 - 支持分页和过滤"""
pg = int(pg)
items_per_page = 30
# 根据分类ID过滤频道
if tid == 'hd':
channels = [ch for ch in self.all_channels if 'HD' in ch['title'].upper()]
elif tid == 'fap':
channels = [ch for ch in self.all_channels if 'FAP' in ch['title'].upper()]
else: # all
channels = self.all_channels
# 分页
start = (pg - 1) * items_per_page
end = start + items_per_page
page_channels = channels[start:end]
# 构建视频列表
videos = []
for ch in page_channels:
videos.append({
'vod_id': ch['href'],
'vod_name': ch['title'],
'vod_pic': self._get_channel_image(ch['title']),
'vod_remarks': '直播',
})
return {
'list': videos,
'page': pg,
'pagecount': max(1, (len(channels) + items_per_page - 1) // items_per_page),
'limit': items_per_page,
'total': len(channels),
}
def detailContent(self, array):
"""详情页 - 直接返回页面URL不做m3u8提取"""
if not array or not array[0]:
return {'list': []}
relative_path = array[0]
detail_url = self._abs_url(self.base_url, relative_path)
# 提取标题(从相对路径推断)
title = relative_path.replace('.html', '').replace('/', '').replace('-', ' ').title()
# 从 all_channels 查找真实标题
for ch in self.all_channels:
if ch['href'] == relative_path:
title = ch['title']
break
vod = {
'vod_id': relative_path,
'vod_name': title,
'vod_pic': self._get_channel_image(title),
'vod_remarks': '直播',
'vod_content': '成人电视直播频道',
'vod_play_from': 'OXAX',
'vod_play_url': f'{title}${detail_url}',
}
return {'list': [vod]}
def searchContent(self, key, quick, page='1'):
"""搜索功能"""
if not key:
return {'list': []}
key_lower = key.lower()
results = []
# 在本地频道列表中搜索
for ch in self.all_channels:
if key_lower in ch['title'].lower():
results.append({
'vod_id': ch['href'],
'vod_name': ch['title'],
'vod_pic': self._get_channel_image(ch['title']),
'vod_remarks': '直播',
})
return {'list': results}
def playerContent(self, flag, id, vipFlags):
"""
播放器内容解析 - 关键修改点
直接返回 video:// 协议的URL让播放器自行解析页面
"""
result = {
"parse": 0,
"playUrl": "",
"url": "",
"header": {
"User-Agent": self.session.headers.get('User-Agent'),
"Referer": self.base_url
}
}
if not id:
return result
try:
# id格式: "标题$URL"
url = id
if '$' in url:
url = url.split('$')[1]
result["url"] = f"video://{url}"
except Exception as e:
print(f"[ERROR] 播放器解析失败: {e}")
return result
def isVideoFormat(self, url):
"""判断是否为视频格式 - video:// 协议不是直接的视频格式"""
return False
def manualVideoCheck(self):
"""不需要手动视频检查"""
return False
def localProxy(self, param):
"""不使用本地代理"""
return {}