电话
400 9058 355
本文详解 pyrogram 机器人下载并发送 youtube 视频时“卡在最后一步”的常见原因,包括异步阻塞、文件路径错误、权限问题及缺乏异常追踪,并提供可立即验证的调试方案与健壮实现。
你的代码逻辑看似完整:下载视频 → 等待文件生成 → 调用 send_video 发送。但实际中 await client.send_video(...) 未执行或静默失败,根本原因往往不是配置错误,而是未捕获底层异常 + 同步/异步混用导致阻塞 + 文件路径与权限隐患。下面逐层分析并给出生产级修复方案。
原代码中 except Exception as e: 仅打印字符串,而 Pyrogram 的网络异常(如 FilePartMissing, Timeout, PeerIdInvalid, ChatWriteForbidden)常被吞掉。务必引入 traceback 获取完整堆栈:
import traceback
# 替换原 send_video 的 except 块:
except Exception as e:
print(f"❌ Failed to send video:")
traceback.print_exc() # ← 关键!输出完整错误链
return运行后你极可能看到类似:
这些信息是调试的唯一入口。
ys.download(...) 是同步阻塞调用,

import asyncio
from concurrent.futures import ThreadPoolExecutor
# 创建线程池(全局复用)
executor = ThreadPoolExecutor(max_workers=4)
@app.on_message()
async def send_video(client, message):
if not message.text or not message.text.startswith("https://"):
await message.reply("⚠️ 请发送有效的 YouTube 链接")
return
URL = message.text.strip()
yt = YouTube(URL)
# ✅ 异步安全下载:委托给线程池
try:
ys = yt.streams.get_highest_resolution()
video_path = "video.mp4"
# 在线程中执行下载(避免阻塞事件循环)
await asyncio.get_event_loop().run_in_executor(
executor,
lambda: ys.download(filename=video_path)
)
print("✅ Video downloaded successfully")
except Exception as e:
print(f"❌ Download failed: {e}")
await message.reply("下载失败,请检查链接或重试")
return
# ✅ 不再轮询等待:直接校验文件存在性
if not os.path.exists(video_path) or os.path.getsize(video_path) == 0:
await message.reply("⚠️ 下载完成但文件为空,请重试")
return
# ✅ 使用绝对路径避免路径歧义(尤其 Docker/服务器环境)
abs_path = os.path.abspath(video_path)
try:
# 发送前可选:添加进度回调(提升用户体验)
def progress(current, total):
percent = (current / total) * 100
if int(percent) % 20 == 0: # 每20%上报一次
asyncio.create_task(message.reply(f"? 上传中... {int(percent)}%"))
await client.send_video(
chat_id=message.chat.id,
video=abs_path,
duration=yt.length,
caption=f"? {yt.title[:50]}...",
progress=progress
)
print("✅ Video sent successfully")
await message.reply("✅ 视频已发送!")
except Exception as e:
print(f"❌ Send failed:")
traceback.print_exc()
await message.reply("发送失败,请稍后重试或联系管理员")
finally:
# ✅ 清理临时文件(防止磁盘占满)
if os.path.exists(abs_path):
os.remove(abs_path)# 在下载后加入
size_mb = os.path.getsize(abs_path) / (1024 * 1024)
if size_mb > 45: # 预留缓冲
await message.reply(f"⚠️ 视频过大 ({size_mb:.1f} MB),Telegram 限制为 50 MB")
returnexcept FloodWait as e:
print(f"⏳ Flood wait for {e.value} seconds")
await asyncio.sleep(e.value + 1)
# 重试逻辑(需封装为递归或循环)? 总结:Pyrogram 机器人“不发送”几乎从不是配置问题,而是同步阻塞、异常静默、路径/权限疏漏三者叠加的结果。用 ThreadPoolExecutor 解耦下载、用 traceback 揭示真相、用绝对路径和大小校验筑牢防线——这才是稳定交付的关键。
邮箱:8955556@qq.com
Q Q:8955556
本文详解如何将Go官方present工具(用于生成HTML5...
PySNMP在不同版本中对SNMP错误状态(errorSta...
time.Sleep仅阻塞当前goroutine,其他gor...
PHPfopen()创建含特殊符号的文件名失败主因是操作系统...
WooCommerce中通过代码为分组产品动态聚合子商品的属...
io.ReadFull返回io.ErrUnexpectedE...
本文详解Yii2中控制器向视图传递ActiveRecord数...
本文详解为何通过wp_set_object_terms()为...
Pytest中使用@mock.patch类装饰器会导致补丁泄...
带缓冲的channel是并发安全的FIFO队列;make(c...