Spaces:
Running
Running
Upload 4 files
Browse files
app.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
import os
|
|
|
|
| 2 |
|
| 3 |
from fastapi import FastAPI, Request
|
| 4 |
from fastapi.responses import Response, StreamingResponse
|
|
@@ -30,6 +31,7 @@ async def proxy(path: str, request: Request):
|
|
| 30 |
# - Bot API 的 /bot... 响应是小 JSON(sendDocument/getFile/getMe),直接“读全量再返回”,避免流式上下文提前关闭导致空响应。
|
| 31 |
# - Bot API 的 /file/... 响应是大文件,才需要流式透传。
|
| 32 |
is_file_download = path.startswith("file/") or path.startswith("/file/")
|
|
|
|
| 33 |
|
| 34 |
passthrough_allow = {
|
| 35 |
"content-type",
|
|
@@ -55,6 +57,58 @@ async def proxy(path: str, request: Request):
|
|
| 55 |
content=iter_request_body(),
|
| 56 |
)
|
| 57 |
resp_headers = {k: v for k, v in r.headers.items() if k.lower() in passthrough_allow}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
return Response(content=r.content, status_code=r.status_code, headers=resp_headers)
|
| 59 |
finally:
|
| 60 |
await client.aclose()
|
|
|
|
| 1 |
import os
|
| 2 |
+
import json
|
| 3 |
|
| 4 |
from fastapi import FastAPI, Request
|
| 5 |
from fastapi.responses import Response, StreamingResponse
|
|
|
|
| 31 |
# - Bot API 的 /bot... 响应是小 JSON(sendDocument/getFile/getMe),直接“读全量再返回”,避免流式上下文提前关闭导致空响应。
|
| 32 |
# - Bot API 的 /file/... 响应是大文件,才需要流式透传。
|
| 33 |
is_file_download = path.startswith("file/") or path.startswith("/file/")
|
| 34 |
+
is_get_file = "/getFile" in ("/" + path)
|
| 35 |
|
| 36 |
passthrough_allow = {
|
| 37 |
"content-type",
|
|
|
|
| 57 |
content=iter_request_body(),
|
| 58 |
)
|
| 59 |
resp_headers = {k: v for k, v in r.headers.items() if k.lower() in passthrough_allow}
|
| 60 |
+
|
| 61 |
+
# 关键兼容:某些 Local Bot API Server 会在 getFile 的 result.file_path 里返回本机工作目录路径
|
| 62 |
+
# 例如:var/lib/telegram-bot-api/<token>/documents/xxx
|
| 63 |
+
# 但 CloudPaste 会把这个 file_path 拼到 /file/bot<TOKEN>/<file_path> 上,导致 404。
|
| 64 |
+
# 这里把 file_path 规范化回 documents/xxx 这种“相对路径”,让后续下载正常。
|
| 65 |
+
content_type = (r.headers.get("content-type") or "").lower()
|
| 66 |
+
if is_get_file and r.status_code == 200 and "application/json" in content_type:
|
| 67 |
+
try:
|
| 68 |
+
payload = r.json()
|
| 69 |
+
if isinstance(payload, dict) and payload.get("ok") is True and isinstance(payload.get("result"), dict):
|
| 70 |
+
result = payload.get("result") or {}
|
| 71 |
+
fp = result.get("file_path")
|
| 72 |
+
if isinstance(fp, str) and fp:
|
| 73 |
+
# 从 path 里提取 token(URL path 中是 url-encoded 的形式,正好能匹配 file_path 里的 token 段)
|
| 74 |
+
token_enc = None
|
| 75 |
+
p = path.lstrip("/")
|
| 76 |
+
if p.startswith("bot"):
|
| 77 |
+
token_enc = p[3:].split("/", 1)[0] or None
|
| 78 |
+
|
| 79 |
+
raw_fp = fp.lstrip("/")
|
| 80 |
+
# 优先用 “/<token>/” 作为分隔点,截掉前面的工作目录
|
| 81 |
+
if token_enc:
|
| 82 |
+
marker = f"/{token_enc}/"
|
| 83 |
+
idx = raw_fp.find(marker)
|
| 84 |
+
if idx >= 0:
|
| 85 |
+
raw_fp = raw_fp[idx + len(marker) :]
|
| 86 |
+
elif raw_fp.startswith(f"{token_enc}/"):
|
| 87 |
+
raw_fp = raw_fp[len(token_enc) + 1 :]
|
| 88 |
+
|
| 89 |
+
# 最终只保留常见的相对目录开头(documents/photos/videos/voice/audio/animations/stickers 等)
|
| 90 |
+
for prefix in (
|
| 91 |
+
"documents/",
|
| 92 |
+
"photos/",
|
| 93 |
+
"videos/",
|
| 94 |
+
"video_notes/",
|
| 95 |
+
"voice/",
|
| 96 |
+
"audio/",
|
| 97 |
+
"animations/",
|
| 98 |
+
"stickers/",
|
| 99 |
+
"profile_photos/",
|
| 100 |
+
"thumbnails/",
|
| 101 |
+
):
|
| 102 |
+
if raw_fp.startswith(prefix):
|
| 103 |
+
result["file_path"] = raw_fp
|
| 104 |
+
payload["result"] = result
|
| 105 |
+
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
|
| 106 |
+
# 确保 JSON 的 content-type 不被冲掉
|
| 107 |
+
resp_headers.setdefault("content-type", "application/json")
|
| 108 |
+
return Response(content=body, status_code=r.status_code, headers=resp_headers)
|
| 109 |
+
except Exception:
|
| 110 |
+
pass
|
| 111 |
+
|
| 112 |
return Response(content=r.content, status_code=r.status_code, headers=resp_headers)
|
| 113 |
finally:
|
| 114 |
await client.aclose()
|
start.sh
CHANGED
|
@@ -13,7 +13,7 @@ WORK_DIR="${TELEGRAM_WORK_DIR:-/tmp/telegram-bot-api-data}"
|
|
| 13 |
TEMP_DIR="${TELEGRAM_TEMP_DIR:-/tmp/telegram-bot-api-tmp}"
|
| 14 |
mkdir -p "$WORK_DIR" "$TEMP_DIR"
|
| 15 |
|
| 16 |
-
VERBOSITY="${TELEGRAM_VERBOSITY:-
|
| 17 |
|
| 18 |
telegram-bot-api \
|
| 19 |
--api-id="${TELEGRAM_API_ID}" \
|
|
|
|
| 13 |
TEMP_DIR="${TELEGRAM_TEMP_DIR:-/tmp/telegram-bot-api-tmp}"
|
| 14 |
mkdir -p "$WORK_DIR" "$TEMP_DIR"
|
| 15 |
|
| 16 |
+
VERBOSITY="${TELEGRAM_VERBOSITY:-1}"
|
| 17 |
|
| 18 |
telegram-bot-api \
|
| 19 |
--api-id="${TELEGRAM_API_ID}" \
|