193 lines
5.8 KiB
Python
193 lines
5.8 KiB
Python
#coding=utf-8
|
||
#!/usr/bin/python
|
||
import sys
|
||
sys.dont_write_bytecode = True # ✅ 禁止生成 __pycache__ 编译缓存
|
||
|
||
import re
|
||
import os
|
||
import json
|
||
import time
|
||
import requests
|
||
from lxml import etree
|
||
from abc import ABCMeta
|
||
from importlib.machinery import SourceFileLoader
|
||
|
||
# ============================================================
|
||
# 模拟 Android 的 Proxy 和 Python 模块(无缓存路径版本)
|
||
# ============================================================
|
||
|
||
class Proxy:
|
||
@staticmethod
|
||
def getUrl(local=True):
|
||
return "http://127.0.0.1:9978"
|
||
|
||
@staticmethod
|
||
def getPort():
|
||
return 9978
|
||
|
||
|
||
class Python:
|
||
class Platform:
|
||
def __init__(self):
|
||
# 不使用任何缓存目录
|
||
self.cache_dir = os.getcwd()
|
||
|
||
def getApplication(self):
|
||
return self
|
||
|
||
def getCacheDir(self):
|
||
class Cache:
|
||
def getAbsolutePath(inner_self):
|
||
# 始终返回当前工作目录
|
||
return self.cache_dir
|
||
return Cache()
|
||
|
||
@staticmethod
|
||
def getPlatform():
|
||
return Python.Platform()
|
||
|
||
|
||
# ============================================================
|
||
# Spider 主类(无缓存、实时加载、无 __pycache__)
|
||
# ============================================================
|
||
|
||
class Spider(metaclass=ABCMeta):
|
||
_instance = None
|
||
|
||
def __init__(self):
|
||
self.extend = ''
|
||
|
||
def __new__(cls, *args, **kwargs):
|
||
if cls._instance:
|
||
return cls._instance
|
||
else:
|
||
cls._instance = super().__new__(cls)
|
||
return cls._instance
|
||
|
||
def init(self, extend=""):
|
||
self.extend = extend
|
||
|
||
# -------------------------------
|
||
# 核心内容接口
|
||
# -------------------------------
|
||
def homeContent(self, filter):
|
||
return {"class": [], "list": []}
|
||
|
||
def homeVideoContent(self):
|
||
return []
|
||
|
||
def categoryContent(self, cid=None, page="1", filter=None, ext=None):
|
||
print(f"[调试] categoryContent called with cid={cid}, page={page}, ext={ext}")
|
||
return {"class": [{"type_name": "示例分类", "type_id": "1"}], "list": [], "page": page}
|
||
|
||
def detailContent(self, ids):
|
||
return {"list": [{"vod_id": ids, "vod_name": "示例视频"}]}
|
||
|
||
def searchContent(self, key, quick, pg="1"):
|
||
return {"list": [{"vod_id": "1", "vod_name": f"搜索结果: {key}"}]}
|
||
|
||
def playerContent(self, flag, flag_id=None, vipFlags=None):
|
||
if flag_id is None and hasattr(self, 'id'):
|
||
flag_id = self.id
|
||
print(f"[调试] playerContent called with flag={flag}, flag_id={flag_id}, vipFlags={vipFlags}")
|
||
return {"url": f"http://example.com/{flag_id}.m3u8", "parse": 0}
|
||
|
||
def liveContent(self, url):
|
||
return {}
|
||
|
||
def localProxy(self, param):
|
||
return {}
|
||
|
||
def isVideoFormat(self, url):
|
||
return url.endswith((".mp4", ".m3u8"))
|
||
|
||
def manualVideoCheck(self):
|
||
return False
|
||
|
||
def action(self, action):
|
||
return {}
|
||
|
||
def destroy(self):
|
||
pass
|
||
|
||
def getName(self):
|
||
return "Spider"
|
||
|
||
def getDependence(self):
|
||
return []
|
||
|
||
# -------------------------------
|
||
# 模块加载(实时加载,无缓存)
|
||
# -------------------------------
|
||
def loadSpider(self, name):
|
||
return self.loadModule(name).Spider()
|
||
|
||
def loadModule(self, name):
|
||
# ✅ 实时从当前目录加载,不再使用缓存目录
|
||
path = os.path.join(os.getcwd(), f"{name}.py")
|
||
if not os.path.exists(path):
|
||
raise FileNotFoundError(f"模块文件不存在: {path}")
|
||
# 每次强制重新加载模块,防止 Python 缓存
|
||
if name in sys.modules:
|
||
del sys.modules[name]
|
||
module = SourceFileLoader(name, path).load_module()
|
||
print(f"[加载成功] {module.__name__} -> {module.Spider}")
|
||
return module
|
||
|
||
# -------------------------------
|
||
# 工具方法
|
||
# -------------------------------
|
||
def regStr(self, reg, src, group=1):
|
||
m = re.search(reg, src)
|
||
return m.group(group) if m else ''
|
||
|
||
def removeHtmlTags(self, src):
|
||
clean = re.compile('<.*?>')
|
||
return re.sub(clean, '', src)
|
||
|
||
def cleanText(self, src):
|
||
clean = re.sub('[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\U0001F680-\U0001F6FF\U0001F1E0-\U0001F1FF]', '', src)
|
||
return clean
|
||
|
||
def fetch(self, url, params=None, cookies=None, headers=None, timeout=5, verify=True, stream=False, allow_redirects=True):
|
||
rsp = requests.get(url, params=params, cookies=cookies, headers=headers,
|
||
timeout=timeout, verify=verify, stream=stream, allow_redirects=allow_redirects)
|
||
rsp.encoding = 'utf-8'
|
||
return rsp
|
||
|
||
def post(self, url, params=None, data=None, json=None, cookies=None, headers=None,
|
||
timeout=5, verify=True, stream=False, allow_redirects=True):
|
||
rsp = requests.post(url, params=params, data=data, json=json, cookies=cookies, headers=headers,
|
||
timeout=timeout, verify=verify, stream=stream, allow_redirects=allow_redirects)
|
||
rsp.encoding = 'utf-8'
|
||
return rsp
|
||
|
||
def html(self, content):
|
||
return etree.HTML(content)
|
||
|
||
def str2json(self, s):
|
||
return json.loads(s)
|
||
|
||
def json2str(self, s):
|
||
return json.dumps(s, ensure_ascii=False)
|
||
|
||
def getProxyUrl(self, local=True):
|
||
return f'{Proxy.getUrl(local)}?do=py'
|
||
|
||
def log(self, msg):
|
||
if isinstance(msg, (dict, list)):
|
||
print(json.dumps(msg, ensure_ascii=False))
|
||
else:
|
||
print(f'{msg}')
|
||
|
||
# -------------------------------
|
||
# 缓存接口(仅保留接口,不执行任何操作)
|
||
# -------------------------------
|
||
def getCache(self, key):
|
||
return None
|
||
|
||
def setCache(self, key, value):
|
||
return 'succeed'
|
||
|
||
def delCache(self, key):
|
||
return 'succeed' |