From 1da99ee52969b3903f058b43309f9af97165c3fe Mon Sep 17 00:00:00 2001 From: qist <87984115@qq.com> Date: Thu, 21 May 2026 19:27:05 +0800 Subject: [PATCH] add --- json/厂长影视.json | 46 ++++ py/czzyv.py | 396 --------------------------------- py/czzyv_v2.py | 531 --------------------------------------------- tools/dianshi.json | 2 +- tools/jsm.json | 1 + 5 files changed, 48 insertions(+), 928 deletions(-) create mode 100644 json/厂长影视.json delete mode 100644 py/czzyv.py delete mode 100644 py/czzyv_v2.py diff --git a/json/厂长影视.json b/json/厂长影视.json new file mode 100644 index 00000000..7b875737 --- /dev/null +++ b/json/厂长影视.json @@ -0,0 +1,46 @@ +{ +"站名":"厂长影视", +"主页url":"https://czzyv.com/", +//发布页https://www.czzy.site/https://www.cz01.vip/ +"请求头": "User-Agent$Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 GLS/100.10.9939.100#Cookie$myannoun=1;sl-session=nifXAZvt5WjqlDh/NcYTUA==;sl-challenge-server=cloud;sl_jwt_session=EQveYsYDV7wH/Wphi/tHVo2pAgUUX3uSIMZ9fWDJtT4OJI8j22NuLwc8mqCbW1a1;sl_jwt_sign=;wordpress_logged_in_748088ce97a4ca7fd21a7d585d745ae0=mimang%7C1759985581%7COXGZlXfKhdGnvczyTtiNwPyeBrEG3eXSJ5t7nZiG3zU%7C6080b1ef7e3be9093358dd9a14d9b1c33a8a3636aa2df11a2bd4b328048b52bb#Referer$https://czzyv.com/", +"二次截取":"
&&
", +"数组":"
  • &&
  • ", +"图片":"data-original=\"&&\"", +"标题":"alt=\"&&\"", +"链接":"href=\"&&\"", +"登陆":"https://czzyv.com/api/vs/session;post;username=824383214@qq.com&password=123456789&email=&url=https://czzyv.com/&invitecode=&linuser=", +"副标题":"qb\">&&", +"线路数组":"
    &&
    ", +"线路标题":"&&", +"播放数组":"
    &&
    ", +"状态":"上映:&&", +"导演":"导演:&&", +"主演":"主演:&&", +"简介":"
    &&

    ", +"播放列表":"", +"播放标题":">&&<", +"播放链接":"href=\"&&\"", +"跳转播放链接":"", + //"搜索标题":"role=\"text\">&&》[替换:>>空>>空]", + //"搜索链接":"href=\"&&\"", +"搜索模式":"1", +"搜索二次截取":"
    &&", +"搜索数组":"
  • &&", +"搜索图片":"src=\"&&\"", +"搜索标题":"alt=\"&&\"", +"搜索链接":"href=\"&&\"", +//"搜索副标题":"class=\"jidi\">&&", +"搜索副标题":"alt=\"&&\"", +"嗅探词":"ssrcdn.com#ctyunxs#124.223.74.47#.m3u8#.mp4#obj/", +//"过滤词":"url=#py1080p.com#cnzz.com#baidu.com#bilibili.com", +"播放请求头":"User-Agent$Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 GLS/100.10.9939.100#Cookie$myannoun=1;sl-challenge-server=cloud;sl-session=oellDmtwrGgTj59GoKOZMg==", +"分类":"国产剧&最新电影&电影&连续剧", +"分类值":"gcj&zuixindianying&movie_bt/movie_bt_series/dyy&dsj", +"分类url":"https://czzyv.com/{cateId}/page/{catePg};;P", + "筛选":"0" +} diff --git a/py/czzyv.py b/py/czzyv.py deleted file mode 100644 index f785343f..00000000 --- a/py/czzyv.py +++ /dev/null @@ -1,396 +0,0 @@ -""" -czzyv.com - 厂长资源 -""" - -import re -import json -import time -from urllib.parse import urljoin, quote, unquote, urlparse, parse_qs - -import requests - -from base.spider import Spider - - -class Spider(Spider): - def __init__(self): - self.host = "https://czzyv.com" - self.timeout = 20 - self._hosts = [ - "https://czzyv.com", - "https://www.czzy.site", - "https://www.cz4k.com", - "https://cz01.vip", - "https://cz01.tv", - ] - self.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36", - "Referer": "https://czzyv.com/", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", - "Accept-Language": "zh-CN,zh;q=0.9", - } - self.session = None - self._text_cache = {} - self._text_cache_ttl = 300 - self._api_base = "" - self._use_api = False - self._ua_fallback = "Dalvik/2.1.0 (Linux; U; Android 10)" - - self._class_map = [ - ("最新电影", "zuixindianying", "/zuixindianying"), - ("豆瓣Top250", "dbtop250", "/dbtop250"), - ("国产剧", "gcj", "/gcj"), - ("美剧", "meijutt", "/meijutt"), - ("韩剧", "hanjutv", "/hanjutv"), - ("日剧", "riju", "/riju"), - ("番剧", "fanju", "/fanju"), - ("剧场版", "dongmanjuchangban", "/dongmanjuchangban"), - ("海外剧", "haiwaijuqita", "/haiwaijuqita"), - ] - self._tid_map = {} - for n, tid, p in self._class_map: - self._tid_map[tid] = p - self._tid_map[n] = p - self._tid_map[p] = p - self._tid_map[p.lstrip("/")] = p - - def getName(self): - return "厂长资源" - - def init(self, extend=""): - if isinstance(extend, dict): - host = (extend.get("host") or extend.get("site") or "").strip() - if host: - self.host = host.rstrip("/") - elif isinstance(extend, str) and extend.strip(): - ext_str = extend.strip() - if (ext_str.startswith("{") and ext_str.endswith("}")) or (ext_str.startswith("[") and ext_str.endswith("]")): - try: - ext_obj = json.loads(ext_str) - if isinstance(ext_obj, dict): - host = (ext_obj.get("host") or ext_obj.get("site") or "").strip() - if host: - self.host = host.rstrip("/") - except Exception: - pass - elif ext_str.startswith("http"): - self.host = ext_str.rstrip("/") - - self.headers["Referer"] = self.host + "/" - self.headers["Origin"] = self.host - self.session = requests.Session() - self.session.headers.update(self.headers) - self._choose_host() - self._detect_api() - self._warmup() - - def isVideoFormat(self, url): - pass - - def manualVideoCheck(self): - pass - - def destroy(self): - pass - - def _choose_host(self): - if not self.session: - return - - candidates = [] - if self.host: - candidates.append(self.host.rstrip("/")) - for h in self._hosts: - h = (h or "").rstrip("/") - if h and h not in candidates: - candidates.append(h) - - for h in candidates: - try: - r = self.session.get(h + "/", timeout=self.timeout, allow_redirects=True, verify=False) - if not r or r.status_code != 200: - continue - r.encoding = "utf-8" - text = r.text or "" - if "访问已被拦截" in text or "已被拦截" in text: - continue - self.host = h - self.headers["Referer"] = self.host + "/" - self.headers["Origin"] = self.host - self.session.headers.update(self.headers) - self._text_cache.clear() - return - except Exception: - continue - - def _detect_api(self): - candidates = [ - "/api.php/provide/vod?ac=list", - "/api.php/provide/vod/?ac=list", - "/index.php/api/vod?ac=list", - ] - for p in candidates: - url = urljoin(self.host + "/", p.lstrip("/")) - try: - r = self.session.get(url, timeout=self.timeout, allow_redirects=True, verify=False) - ct = (r.headers.get("Content-Type") or "").lower() - if r.status_code == 200 and (("json" in ct) or ("xml" in ct) or r.text.strip().startswith(("{", "<"))): - self._api_base = url.split("?", 1)[0] - self._use_api = True - return - except Exception: - continue - self._api_base = "" - self._use_api = False - - def _warmup(self): - try: - self.session.get(self.host + "/", timeout=self.timeout, allow_redirects=True, verify=False) - except Exception: - pass - - def _fetch_text(self, url): - now = time.time() - cached = self._text_cache.get(url) - if cached and cached[0] > now: - return cached[1] - - try: - r = None - for _ in range(3): - try: - r = self.session.get(url, timeout=self.timeout, allow_redirects=True, verify=False) - break - except Exception: - time.sleep(1) - if not r or r.status_code != 200: - if r and r.status_code in (403, 406, 412): - self.session.headers["User-Agent"] = self._ua_fallback - try: - r = self.session.get(url, timeout=self.timeout, allow_redirects=True, verify=False) - except Exception: - r = None - if not r or r.status_code != 200: - return "" - r.encoding = "utf-8" - text = r.text or "" - if "访问已被拦截" in text or "已被拦截" in text: - self.session.headers["User-Agent"] = self._ua_fallback - try: - r2 = self.session.get(url, timeout=self.timeout, allow_redirects=True, verify=False) - if r2 and r2.status_code == 200: - r2.encoding = "utf-8" - text = r2.text or "" - except Exception: - pass - if text: - self._text_cache[url] = (now + self._text_cache_ttl, text) - return text - except Exception: - return "" - - def _abs(self, href): - return urljoin(self.host + "/", href or "") - - def _parse_pagecount(self, html, current_pg): - m = re.findall(r"/page/(\d+)", html or "") - nums = [int(x) for x in m if x.isdigit()] - if nums: - return max(max(nums), current_pg) - return 999 - - def _parse_vod_list(self, html): - html = html or "" - vods = [] - - blocks = re.findall(r"(?is)]*>.*?
  • ", html) - for b in blocks: - if "/movie/" not in b: - continue - m_id = re.search(r'(?is)href=["\'](?:https?://[^"\']+)?/movie/(\d+)\.html["\']', b) - if not m_id: - continue - mid = m_id.group(1) - - m_alt = re.search(r'(?is)]*\balt=["\']([^"\']+)["\']', b) - name = (m_alt.group(1).strip() if m_alt else "") or mid - - m_pic = re.search(r'(?is)]*(?:data-original|data-src|data-lazy-src|src)=["\']([^"\']+)["\']', b) - pic = (m_pic.group(1).strip() if m_pic else "") - - remark = "" - m_qb = re.search(r'(?is)]*class=["\'][^"\']*\bhdinfo\b[^"\']*["\'][^>]*>.*?]*>(.*?)', b) - if m_qb: - remark = re.sub(r"(?is)<[^>]+>", "", m_qb.group(1)).strip() - m_score = re.search(r'(?is)]*class=["\'][^"\']*\brating\b[^"\']*["\'][^>]*>\s*([^<]+)\s*
    ', b) - score = (m_score.group(1).strip() if m_score else "") - if remark and score and score not in remark: - remark = f"{remark} {score}" - elif not remark: - remark = score - - vods.append({"vod_id": mid, "vod_name": name, "vod_pic": pic, "vod_remarks": remark}) - - seen = set() - unique = [] - for v in vods: - if v["vod_id"] in seen: - continue - seen.add(v["vod_id"]) - unique.append(v) - return unique - - def homeContent(self, filter): - result = {"class": [], "list": []} - for name, tid, _ in self._class_map: - result["class"].append({"type_name": name, "type_id": tid}) - - if self._use_api: - return result - - html = self._fetch_text(self.host + "/") - result["list"] = self._parse_vod_list(html)[:24] - return result - - def homeVideoContent(self): - if self._use_api: - return {} - html = self._fetch_text(self.host + "/") - return {"list": self._parse_vod_list(html)[:24]} - - def categoryContent(self, tid, pg, filter, extend): - pg = int(pg or 1) - result = {"list": [], "page": pg, "pagecount": 999, "limit": 24, "total": 0} - - if self._use_api: - return result - - tid = self._tid_map.get(tid, tid) - if tid.startswith("http"): - base = tid - else: - base = self._abs(tid) - - if pg > 1: - if base.endswith("/"): - url = base + f"page/{pg}" - else: - url = base + f"/page/{pg}" - else: - url = base - - html = self._fetch_text(url) - result["list"] = self._parse_vod_list(html) - result["pagecount"] = self._parse_pagecount(html, pg) - result["total"] = result["pagecount"] * result["limit"] - return result - - def detailContent(self, ids): - if not ids or not ids[0]: - return {"list": []} - vid = ids[0] - if vid.startswith("http"): - url = vid - else: - url = f"{self.host}/movie/{vid}.html" - - html = self._fetch_text(url) - name = "" - m_title = re.search(r"(?is)]*>\s*([^<]+)\s*", html or "") - if m_title: - name = m_title.group(1).strip() - - pic = "" - m_pic = re.search(r'(?is)]*class=["\'][^"\']*\bdyimg\b[^"\']*["\'][^>]*>[\s\S]*?]*(?:data-original|data-src|data-lazy-src|src)=["\']([^"\']+)["\']', html or "") - if not m_pic: - m_pic = re.search(r'(?is)]*(?:data-original|data-src|data-lazy-src|src)=["\']([^"\']+)["\']', html or "") - if m_pic: - pic = m_pic.group(1).strip() - - desc = "" - m_desc = re.search(r'(?is)]*class=["\'][^"\']*\byp_context\b[^"\']*["\'][^>]*>\s*([\s\S]*?)\s*
    ', html or "") - if m_desc: - desc = re.sub(r"(?is)<[^>]+>", "", m_desc.group(1)).strip() - - actor = "" - director = "" - m_actor = re.search(r"(?is)主演:\s*([^<\n\r]+)", html or "") - if m_actor: - actor = m_actor.group(1).strip() - m_director = re.search(r"(?is)导演:\s*([^<\n\r]+)", html or "") - if m_director: - director = m_director.group(1).strip() - - play_items = [] - for m in re.finditer(r'(?is)]*href=["\']([^"\']*/v_play/[^"\']+)["\'][^>]*>\s*([^<]+)\s*', html or ""): - href = self._abs(m.group(1).strip()) - t = m.group(2).strip() - if t and href: - play_items.append(f"{t}${href}") - - if not play_items: - play_items.append(f"播放${url}") - - return { - "list": [ - { - "vod_id": vid, - "vod_name": name or vid, - "vod_pic": pic, - "vod_remarks": "", - "vod_year": "", - "type_name": "", - "vod_content": desc, - "vod_actor": actor, - "vod_director": director, - "vod_play_from": "厂长资源", - "vod_play_url": "#".join(play_items), - } - ] - } - - def searchContent(self, key, quick, pg="1"): - if not key: - return {"list": []} - if self._use_api: - return {"list": []} - pg = str(pg or "1") - url = f"{self.host}/boss1O1?q={quote(key)}" - if pg != "1": - url += f"&page={quote(pg)}" - html = self._fetch_text(url) - return {"list": self._parse_vod_list(html)} - - def playerContent(self, flag, id, vipFlags): - h = {"User-Agent": self.headers.get("User-Agent", ""), "Referer": self.host + "/"} - - if not id: - return {"parse": 1, "url": "", "header": h, "playUrl": ""} - - if isinstance(id, str) and (".m3u8" in id or ".mp4" in id) and id.startswith("http"): - return {"parse": 0, "url": id, "header": h, "playUrl": ""} - - play_url = id if id.startswith("http") else self._abs(id) - if "/v_play/" not in play_url: - return {"parse": 1, "url": play_url, "header": h, "playUrl": ""} - - html = self._fetch_text(play_url) - m_iframe = re.search(r'(?is)]*\bsrc=["\']([^"\']+)["\']', html or "") - if m_iframe: - src = m_iframe.group(1).strip() - if src: - qs = parse_qs(urlparse(src).query) - raw = (qs.get("url") or [""])[0] - raw = unquote(raw).strip() - if raw.startswith("http"): - return {"parse": 0, "url": raw, "header": h, "playUrl": ""} - return {"parse": 1, "url": src, "header": h, "playUrl": ""} - - m = re.findall(r'https?://[^\s"\']+?\.(?:m3u8|mp4)(?:\?[^\s"\']*)?', html or "") - if m: - return {"parse": 0, "url": m[0], "header": h, "playUrl": ""} - - return {"parse": 1, "url": play_url, "header": h, "playUrl": ""} - - def localProxy(self, param): - return None diff --git a/py/czzyv_v2.py b/py/czzyv_v2.py deleted file mode 100644 index 7cf384d6..00000000 --- a/py/czzyv_v2.py +++ /dev/null @@ -1,531 +0,0 @@ -""" -czzyv.com - 厂长资源 -""" - -import re -import json -import time -from urllib.parse import urljoin, quote, unquote, urlparse, parse_qs - -import requests - -from base.spider import Spider - - -class Spider(Spider): - def __init__(self): - self.host = "https://czzyv.com" - self.timeout = 20 - self._proxy = "" - self._debug = True - self._cookies = "myannoun=1" - self._hosts = [ - "https://czzyv.com", - ] - self.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36", - "Referer": "https://czzyv.com/", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", - "Accept-Language": "zh-CN,zh;q=0.9", - "Cookie": "myannoun=1", - } - self.session = None - self._text_cache = {} - self._text_cache_ttl = 300 - self._last = {"url": "", "final_url": "", "status": 0, "len": 0, "host": "", "ua": "", "proxy": "", "err": ""} - self._api_base = "" - self._use_api = False - self._ua_fallback = "Dalvik/2.1.0 (Linux; U; Android 10)" - - self._class_map = [ - ("最新电影", "zuixindianying", "/zuixindianying"), - ("豆瓣Top250", "dbtop250", "/dbtop250"), - ("国产剧", "gcj", "/gcj"), - ("美剧", "meijutt", "/meijutt"), - ("韩剧", "hanjutv", "/hanjutv"), - ("日剧", "riju", "/riju"), - ("番剧", "fanju", "/fanju"), - ("剧场版", "dongmanjuchangban", "/dongmanjuchangban"), - ("海外剧", "haiwaijuqita", "/haiwaijuqita"), - ] - self._tid_map = {} - for n, tid, p in self._class_map: - self._tid_map[tid] = p - self._tid_map[n] = p - self._tid_map[p] = p - self._tid_map[p.lstrip("/")] = p - - def getName(self): - return "厂长资源" - - def _log(self, data): - if not self._debug: - return - try: - fn = getattr(self, "log", None) - if callable(fn): - fn(data) - else: - if isinstance(data, (dict, list)): - print(json.dumps(data, ensure_ascii=False)) - else: - print(str(data)) - except Exception: - pass - - def init(self, extend=""): - proxy = "" - debug = None - cookies = "" - if isinstance(extend, dict): - host = (extend.get("host") or extend.get("site") or "").strip() - if host: - self.host = host.rstrip("/") - proxy = (extend.get("proxy") or extend.get("http_proxy") or extend.get("https_proxy") or "").strip() - debug = extend.get("debug") - cookies = (extend.get("cookie") or extend.get("cookies") or "").strip() - elif isinstance(extend, str) and extend.strip(): - ext_str = extend.strip() - if (ext_str.startswith("{") and ext_str.endswith("}")) or (ext_str.startswith("[") and ext_str.endswith("]")): - try: - ext_obj = json.loads(ext_str) - if isinstance(ext_obj, dict): - host = (ext_obj.get("host") or ext_obj.get("site") or "").strip() - if host: - self.host = host.rstrip("/") - proxy = (ext_obj.get("proxy") or ext_obj.get("http_proxy") or ext_obj.get("https_proxy") or "").strip() - debug = ext_obj.get("debug") - cookies = (ext_obj.get("cookie") or ext_obj.get("cookies") or "").strip() - except Exception: - pass - elif ext_str.startswith("http"): - self.host = ext_str.rstrip("/") - - if debug is not None: - self._debug = bool(debug) - if cookies: - self._cookies = cookies - - self.headers["Referer"] = self.host + "/" - self.headers["Origin"] = self.host - self.headers["Cookie"] = self._cookies - self.session = requests.Session() - self.session.headers.update(self.headers) - self._proxy = proxy - if proxy: - self.session.proxies.update({"http": proxy, "https": proxy}) - self._log({"event": "init", "host": self.host, "proxy": self._proxy, "ua": self.session.headers.get("User-Agent", ""), "cookie": self._cookies}) - self._choose_host() - self._detect_api() - self._warmup() - - def isVideoFormat(self, url): - pass - - def manualVideoCheck(self): - pass - - def destroy(self): - pass - - def _choose_host(self): - if not self.session: - return - - candidates = [] - if self.host: - candidates.append(self.host.rstrip("/")) - for h in self._hosts: - h = (h or "").rstrip("/") - if h and h not in candidates: - candidates.append(h) - - for h in candidates: - try: - r = self.session.get(h + "/", timeout=self.timeout, allow_redirects=True, verify=False) - if not r or r.status_code != 200: - self._log({"event": "choose_host", "try": h, "status": int(r.status_code) if r else 0, "final_url": r.url if r else ""}) - continue - try: - if urlparse(r.url).netloc != urlparse(h).netloc: - self._log({"event": "choose_host", "try": h, "status": int(r.status_code), "final_url": r.url, "skip": "redirect"}) - continue - except Exception: - pass - r.encoding = "utf-8" - text = r.text or "" - if "访问已被拦截" in text or "已被拦截" in text: - self._log({"event": "choose_host", "try": h, "status": int(r.status_code), "final_url": r.url, "skip": "blocked"}) - continue - if ("公告" in text and "域名" in text) or ("最新发布" in text) or ("备用网址" in text): - self._log({"event": "choose_host", "try": h, "status": int(r.status_code), "final_url": r.url, "skip": "notice"}) - continue - self.host = h - self.headers["Referer"] = self.host + "/" - self.headers["Origin"] = self.host - self.session.headers.update(self.headers) - self._text_cache.clear() - self._log({"event": "choose_host", "ok": True, "host": self.host, "final_url": r.url}) - return - except Exception: - self._log({"event": "choose_host", "try": h, "ok": False, "err": "exception"}) - continue - self._log({"event": "choose_host", "ok": False, "host": self.host}) - - def _detect_api(self): - candidates = [ - "/api.php/provide/vod?ac=list", - "/api.php/provide/vod/?ac=list", - "/index.php/api/vod?ac=list", - ] - for p in candidates: - url = urljoin(self.host + "/", p.lstrip("/")) - try: - r = self.session.get(url, timeout=self.timeout, allow_redirects=True, verify=False) - ct = (r.headers.get("Content-Type") or "").lower() - if r.status_code == 200 and (("json" in ct) or ("xml" in ct) or r.text.strip().startswith(("{", "<"))): - self._api_base = url.split("?", 1)[0] - self._use_api = True - return - except Exception: - continue - self._api_base = "" - self._use_api = False - - def _warmup(self): - try: - self.session.get(self.host + "/", timeout=self.timeout, allow_redirects=True, verify=False) - except Exception: - pass - - def _fetch_text(self, url): - now = time.time() - cached = self._text_cache.get(url) - if cached and cached[0] > now: - return cached[1] - - try: - r = None - last_exc = "" - for _ in range(3): - try: - r = self.session.get(url, timeout=self.timeout, allow_redirects=True, verify=False) - break - except Exception as e: - last_exc = f"{type(e).__name__}: {e}" - time.sleep(1) - if r is None: - try: - r = requests.get( - url, - headers=(self.session.headers if self.session else self.headers), - timeout=self.timeout, - allow_redirects=True, - verify=False, - proxies=(self.session.proxies if self.session else None), - ) - except Exception as e: - if not last_exc: - last_exc = f"{type(e).__name__}: {e}" - if not r or r.status_code != 200: - if r and r.status_code in (403, 406, 412): - self.session.headers["User-Agent"] = self._ua_fallback - try: - r = self.session.get(url, timeout=self.timeout, allow_redirects=True, verify=False) - except Exception: - r = None - if not r or r.status_code != 200: - self._last = { - "url": url, - "final_url": r.url if r else "", - "status": int(r.status_code) if r else 0, - "len": 0, - "host": self.host, - "ua": (self.session.headers.get("User-Agent") if self.session else ""), - "proxy": self._proxy, - "err": last_exc or ("no_response" if r is None else "bad_status"), - } - self._log({"event": "fetch", **self._last}) - return "" - r.encoding = "utf-8" - text = r.text or "" - if "访问已被拦截" in text or "已被拦截" in text: - self.session.headers["User-Agent"] = self._ua_fallback - try: - r2 = self.session.get(url, timeout=self.timeout, allow_redirects=True, verify=False) - if r2 and r2.status_code == 200: - r2.encoding = "utf-8" - text = r2.text or "" - except Exception: - pass - self._last = { - "url": url, - "final_url": r.url if r else "", - "status": int(r.status_code) if r else 0, - "len": len(text), - "host": self.host, - "ua": (self.session.headers.get("User-Agent") if self.session else ""), - "proxy": self._proxy, - "err": "", - } - if not text: - self._log({"event": "fetch", **self._last, "warn": "empty_text"}) - if text: - self._text_cache[url] = (now + self._text_cache_ttl, text) - return text - except Exception as e: - self._last = { - "url": url, - "final_url": "", - "status": 0, - "len": 0, - "host": self.host, - "ua": (self.session.headers.get("User-Agent") if self.session else ""), - "proxy": self._proxy, - "err": f"{type(e).__name__}: {e}", - } - self._log({"event": "fetch", **self._last}) - return "" - - def _debug_item(self, tag): - last = self._last or {} - remark = f'{tag} status={last.get("status")} len={last.get("len")} host={last.get("host")}' - err = last.get("err") or "" - if err: - remark = remark + f" err={err}" - return {"vod_id": f"debug@{tag}", "vod_name": f"DEBUG-{tag}", "vod_pic": "", "vod_remarks": remark} - - def _abs(self, href): - return urljoin(self.host + "/", href or "") - - def _parse_pagecount(self, html, current_pg): - m = re.findall(r"/page/(\d+)", html or "") - nums = [int(x) for x in m if x.isdigit()] - if nums: - return max(max(nums), current_pg) - return 999 - - def _parse_vod_list(self, html): - html = html or "" - vods = [] - - blocks = re.findall(r"(?is)]*>.*?", html) - for b in blocks: - if "/movie/" not in b: - continue - m_id = re.search(r'(?is)href=["\'](?:https?://[^"\']+)?/movie/(\d+)\.html["\']', b) - if not m_id: - continue - mid = m_id.group(1) - - m_alt = re.search(r'(?is)]*\balt=["\']([^"\']+)["\']', b) - name = (m_alt.group(1).strip() if m_alt else "") or mid - - m_pic = re.search(r'(?is)]*(?:data-original|data-src|data-lazy-src|src)=["\']([^"\']+)["\']', b) - pic = (m_pic.group(1).strip() if m_pic else "") - - remark = "" - m_qb = re.search(r'(?is)]*class=["\'][^"\']*\bhdinfo\b[^"\']*["\'][^>]*>.*?]*>(.*?)', b) - if m_qb: - remark = re.sub(r"(?is)<[^>]+>", "", m_qb.group(1)).strip() - m_score = re.search(r'(?is)]*class=["\'][^"\']*\brating\b[^"\']*["\'][^>]*>\s*([^<]+)\s*
    ', b) - score = (m_score.group(1).strip() if m_score else "") - if remark and score and score not in remark: - remark = f"{remark} {score}" - elif not remark: - remark = score - - vods.append({"vod_id": mid, "vod_name": name, "vod_pic": pic, "vod_remarks": remark}) - - seen = set() - unique = [] - for v in vods: - if v["vod_id"] in seen: - continue - seen.add(v["vod_id"]) - unique.append(v) - return unique - - def homeContent(self, filter): - result = {"class": [], "list": []} - for name, tid, _ in self._class_map: - result["class"].append({"type_name": name, "type_id": tid}) - - if self._use_api: - return result - - html = self._fetch_text(self.host + "/") - result["list"] = self._parse_vod_list(html)[:24] - return result - - def homeVideoContent(self): - if self._use_api: - return {} - html = self._fetch_text(self.host + "/") - vods = self._parse_vod_list(html)[:24] - if not vods: - vods = [self._debug_item("home")] - return {"list": vods} - - def categoryContent(self, tid, pg, filter, extend): - pg = int(pg or 1) - result = {"list": [], "page": pg, "pagecount": 999, "limit": 24, "total": 0} - - if self._use_api: - return result - - tid = self._tid_map.get(tid, tid) - if tid.startswith("http"): - base = tid - else: - base = self._abs(tid) - - if pg > 1: - if base.endswith("/"): - url = base + f"page/{pg}" - else: - url = base + f"/page/{pg}" - else: - url = base - - html = self._fetch_text(url) - result["list"] = self._parse_vod_list(html) - if not result["list"]: - result["list"] = [self._debug_item("cate")] - result["pagecount"] = self._parse_pagecount(html, pg) - result["total"] = result["pagecount"] * result["limit"] - return result - - def detailContent(self, ids): - if not ids or not ids[0]: - return {"list": []} - vid = ids[0] - if isinstance(vid, str) and vid.startswith("debug@"): - last = self._last or {} - content = json.dumps(last, ensure_ascii=False) - play_url = last.get("url") or "" - play_url = play_url if isinstance(play_url, str) else "" - play_from = "DEBUG" - play = f'请求URL${play_url}' if play_url else "" - return { - "list": [ - { - "vod_id": vid, - "vod_name": "DEBUG", - "vod_pic": "", - "vod_remarks": "", - "vod_year": "", - "type_name": "", - "vod_content": content, - "vod_actor": "", - "vod_director": "", - "vod_play_from": play_from, - "vod_play_url": play, - } - ] - } - if vid.startswith("http"): - url = vid - else: - url = f"{self.host}/movie/{vid}.html" - - html = self._fetch_text(url) - name = "" - m_title = re.search(r"(?is)]*>\s*([^<]+)\s*", html or "") - if m_title: - name = m_title.group(1).strip() - - pic = "" - m_pic = re.search(r'(?is)]*class=["\'][^"\']*\bdyimg\b[^"\']*["\'][^>]*>[\s\S]*?]*(?:data-original|data-src|data-lazy-src|src)=["\']([^"\']+)["\']', html or "") - if not m_pic: - m_pic = re.search(r'(?is)]*(?:data-original|data-src|data-lazy-src|src)=["\']([^"\']+)["\']', html or "") - if m_pic: - pic = m_pic.group(1).strip() - - desc = "" - m_desc = re.search(r'(?is)]*class=["\'][^"\']*\byp_context\b[^"\']*["\'][^>]*>\s*([\s\S]*?)\s*', html or "") - if m_desc: - desc = re.sub(r"(?is)<[^>]+>", "", m_desc.group(1)).strip() - - actor = "" - director = "" - m_actor = re.search(r"(?is)主演:\s*([^<\n\r]+)", html or "") - if m_actor: - actor = m_actor.group(1).strip() - m_director = re.search(r"(?is)导演:\s*([^<\n\r]+)", html or "") - if m_director: - director = m_director.group(1).strip() - - play_items = [] - for m in re.finditer(r'(?is)]*href=["\']([^"\']*/v_play/[^"\']+)["\'][^>]*>\s*([^<]+)\s*', html or ""): - href = self._abs(m.group(1).strip()) - t = m.group(2).strip() - if t and href: - play_items.append(f"{t}${href}") - - if not play_items: - play_items.append(f"播放${url}") - - return { - "list": [ - { - "vod_id": vid, - "vod_name": name or vid, - "vod_pic": pic, - "vod_remarks": "", - "vod_year": "", - "type_name": "", - "vod_content": desc, - "vod_actor": actor, - "vod_director": director, - "vod_play_from": "厂长资源", - "vod_play_url": "#".join(play_items), - } - ] - } - - def searchContent(self, key, quick, pg="1"): - if not key: - return {"list": []} - if self._use_api: - return {"list": []} - pg = str(pg or "1") - url = f"{self.host}/boss1O1?q={quote(key)}" - if pg != "1": - url += f"&page={quote(pg)}" - html = self._fetch_text(url) - return {"list": self._parse_vod_list(html)} - - def playerContent(self, flag, id, vipFlags): - h = {"User-Agent": self.headers.get("User-Agent", ""), "Referer": self.host + "/"} - - if not id: - return {"parse": 1, "url": "", "header": h, "playUrl": ""} - - if isinstance(id, str) and (".m3u8" in id or ".mp4" in id) and id.startswith("http"): - return {"parse": 0, "url": id, "header": h, "playUrl": ""} - - play_url = id if id.startswith("http") else self._abs(id) - if "/v_play/" not in play_url: - return {"parse": 1, "url": play_url, "header": h, "playUrl": ""} - - html = self._fetch_text(play_url) - m_iframe = re.search(r'(?is)]*\bsrc=["\']([^"\']+)["\']', html or "") - if m_iframe: - src = m_iframe.group(1).strip() - if src: - qs = parse_qs(urlparse(src).query) - raw = (qs.get("url") or [""])[0] - raw = unquote(raw).strip() - if raw.startswith("http"): - return {"parse": 0, "url": raw, "header": h, "playUrl": ""} - return {"parse": 1, "url": src, "header": h, "playUrl": ""} - - m = re.findall(r'https?://[^\s"\']+?\.(?:m3u8|mp4)(?:\?[^\s"\']*)?', html or "") - if m: - return {"parse": 0, "url": m[0], "header": h, "playUrl": ""} - - return {"parse": 1, "url": play_url, "header": h, "playUrl": ""} - - def localProxy(self, param): - return None diff --git a/tools/dianshi.json b/tools/dianshi.json index f9186920..bb5c0a90 100644 --- a/tools/dianshi.json +++ b/tools/dianshi.json @@ -13,7 +13,7 @@ {"key":"闪雷","name":"闪雷┃MP4","type":3,"api":"./lib/drpy2.min.js","ext":"./js/678.js","header":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"}}, {"key":"fyyy","name":"飞宇影院","type":3,"api":"csp_XBPQ","searchable":1,"quickSearch":1,"filterable":1,"changeable":1,"ext":{"分类url":"http://ntfeiyu.com/nt/{cateId}/area/{area}/by/{by}/class/{class}/lang/{lang}/page/{catePg}/year/{year}.html","分类":"电影$1#电视剧$2#综艺$3#动漫$4"},"header":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"}}, {"key":"cupfox_in","name":"茶杯狐┃cupfox.in","type":3,"api":"./lib/drpy2.min.js","ext":"./js/茶杯狐.js","searchable":1,"quickSearch":1,"filterable":0,"changeable":1,"header":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"}}, -{"key": "czzyv","name": "厂长 | 影视","type": 3,"api": "./py/czzyv_v2.py","searchable": 1,"quickSearch": 1,"filterable": 0,"changeable": 1,"header":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36","Referer":"https://czzyv.com/"}}, +{"key":"czzyv","name":"厂长影视","type":3,"api":"csp_XBPQ","searchable":1,"quickSearch":1,"filterable":1,"changeable":1,"ext":"./json/厂长影视.json","header":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"}}, {"key": "libvio","name": "libvio | 影视","type": 3,"api": "./py/libvio.py","searchable": 1,"quickSearch": 1,"filterable": 0,"changeable": 1}, {"key":"italkbbtv","name":"ITalkBB | 外","type":3,"api":"./py/ITalkBBTV.py","searchable":1,"quickSearch":1,"filterable":0,"changeable":1}, {"key":"qiletv","name":"奇乐影视","type":3,"api":"csp_XBPQ","searchable":1,"quickSearch":1,"filterable":1,"changeable":1,"ext":"./json/奇乐.json","header":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"}}, diff --git a/tools/jsm.json b/tools/jsm.json index 76f8aa7b..28b2b1e8 100644 --- a/tools/jsm.json +++ b/tools/jsm.json @@ -14,6 +14,7 @@ {"key":"新闪雷","name":"新闪雷┃MP4","type":3,"api":"./lib/drpy2.min.js","ext":"./js/新闪雷.js","header":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"}}, {"key":"fyyy","name":"飞宇影院","type":3,"api":"csp_XBPQ","searchable":1,"quickSearch":1,"filterable":1,"changeable":1,"ext":{"分类url":"http://ntfeiyu.com/nt/{cateId}/area/{area}/by/{by}/class/{class}/lang/{lang}/page/{catePg}/year/{year}.html","分类":"电影$1#电视剧$2#综艺$3#动漫$4"},"header":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"}}, {"key":"cupfox_in","name":"茶杯狐┃cupfox.in","type":3,"api":"./lib/drpy2.min.js","ext":"./js/茶杯狐.js","searchable":1,"quickSearch":1,"filterable":0,"changeable":1,"header":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"}}, +{"key":"czzyv","name":"厂长影视","type":3,"api":"csp_XBPQ","searchable":1,"quickSearch":1,"filterable":1,"changeable":1,"ext":"./json/厂长影视.json","header":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"}}, {"key": "libvio","name": "libvio|影视","type": 3,"api": "./py/libvio.py","searchable": 1,"quickSearch": 1,"filterable": 0,"changeable": 1}, {"key":"italkbbtv","name":"ITalkBB|外","type":3,"api":"./py/ITalkBBTV.py","searchable":1,"quickSearch":1,"filterable":0,"changeable":1}, {"key":"qiletv","name":"奇乐影视","type":3,"api":"csp_XBPQ","searchable":1,"quickSearch":1,"filterable":1,"changeable":1,"ext":"./json/奇乐.json","header":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"}},