Skip to content

Instantly share code, notes, and snippets.

@we-taper
Last active January 12, 2024 16:20
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save we-taper/96792114f267fc8fcf21807b0e216ffd to your computer and use it in GitHub Desktop.
Save we-taper/96792114f267fc8fcf21807b0e216ffd to your computer and use it in GitHub Desktop.
Extract chapters part of the Youtube-dl's json info into a CUE file
#! python3
"""
Extract chapters part of the Youtube-dl's json info into a CUE file.
This file is in the public domain.
Requirements:
pydantic
python>=3.6
Steps:
1. Download JSON information (`--skip-download` skips downloading the video/audio):
`youtube-dl --skip-download --write-info-json YouTubeURL`
2. Generate CUE file: `ydljson2cue.py json_filename [optional video/audio extension]`
"""
from pathlib import Path
from pydantic import BaseModel
from typing import List, Union
import os
class Chapter(BaseModel):
start_time: int
end_time: int
title: str
def to_cue_data(chapter: Chapter, idx: int) -> List[str]:
return [
f" TRACK {idx:02d} AUDIO",
f' TITLE "{chapter.title}"',
f" INDEX 01 {chapter.start_time // 60}:{chapter.start_time % 60}:00",
]
class YoutubeDlInfoJson(BaseModel):
chapters: List[Chapter]
title: str
class Config:
ignore_extra = True
def convert(ydl_info: YoutubeDlInfoJson, output_file):
cue_data = [
f'TITLE "{ydl_info.title}"',
f'FILE "{output_file}" WAVE',
]
for idx, chapter in enumerate(ydl_info.chapters):
cue_data.extend(to_cue_data(chapter, idx + 1))
return cue_data
def read_and_write(input: Union[str, Path], ext="mp3"):
input = Path(input)
basename = os.path.splitext(input)[0]
output = input.parent / f"{basename}.cue"
ydl_info = YoutubeDlInfoJson.parse_file(input)
cue_data = convert(ydl_info, input.parent / f"{basename}.{ext}")
output.write_text(os.linesep.join(cue_data))
if __name__ == "__main__":
import sys
argv_len = len(sys.argv)
if argv_len == 2:
file = sys.argv[1]
ext = "mp3"
elif argv_len == 3:
file, ext = sys.argv[1:]
else:
print("Usage: script_name json_filename [extension]", file=sys.stderr)
sys.exit(1)
read_and_write(file, ext)
@6b6561
Copy link

6b6561 commented Jan 11, 2024

I tried your script which runs properly but giving a warning with pydantic-2.5.3 which was installed by pip.
$ python3 ydljson2cue.py test.json ydljson2cue.py:59: PydanticDeprecatedSince20: The parse_filemethod is deprecated; load the data from file, then if your data is JSON usemodel_validate_json, otherwise model_validateinstead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ ydl_info = YoutubeDlInfoJson.parse_file(input)

@we-taper
Copy link
Author

@6b6561 Thanks. In response to Pydantic's change, maybe replace that piece of code by first load the file into dict with python's json library, and then convert it to YoutubeDlInfoJson with YoutubeDlInfoJson.model_validate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment