返回列表 发布新帖

[同步与备份] 同步下载云盘高码率新剧,避免在线播放卡顿

138 2
发表于 昨天 10:46 | 查看全部 阅读模式 IP:–河南 /数据上网公共出口

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

最近使用tg2drive自动追剧到云盘,但是对于码率比较高的电视剧在观看时会很卡,几乎一秒一卡,于是有了本脚本的出现。


通过监控tg2drive生成的strm文件夹,通过关键词匹配下载指定电视剧,实现观看时不再卡顿,自动跳过已下载文件,由于监控的是生成到本地的strm文件,因此全程无云盘风控风险,扫描间隔在青龙面板配置想多短就多短。

对于其他strm方案只要strm内容是http直链均可正常使用,如果需要的人多也可以改一版webdav挂载方案。

至于为什么使用青龙面板而不是发一个docker,一来功能简单,二来实在是内存不够了


image.png
  1. #!/usr/bin/env python3
  2. """
  3. 青龙面板定时脚本:扫描 strm 文件夹,下载关键词匹配的文件,保持目录结构
  4. """

  5. import os
  6. import re
  7. import time
  8. import logging
  9. import shutil
  10. from urllib.parse import unquote, urlparse
  11. from pathlib import Path

  12. import requests

  13. # ---------- 配置(根据实际情况修改)----------
  14. STRM_DIR = "/volume1/docker/tg2drive/strm/123云盘/library/剧集"
  15. DOWNLOAD_DIR = "/volume5/workspace/云盘下载"
  16. KEYWORDS = ["小芳"]          # 文件名包含任意一个关键词即下载
  17. RECURSIVE = True             # 是否递归扫描子目录
  18. DOWNLOAD_TIMEOUT = 300       # 下载超时(秒)
  19. RETRY_TIMES = 3              # 重试次数
  20. # --------------------------------------------

  21. logging.basicConfig(
  22.     level=logging.INFO,
  23.     format='%(asctime)s - %(levelname)s - %(message)s'
  24. )
  25. logger = logging.getLogger(__name__)

  26. def ensure_dir(path):
  27.     """确保目录存在"""
  28.     os.makedirs(path, exist_ok=True)

  29. def extract_filename_from_url(url):
  30.     """从 URL 中提取文件名"""
  31.     parsed = urlparse(url)
  32.     path = unquote(parsed.path)
  33.     filename = os.path.basename(path)
  34.     if not filename:
  35.         # 尝试从查询参数中提取(某些链接带 filename 参数)
  36.         query = parsed.query
  37.         match = re.search(r'filename=([^&]+)', query)
  38.         if match:
  39.             filename = unquote(match.group(1))
  40.     return filename

  41. def should_download(filename):
  42.     """根据关键词判断是否应该下载"""
  43.     if not filename:
  44.         return False
  45.     for kw in KEYWORDS:
  46.         if kw in filename:
  47.             return True
  48.     return False

  49. def download_file(url, dest_path):
  50.     """下载文件到指定路径,带重试(每10%打印一次进度)"""
  51.     for attempt in range(1, RETRY_TIMES + 1):
  52.         try:
  53.             logger.info(f"开始下载 [{attempt}/{RETRY_TIMES}]: {dest_path.name}")
  54.             with requests.get(url, stream=True, timeout=DOWNLOAD_TIMEOUT) as r:
  55.                 r.raise_for_status()
  56.                 total_size = int(r.headers.get('content-length', 0))
  57.                 temp_path = str(dest_path) + ".tmp"
  58.                 with open(temp_path, 'wb') as f:
  59.                     downloaded = 0
  60.                     last_percent = -1
  61.                     for chunk in r.iter_content(chunk_size=8192):
  62.                         if chunk:
  63.                             f.write(chunk)
  64.                             downloaded += len(chunk)
  65.                             if total_size:
  66.                                 percent = int((downloaded / total_size) * 100)
  67.                                 if percent >= last_percent + 10:
  68.                                     logger.info(f"下载进度: {dest_path.name} {percent}%")
  69.                                     last_percent = percent
  70.                 shutil.move(temp_path, str(dest_path))
  71.                 logger.info(f"下载完成: {dest_path.name} (大小: {total_size} bytes)")
  72.                 return True
  73.         except Exception as e:
  74.             logger.error(f"下载失败 (尝试 {attempt}): {e}")
  75.             temp_path = str(dest_path) + ".tmp"
  76.             if os.path.exists(temp_path):
  77.                 os.remove(temp_path)
  78.             if attempt == RETRY_TIMES:
  79.                 logger.error(f"下载最终失败: {dest_path.name}")
  80.                 return False
  81.             time.sleep(2 ** attempt)
  82.     return False
  83.    
  84. def process_strm_file(strm_path):
  85.     """
  86.     处理单个 strm 文件
  87.     返回:
  88.         1  = 下载成功
  89.         0  = 文件已存在,跳过
  90.         -1 = 下载失败
  91.         -2 = 关键词不匹配,跳过
  92.     """
  93.     # 读取 URL
  94.     try:
  95.         with open(strm_path, 'r', encoding='utf-8') as f:
  96.             url = f.readline().strip()
  97.     except Exception as e:
  98.         logger.error(f"读取 strm 文件失败 {strm_path}: {e}")
  99.         return -1

  100.     if not url:
  101.         logger.warning(f"strm 文件内容为空: {strm_path}")
  102.         return -1

  103.     # 提取文件名
  104.     filename = extract_filename_from_url(url)
  105.     if not filename:
  106.         filename = Path(strm_path).stem
  107.         logger.warning(f"无法从 URL 提取文件名,使用 strm 文件名: {filename}")

  108.     # 关键词过滤
  109.     if not should_download(filename):
  110.         return -2  # 关键词不匹配

  111.     # 计算目标路径
  112.     rel_path = os.path.relpath(strm_path, STRM_DIR)
  113.     rel_dir = os.path.dirname(rel_path)
  114.     target_dir = Path(DOWNLOAD_DIR) / rel_dir
  115.     dest_path = target_dir / filename

  116.     # 检查是否已存在
  117.     if dest_path.exists():
  118.         logger.debug(f"文件已存在,跳过: {dest_path}")  # debug 级别,不显示
  119.         return 0

  120.     # 确保目录存在
  121.     ensure_dir(target_dir)

  122.     # 下载
  123.     success = download_file(url, dest_path)
  124.     if success:
  125.         logger.info(f"成功下载: {filename} 到 {dest_path}")
  126.         return 1
  127.     else:
  128.         logger.error(f"下载失败: {filename}")
  129.         return -1

  130. def main():
  131.     logger.info("===== 开始扫描 strm 文件 =====")
  132.     ensure_dir(DOWNLOAD_DIR)

  133.     strm_files = []
  134.     if RECURSIVE:
  135.         for root, _, files in os.walk(STRM_DIR):
  136.             for f in files:
  137.                 if f.lower().endswith('.strm'):
  138.                     strm_files.append(os.path.join(root, f))
  139.     else:
  140.         for f in os.listdir(STRM_DIR):
  141.             if f.lower().endswith('.strm'):
  142.                 strm_files.append(os.path.join(STRM_DIR, f))

  143.     total = len(strm_files)
  144.     logger.info(f"共发现 {total} 个 strm 文件")

  145.     # 统计
  146.     skipped_exist = 0
  147.     skipped_keyword = 0
  148.     downloaded = 0
  149.     failed = 0

  150.     for strm_path in strm_files:
  151.         status = process_strm_file(strm_path)
  152.         if status == 1:
  153.             downloaded += 1
  154.         elif status == 0:
  155.             skipped_exist += 1
  156.         elif status == -2:
  157.             skipped_keyword += 1
  158.         else:  # -1
  159.             failed += 1

  160.     # 最终统计信息
  161.     logger.info("===== 扫描完成 =====")
  162.     logger.info(f"总计扫描 strm 文件: {total}")
  163.     logger.info(f"已存在跳过: {skipped_exist}")
  164.     logger.info(f"关键词不匹配跳过: {skipped_keyword}")
  165.     logger.info(f"下载成功: {downloaded}")
  166.     logger.info(f"下载失败: {failed}")

  167. if __name__ == "__main__":
  168.     main()
复制代码


评论2

蓝小白Lv.4 发表于 昨天 13:08 | 查看全部 IP:四川省 业务平台
你又出山了
不爱思考楼主Lv.1绿联NAS社区会员用户 发表于 昨天 13:58 | 查看全部 IP:–河南 /数据上网公共出口

评论

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Copyright © 2026 绿联NAS私有云社区 版权所有 All Rights Reserved. 粤公网安备44030002002555号| 粤ICP备12028978号
关灯 在本版发帖
联系技术支持
返回顶部
快速回复 返回顶部 返回列表