From 9043a859b9ca773d01d539b2a0d090f696755bfa Mon Sep 17 00:00:00 2001 From: "Wang.Luo" <1593775941@qq.com> Date: Sun, 12 Oct 2025 14:44:22 +0800 Subject: [PATCH] =?UTF-8?q?```=20feat(adult):=20=E6=9B=B4=E6=96=B0cam4?= =?UTF-8?q?=E7=9B=B4=E6=92=AD=E6=BA=90=E9=85=8D=E7=BD=AE=E5=B9=B6=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E7=88=AC=E8=99=AB=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除旧的cam4和恰逢好色直播接口,添加新的cam4直播爬虫实现。 支持分类筛选、搜索及播放功能,优化直播内容展示。 ``` --- adult.json | 15 +++--- py/adult/cam4.py | 118 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 9 deletions(-) create mode 100644 py/adult/cam4.py diff --git a/adult.json b/adult.json index 0c78a43..2b51c68 100644 --- a/adult.json +++ b/adult.json @@ -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": [ diff --git a/py/adult/cam4.py b/py/adult/cam4.py new file mode 100644 index 0000000..f9ac6fa --- /dev/null +++ b/py/adult/cam4.py @@ -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 \ No newline at end of file