YouTube 的新功能
Youtube 最近启用了以下选项:添加章节在 YouTube 视频中。
只需在视频描述中添加章节时间戳(开始时间)即可完成。
相关话题
使用 youtube-dl/yt-dlp 我们可以
下载 YouTube 视频的一部分通过提供
start time
和duration
。
提取 YouTube 视频的描述作为
.description
文件。
问题
是否有一个命令可以将 YouTube 视频的各章节下载为单独的视频文件没有提供start time
并且duration
它会自动从中提取时间戳.description
?
答案1
答案2
您不能直接执行此操作。我编写了一个 Python 脚本,它将下载整个文件,处理描述文件,然后将下载的文件拆分为其组成章节。
用法 - 如果你将其保存到名为“yt_chapters.py”的文件中,然后运行
yt_chapters.py --split "https://www.youtube.com/watch?v=m5lp8S-YgrQ"
您可以传递多个下载链接,它将循环遍历列表。
章节记录将会添加到原始下载的MP4中。
要求:youtubedl、ffmpeg 和 MP4Box (GPAC)。如果您不想保留原始 MP4,或者您不介意它有章节,您可以注释掉该部分。youtubedl 和 ffmpeg 应该在您的系统路径中,否则请更改以下代码以包含可执行文件的完整路径。
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import subprocess, os, argparse, datetime, re, sys
def get_source_name(download_source:str)->str:
# Get the expected filename in order to process everything down the line
result = subprocess.run(["youtube-dl", "--get-filename",
"-o", "%(title)s", download_source],
capture_output=True, encoding='UTF8')
return result.stdout.rstrip('\n')
def get_best_mp4_single_file(download_source:str, description_file:str,
fix_required:bool=False)->list:
# Download the file as mp4 (in order to use MP4)
subprocess.run(["youtube-dl", "--write-description", "-f",
"bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4",
"-o", "%(title)s.%(ext)s", link_to_download])
if fix_required:
input("Fix the description file to have the chapters "
"on their own lines in the format timecode name "
"and then press Enter to continue...")
return read_description_file(description_file=description_file)
def get_worst_mp4_single_file(download_source:str, description_file:str,
fix_required:bool=False)->list:
# Download the file as mp4 (in order to use MP4)
subprocess.run(["youtube-dl", "--write-description", "-f",
"worstvideo[ext=mp4]+worstaudio[ext=m4a]/mp4",
"-o", "%(title)s.%(ext)s", link_to_download])
if fix_required:
input("Fix the description file to have the chapters "
"on their own lines in the format timecode name "
"and then press Enter to continue...")
return read_description_file(description_file=description_file)
def add_chapters_to_mp4(chapter_file_name:str, name_for_download:str)->None:
# Use MP4Box to mux the chapter file with the mp4
subprocess.run(["MP4Box", "-chap", chapter_file_name, name_for_download])
def read_description_file(description_file:str)->list:
# Read the description file
# Split into time and chapter name
list_of_chapters = []
with open(description_file, 'r') as f:
# only increment chapter number on a chapter line
# chapter lines start with timecode
line_counter = 1
for line in f:
result = re.search(r"\(?(\d?[:]?\d+[:]\d+)\)?", line)
try:
# result = re.search("\(?(\d+[:]\d+[:]\d+)\)?", line)
time_count = datetime.datetime.strptime(result.group(1), '%H:%M:%S')
except:
try:
# result = re.search("\(?(\d+[:]\d+)\)?", line)
time_count = datetime.datetime.strptime(result.group(1), '%M:%S')
except:
continue
chap_name = line.replace(result.group(0),"").rstrip(' :\n')
chap_pos = datetime.datetime.strftime(time_count, '%H:%M:%S')
list_of_chapters.append((str(line_counter).zfill(2), chap_pos, chap_name))
line_counter += 1
return list_of_chapters
def write_chapters_file(chapter_file:str, chapter_list:tuple)->None:
#open(chapter_file, 'w').close()
# Write out the chapter file based on simple MP4 format (OGM)
with open(chapter_file, 'w') as fo:
for current_chapter in chapter_list:
fo.write(f'CHAPTER{current_chapter[0]}='
f'{current_chapter[1]}\n'
f'CHAPTER{current_chapter[0]}NAME='
f'{current_chapter[2]}\n')
def split_mp4(chapters:list, download_filename:str, download_name:str)->None:
# current_duration = subprocess.run(['ffprobe', '-i', download_filename,
# '-show_entries', 'format=duration',
# '-v', 'quiet', '-of', 'csv="p=0"'],
# capture_output=True, encoding='UTF8')
current_duration_pretext = subprocess.run(['ffprobe', '-i', download_filename,
'-show_entries', 'format=duration',
'-v', 'quiet'],
capture_output=True, encoding='UTF8')
current_duration = float(current_duration_pretext.stdout[18:-13])
m, s = divmod(current_duration, 60)
h, m = divmod(m, 60)
current_dur = ':'.join([str(int(h)),str(int(m)),str(s)])
for current_index, current_chapter in enumerate(chapters):
# current_chapter will be a tuple: position, timecode, name
next_index = current_index + 1
start_time = current_chapter[1]
try:
end_time = chapters[next_index][1]
except:
end_time = current_dur
output_name = f'{download_name} - ({current_chapter[2]}).mp4'
subprocess.run(["ffmpeg", "-ss", start_time, "-to", end_time,
"-i", download_filename, "-acodec", "copy",
"-vcodec", "copy", output_name])
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Download Youtube videos with chapters')
parser.add_argument('links', metavar='N', type=str, nargs='+',
help='List of links to download')
parser.add_argument("--split", help="Split chapters into individual files",
action="store_true")
parser.add_argument("--test", help="Download worst version to speed up testing",
action="store_true")
parser.add_argument("--fix", help="Pause to allow manual correction of the description file",
action="store_true")
args = parser.parse_args()
# print(args.links)
for link_to_download in args.links:
download_name = get_source_name(download_source=link_to_download)
download_filename = f'{download_name}.mp4'
description_file = f'{download_name}.description'
chapter_file = f'{download_name}_chapter.txt'
if not args.test:
chapters = get_best_mp4_single_file(download_source=link_to_download,
description_file=description_file,
fix_required=args.fix)
else:
chapters = get_worst_mp4_single_file(download_source=link_to_download,
description_file=description_file,
fix_required=args.fix)
if not chapter_file:
print("No chapters found")
sys.exit(1)
write_chapters_file(chapter_file=chapter_file, chapter_list=chapters)
if args.split:
split_mp4(chapters=chapters, download_filename=download_filename,
download_name=download_name)
add_chapters_to_mp4(chapter_file_name=chapter_file,
name_for_download=download_filename)
# Clean up the text files
os.remove(description_file)
os.remove(chapter_file)
答案3
在终端上使用此 yt-dlp 命令
安装后,按照文档中的说明yt-dlp
使用$ python3 -m pip install -U yt-dlp
这里。
cd 到您选择的目录并运行以下命令。
yt-dlp -f 'best[height=720]' [URL...] -o '%(title)s/%(title)s.%(ext)s' --split-chapters -o "chapter:%(title)s/[%(section_number)s] - %(section_title)s.%(ext)s"
记得更新[URL...]
视频网址(删除方括号)。您可能ffmpeg
还需要安装。谢谢