Spaces:
Paused
Paused
Upload 24 files
Browse files- app/__pycache__/__init__.cpython-313.pyc +0 -0
- app/__pycache__/auth.cpython-313.pyc +0 -0
- app/__pycache__/clash_manager.cpython-313.pyc +0 -0
- app/__pycache__/debug_tools.cpython-313.pyc +0 -0
- app/__pycache__/main.cpython-313.pyc +0 -0
- app/__pycache__/sub_manager.cpython-313.pyc +0 -0
- app/sub_manager.py +41 -82
app/__pycache__/__init__.cpython-313.pyc
ADDED
|
Binary file (173 Bytes). View file
|
|
|
app/__pycache__/auth.cpython-313.pyc
ADDED
|
Binary file (1.55 kB). View file
|
|
|
app/__pycache__/clash_manager.cpython-313.pyc
ADDED
|
Binary file (19.9 kB). View file
|
|
|
app/__pycache__/debug_tools.cpython-313.pyc
ADDED
|
Binary file (8.19 kB). View file
|
|
|
app/__pycache__/main.cpython-313.pyc
ADDED
|
Binary file (27.2 kB). View file
|
|
|
app/__pycache__/sub_manager.cpython-313.pyc
ADDED
|
Binary file (24.8 kB). View file
|
|
|
app/sub_manager.py
CHANGED
|
@@ -128,50 +128,33 @@ class SubscriptionManager:
|
|
| 128 |
except Exception as e:
|
| 129 |
logger.error(f"创建数据目录失败: {str(e)}")
|
| 130 |
|
| 131 |
-
# 尝试直接读取订阅内容,确认它是否已经是Clash配置
|
| 132 |
-
try:
|
| 133 |
-
with open(input_file, "r", encoding="utf-8") as f:
|
| 134 |
-
content = f.read()
|
| 135 |
-
|
| 136 |
-
# 简单检查是否已经是Clash配置
|
| 137 |
-
if "proxies:" in content and ("port:" in content or "mixed-port:" in content):
|
| 138 |
-
logger.info("检测到输入文件已是Clash配置格式,直接使用")
|
| 139 |
-
with open(self.config_path, "w", encoding="utf-8") as f:
|
| 140 |
-
f.write(content)
|
| 141 |
-
return
|
| 142 |
-
except Exception as e:
|
| 143 |
-
logger.warning(f"读取输入文件时出错: {str(e)},将尝试转换")
|
| 144 |
-
|
| 145 |
# 准备subconverter命令
|
| 146 |
cmd = [
|
| 147 |
self.subconverter_path,
|
| 148 |
-
"-
|
| 149 |
-
"
|
| 150 |
-
"
|
| 151 |
-
|
| 152 |
-
"--include-remarks", ".*" # 包含所有节点
|
| 153 |
]
|
| 154 |
|
| 155 |
logger.info(f"执行命令: {' '.join(cmd)}")
|
| 156 |
|
| 157 |
-
#
|
| 158 |
if not os.path.exists(self.subconverter_path):
|
| 159 |
-
logger.
|
|
|
|
| 160 |
try:
|
| 161 |
with open(input_file, "r", encoding="utf-8") as f:
|
| 162 |
content = f.read()
|
|
|
|
|
|
|
| 163 |
with open(self.config_path, "w", encoding="utf-8") as f:
|
| 164 |
-
f.write(
|
| 165 |
-
logger.
|
| 166 |
-
# 验证文件是否成功写入
|
| 167 |
-
if os.path.exists(self.config_path):
|
| 168 |
-
logger.info(f"文件已成功写入,大小: {os.path.getsize(self.config_path)} 字节")
|
| 169 |
-
else:
|
| 170 |
-
logger.error(f"文件写入失败,{self.config_path} 不存在")
|
| 171 |
except Exception as e:
|
| 172 |
-
logger.error(f"
|
| 173 |
-
raise RuntimeError(f"
|
| 174 |
-
return
|
| 175 |
|
| 176 |
try:
|
| 177 |
# 执行subconverter
|
|
@@ -181,71 +164,46 @@ class SubscriptionManager:
|
|
| 181 |
stderr=subprocess.PIPE,
|
| 182 |
universal_newlines=True
|
| 183 |
)
|
| 184 |
-
stdout, stderr = process.communicate(timeout=
|
| 185 |
|
| 186 |
-
logger.info(f"subconverter
|
|
|
|
|
|
|
| 187 |
|
| 188 |
if process.returncode != 0:
|
| 189 |
-
logger.error(f"subconverter
|
| 190 |
-
#
|
| 191 |
try:
|
| 192 |
with open(input_file, "r", encoding="utf-8") as f:
|
| 193 |
content = f.read()
|
| 194 |
-
|
| 195 |
-
# 确保它是有效的配置,如果是普通订阅格式,添加基本的Clash头
|
| 196 |
if "proxies:" not in content:
|
|
|
|
| 197 |
content = self._add_clash_headers() + content
|
|
|
|
|
|
|
| 198 |
|
| 199 |
with open(self.config_path, "w", encoding="utf-8") as f:
|
| 200 |
f.write(content)
|
| 201 |
-
logger.warning("
|
| 202 |
-
# 验证文件是否成功写入
|
| 203 |
-
if os.path.exists(self.config_path):
|
| 204 |
-
logger.info(f"文件已成功写入,大小: {os.path.getsize(self.config_path)} 字节")
|
| 205 |
-
else:
|
| 206 |
-
logger.error(f"文件写入失败,{self.config_path} 不存在")
|
| 207 |
except Exception as e:
|
| 208 |
-
logger.error(f"
|
| 209 |
-
raise RuntimeError(f"
|
| 210 |
else:
|
| 211 |
-
logger.info("成功转换配置")
|
| 212 |
-
#
|
| 213 |
-
if os.path.exists(self.config_path):
|
| 214 |
logger.info(f"配置文件已生成,路径: {self.config_path},大小: {os.path.getsize(self.config_path)} 字节")
|
| 215 |
else:
|
| 216 |
-
#
|
| 217 |
-
logger.
|
| 218 |
-
|
| 219 |
-
possible_files = [f for f in os.listdir('.') if f.endswith('.yaml') or f.endswith('.yml')]
|
| 220 |
-
if possible_files:
|
| 221 |
-
logger.info(f"找到可能的配置文件: {possible_files}")
|
| 222 |
-
# 尝试复制找到的第一个文件
|
| 223 |
-
try:
|
| 224 |
-
import shutil
|
| 225 |
-
shutil.copy(possible_files[0], self.config_path)
|
| 226 |
-
logger.info(f"已复制 {possible_files[0]} 到 {self.config_path}")
|
| 227 |
-
except Exception as e:
|
| 228 |
-
logger.error(f"复制文件失败: {str(e)}")
|
| 229 |
-
else:
|
| 230 |
-
logger.error("未找到任何可能的配置文件")
|
| 231 |
-
# 尝试使用原始订阅内容作为配置
|
| 232 |
-
try:
|
| 233 |
-
with open(input_file, "r", encoding="utf-8") as f:
|
| 234 |
-
content = f.read()
|
| 235 |
-
|
| 236 |
-
# 确保它是有效的配置,如果是普通订阅格式,添加基本的Clash头
|
| 237 |
-
if "proxies:" not in content:
|
| 238 |
-
content = self._add_clash_headers() + content
|
| 239 |
-
|
| 240 |
-
with open(self.config_path, "w", encoding="utf-8") as f:
|
| 241 |
-
f.write(content)
|
| 242 |
-
logger.warning("使用订阅内容作为配置文件")
|
| 243 |
-
except Exception as e:
|
| 244 |
-
logger.error(f"使用订阅内容时出错: {str(e)}")
|
| 245 |
-
raise RuntimeError(f"写入配置文件失败: {str(e)}")
|
| 246 |
|
|
|
|
|
|
|
|
|
|
| 247 |
except (subprocess.SubprocessError, OSError) as e:
|
| 248 |
-
logger.error(f"执行subconverter
|
| 249 |
raise RuntimeError(f"配置转换失败: {str(e)}")
|
| 250 |
|
| 251 |
def _add_clash_headers(self):
|
|
@@ -332,13 +290,14 @@ secret: ""
|
|
| 332 |
if not proxies_list or not isinstance(proxies_list, list):
|
| 333 |
logger.error("配置文件缺少有效的 'proxies' 列表或列表为空!将仅使用 DIRECT 代理。请检查原始订阅内容。")
|
| 334 |
# 设置一个最小化的 proxies 和 proxy-groups
|
| 335 |
-
|
|
|
|
| 336 |
config_yaml["proxy-groups"] = [{
|
| 337 |
"name": "GLOBAL",
|
| 338 |
"type": "select",
|
| 339 |
-
"proxies": ["DIRECT"]
|
| 340 |
}]
|
| 341 |
-
proxy_names = {"DIRECT", "REJECT"}
|
| 342 |
groups_fixed = True # 标记需要重新生成配置内容
|
| 343 |
has_patch = True
|
| 344 |
else:
|
|
|
|
| 128 |
except Exception as e:
|
| 129 |
logger.error(f"创建数据目录失败: {str(e)}")
|
| 130 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
# 准备subconverter命令
|
| 132 |
cmd = [
|
| 133 |
self.subconverter_path,
|
| 134 |
+
"-i", input_file, # 输入文件
|
| 135 |
+
"-o", self.config_path, # 输出文件
|
| 136 |
+
"-t", "clash" # 目标格式
|
| 137 |
+
# 可根据需要添加其他 subconverter 参数,例如 --config ...
|
|
|
|
| 138 |
]
|
| 139 |
|
| 140 |
logger.info(f"执行命令: {' '.join(cmd)}")
|
| 141 |
|
| 142 |
+
# 检查 subconverter 是否存在
|
| 143 |
if not os.path.exists(self.subconverter_path):
|
| 144 |
+
logger.error(f"subconverter可执行文件未找到: {self.subconverter_path}. 无法转换配置。")
|
| 145 |
+
# 尝试直接使用原始订阅内容,并添加头部
|
| 146 |
try:
|
| 147 |
with open(input_file, "r", encoding="utf-8") as f:
|
| 148 |
content = f.read()
|
| 149 |
+
# 假定原始内容需要添加头部
|
| 150 |
+
final_content = self._add_clash_headers() + content
|
| 151 |
with open(self.config_path, "w", encoding="utf-8") as f:
|
| 152 |
+
f.write(final_content)
|
| 153 |
+
logger.warning("subconverter未找到,尝试使用原始订阅内容 + Clash头部信息写入配置文件")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
except Exception as e:
|
| 155 |
+
logger.error(f"写入原始订阅内容时出错: {str(e)}")
|
| 156 |
+
raise RuntimeError(f"无法转换配置,且无法写入原始订阅: {str(e)}")
|
| 157 |
+
return # 即使尝试写入,也应返回,后续 patch 可能仍有问题
|
| 158 |
|
| 159 |
try:
|
| 160 |
# 执行subconverter
|
|
|
|
| 164 |
stderr=subprocess.PIPE,
|
| 165 |
universal_newlines=True
|
| 166 |
)
|
| 167 |
+
stdout, stderr = process.communicate(timeout=60) # 增加超时时间
|
| 168 |
|
| 169 |
+
logger.info(f"subconverter STDOUT: {stdout[:500]}...") # 记录更多输出
|
| 170 |
+
if stderr:
|
| 171 |
+
logger.warning(f"subconverter STDERR: {stderr[:500]}...")
|
| 172 |
|
| 173 |
if process.returncode != 0:
|
| 174 |
+
logger.error(f"subconverter执行失败,返回码: {process.returncode}. STDERR: {stderr}")
|
| 175 |
+
# 错误处理:尝试直接使用订阅内容作为最后的手段
|
| 176 |
try:
|
| 177 |
with open(input_file, "r", encoding="utf-8") as f:
|
| 178 |
content = f.read()
|
| 179 |
+
# 检查是否需要添加 Clash 头部信息
|
|
|
|
| 180 |
if "proxies:" not in content:
|
| 181 |
+
logger.warning("subconverter失败,且原始内容不像Clash配置,添加基本头部")
|
| 182 |
content = self._add_clash_headers() + content
|
| 183 |
+
else:
|
| 184 |
+
logger.warning("subconverter失败,但原始内容看似Clash配置,直接使用")
|
| 185 |
|
| 186 |
with open(self.config_path, "w", encoding="utf-8") as f:
|
| 187 |
f.write(content)
|
| 188 |
+
logger.warning("subconverter转换失败,已尝试直接使用原始订阅内容写入配置文件")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
except Exception as e:
|
| 190 |
+
logger.error(f"subconverter失败后,尝试使用原始订阅内容时出错: {str(e)}")
|
| 191 |
+
raise RuntimeError(f"subconverter转换失败,且无法回退到原始订阅: {str(e)}")
|
| 192 |
else:
|
| 193 |
+
logger.info("subconverter成功转换配置")
|
| 194 |
+
# 验证输出文件是否存在且非空
|
| 195 |
+
if os.path.exists(self.config_path) and os.path.getsize(self.config_path) > 0:
|
| 196 |
logger.info(f"配置文件已生成,路径: {self.config_path},大小: {os.path.getsize(self.config_path)} 字节")
|
| 197 |
else:
|
| 198 |
+
# 如果文件不存在或为空,记录错误
|
| 199 |
+
logger.error(f"subconverter声称成功,但配置文件不存在或为空: {self.config_path}")
|
| 200 |
+
raise RuntimeError("subconverter转换成功,但未生成有效的配置文件")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
|
| 202 |
+
except subprocess.TimeoutExpired:
|
| 203 |
+
logger.error(f"执行subconverter超时 (超过60秒)")
|
| 204 |
+
raise RuntimeError("subconverter执行超时")
|
| 205 |
except (subprocess.SubprocessError, OSError) as e:
|
| 206 |
+
logger.error(f"执行subconverter时发生错误: {str(e)}")
|
| 207 |
raise RuntimeError(f"配置转换失败: {str(e)}")
|
| 208 |
|
| 209 |
def _add_clash_headers(self):
|
|
|
|
| 290 |
if not proxies_list or not isinstance(proxies_list, list):
|
| 291 |
logger.error("配置文件缺少有效的 'proxies' 列表或列表为空!将仅使用 DIRECT 代理。请检查原始订阅内容。")
|
| 292 |
# 设置一个最小化的 proxies 和 proxy-groups
|
| 293 |
+
# 不要在 proxies 中显式定义 DIRECT,Clash 内置了它
|
| 294 |
+
config_yaml["proxies"] = []
|
| 295 |
config_yaml["proxy-groups"] = [{
|
| 296 |
"name": "GLOBAL",
|
| 297 |
"type": "select",
|
| 298 |
+
"proxies": ["DIRECT"] # 直接引用内置的 DIRECT
|
| 299 |
}]
|
| 300 |
+
proxy_names = {"DIRECT", "REJECT"} # 仍然需要知道内置名称
|
| 301 |
groups_fixed = True # 标记需要重新生成配置内容
|
| 302 |
has_patch = True
|
| 303 |
else:
|