feat(adult): 更新cam4直播源配置并新增爬虫脚本

移除旧的cam4和恰逢好色直播接口,添加新的cam4直播爬虫实现。
支持分类筛选、搜索及播放功能,优化直播内容展示。
```
This commit is contained in:
Wang.Luo 2025-10-12 14:44:22 +08:00
parent f787529952
commit 9043a859b9
2 changed files with 124 additions and 9 deletions

View File

@ -1339,16 +1339,13 @@
}
},
{
"api": "https://learnpython.ggff.net/cam4",
"key": "cam4",
"name": "cam4",
"type": 4
},
{
"api": "https://learnpython.ggff.net/hsTV",
"key": "恰逢好色",
"name": "恰逢好色",
"type": 4
"name": "cam4直播",
"type": 3,
"api": "./py/adult/cam4.py",
"searchable": 1,
"quickSearch": 1,
"filterable": 1
}
],
"lives": [

118
py/adult/cam4.py Normal file
View File

@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
import json
import time
from base.spider import Spider
class Spider(Spider):
def getName(self):
return "Cam4直播"
def init(self, extend=""):
self.base = "https://zh.cam4.com"
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}
return self
def homeContent(self, filter):
classes = [
{"type_id": "all", "type_name": "全部"},
{"type_id": "female", "type_name": "女性"},
{"type_id": "male", "type_name": "男性"},
{"type_id": "couples", "type_name": "情侣"},
{"type_id": "shemale", "type_name": "变性"},
]
return {"class": classes}
def categoryContent(self, tid, pg, filter, extend):
if not pg:
pg = 1
params = f"?directoryJson=true&online=true&url=true&page={pg}"
if tid == "female":
params += "&gender=female"
elif tid == "male":
params += "&gender=male"
elif tid == "couples":
params += "&broadcastType=male_female_group"
elif tid == "shemale":
params += "&gender=shemale"
url = f"{self.base}/directoryCams{params}"
rsp = self.fetch(url, headers=self.headers)
data = rsp.text
try:
jRoot = json.loads(data)
except:
return {"list": []}
videos = []
for u in jRoot.get("users", []):
title = f"{u.get('username')} ({u.get('countryCode', '')})"
if "age" in u:
title += f" - {u['age']}"
if "resolution" in u:
res = u["resolution"].split(":")[-1]
title += f" [HD:{res}]"
video = {
"vod_id": u.get("hlsPreviewUrl"),
"vod_name": title,
"vod_pic": u.get("snapshotImageLink", ""),
"vod_remarks": u.get("statusMessage", ""),
}
videos.append(video)
result = {
"list": videos,
"page": int(pg),
"pagecount": 9999,
"limit": 90,
"total": len(videos)
}
return result
def detailContent(self, ids):
id = ids[0]
vod = {
"vod_id": id,
"vod_name": "Cam4直播",
"vod_pic": "",
"vod_play_from": "Cam4",
"vod_play_url": f"直播源${id}",
}
return {"list": [vod]}
def playerContent(self, flag, id, vipFlags):
play_url = id
return {
"parse": 0,
"playUrl": "",
"url": play_url,
"header": self.headers
}
def searchContent(self, key, quick, pg="1"):
url = f"{self.base}/directoryCams?directoryJson=true&online=true&url=true&showTag={key}&page={pg}"
rsp = self.fetch(url, headers=self.headers)
data = rsp.text
try:
jRoot = json.loads(data)
except:
return {"list": []}
videos = []
for u in jRoot.get("users", []):
title = f"{u.get('username')} ({u.get('countryCode', '')})"
video = {
"vod_id": u.get("hlsPreviewUrl"),
"vod_name": title,
"vod_pic": u.get("snapshotImageLink", ""),
"vod_remarks": u.get("statusMessage", ""),
}
videos.append(video)
return {"list": videos}
def isVideoFormat(self, url):
return ".m3u8" in url
def manualVideoCheck(self):
return True