You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用pytube检查已下载文件,仅下载播放列表中的缺失文件?

修改后的pytube播放列表下载函数(支持覆盖/跳过缺失文件)

核心改动说明

  • 移除文件夹存在时的直接报错逻辑,改为询问用户选择操作模式:1=覆盖所有文件,2=仅下载本地缺失的文件
  • 预加载视频对象并获取标题,用于精准匹配本地已生成的MP3文件
  • 修复原函数中的变量拼写错误(playlsit_name → playlist_name)
  • 优化下载计数逻辑,避免重复遍历文件夹计数
  • 新增本地文件检查逻辑,仅在需要时执行下载、转码和元数据写入操作
  • 增加异常捕获,单个视频处理失败不会中断整个播放列表的下载

完整修改代码

import os
from pathlib import Path
from pytube import Playlist, YouTube
from moviepy.editor import AudioFileClip
import eyed3
import re

# 假设以下变量为外部定义(根据实际场景调整)
# get_link = "你的YouTube播放列表URL"
# user_path = "本地存储根路径"
# var1 = 1  # 控制是否写入音频元数据(1=开启,0=关闭)

def download_playlist():
    # 获取播放列表对象
    playlist = Playlist(get_link)
    playlist_name = playlist.title  # 修复原拼写错误:playlsit_name → playlist_name
    main_dir = os.path.join(user_path, playlist_name)  # 跨平台路径拼接
    
    # 处理文件夹已存在的情况
    if os.path.exists(main_dir):
        print(f"播放列表文件夹「{playlist_name}」已存在,请选择操作:")
        print("1. 覆盖所有已下载文件")
        print("2. 仅下载本地缺失的文件")
        # 循环获取有效输入
        while True:
            choice = input("请输入选择(1/2):")
            if choice in ["1", "2"]:
                break
            print("输入无效,请重新输入1或2")
        download_mode = choice
    else:
        os.mkdir(main_dir, mode=0o666)
        download_mode = "1"  # 新文件夹默认下载所有视频
    
    # 预加载视频对象,减少重复请求
    videos = playlist.videos
    videos_num = len(videos)
    completed_count = 0  # 已完成处理的视频计数
    
    for video in videos:
        # 处理视频标题中的非法文件名字符
        safe_title = re.sub(r'[\\/*?:"<>|]', "", video.title)
        target_mp3_path = os.path.join(main_dir, f"{safe_title}.mp3")
        
        # 跳过模式:检测到已存在则跳过
        if download_mode == "2" and os.path.exists(target_mp3_path):
            print(f"已存在:{safe_title}.mp3,跳过下载")
            completed_count += 1
            print(f"进度:{completed_count}/{videos_num}")
            continue
        
        # 执行下载、转码、元数据写入流程
        try:
            print(f"正在处理:{video.title}")
            # 下载音频流
            temp_mp4_path = video.streams.filter(only_audio=True).first().download(main_dir)
            # 转码为MP3
            audio_clip = AudioFileClip(temp_mp4_path)
            audio_clip.write_audiofile(target_mp3_path)
            # 删除临时MP4文件
            os.remove(temp_mp4_path)
            
            # 写入音频元数据(如果开启)
            if var1 == 1:
                audio_file = eyed3.load(target_mp3_path)
                if not audio_file.tag:
                    audio_file.initTag()
                # 处理频道名称(去除-Topic后缀)
                channel_name = video.author
                if " - Topic" in channel_name:
                    channel_name = channel_name.replace(" - Topic", "")
                audio_file.tag.artist = channel_name
                audio_file.tag.title = video.title
                audio_file.tag.save()
            
            completed_count += 1
            print(f"进度:{completed_count}/{videos_num}")
        except Exception as e:
            print(f"处理视频「{video.title}」时出错:{str(e)}")
            continue
    
    print("下载完成!!!")

关键细节说明

  • 使用playlist.videos预加载所有视频对象,减少重复向YouTube发起HTTP请求,提升整体效率
  • 对视频标题进行非法字符过滤,避免生成操作系统无法识别的文件名
  • 采用os.path.join替代硬编码的路径拼接,确保代码在Windows、Linux、macOS等平台都能正常运行
  • 增加异常捕获逻辑,单个视频处理失败不会导致整个播放列表下载中断

内容的提问来源于stack exchange,提问作者Shoter3000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 01:51:09