Function to generate `.info.json` from `ffmpeg` details.
September 25, 2023 ยท View on GitHub
import os import ffmpeg import datetime import time import json
def create_info_json(video, file_dest, reason="private"):
print("Attempting to generate .info.json details from video metadata.")
info_ext = "info.json"
info_file = f"{os.path.splitext(os.path.basename(video))[0]}.{info_ext}"
try:
vid_ff = ffmpeg.probe(f"{video}")
except ffmpeg.Error as e:
print(e.stderr.decode(), file=sys.stderr)
sys.exit(1)
primary_stream = {}
for stream in vid_ff["streams"]:
if stream["codec_type"] not in primary_stream:
primary_stream[stream["codec_type"]] = int(stream["index"])
if primary_stream[stream["codec_type"]] > int(stream["index"]):
primary_stream[stream["codec_type"]] = int(stream["index"])
info_json = {}
info_json["id"] = vid_ff["format"]["tags"]["comment"].split("?v=")[1]
info_json["title"] = vid_ff["format"]["tags"]["title"]
info_json["formats"] = []
vid_format = {}
vid_format["format_id"] = vid_ff["format"]["tags"]["major_brand"]
vid_format["format_note"] = f"{vid_ff['format']['tags']['major_brand']}."
vid_format["format_note"] += f"{vid_ff['format']['tags']['minor_version']}"
vid_format["ext"] = os.path.splitext(video)[-1]
vid_format["protocol"] = vid_ff["format"]["tags"]["compatible_brands"]
vid_format["acodec"] = vid_ff["streams"][primary_stream["audio"]][
"codec_name"
]
vid_format["vcodec"] = vid_ff["streams"][primary_stream["video"]][
"codec_name"
]
vid_format["url"] = vid_ff["format"]["tags"]["comment"]
vid_format["width"] = vid_ff["streams"][primary_stream["video"]][
"coded_width"
]
vid_format["height"] = vid_ff["streams"][primary_stream["video"]][
"coded_height"
]
vid_format["fps"] = 0
# Fragments are not needed for private or non-existent videos
vid_format["fragments"] = []
vid_format["audio_ext"] = vid_ff["streams"][primary_stream["audio"]][
"codec_long_name"
]
vid_format["video_ext"] = vid_ff["streams"][primary_stream["video"]][
"codec_long_name"
]
vid_format["format"] = vid_ff["format"]["tags"]["compatible_brands"]
vid_format["resolution"] = f"{vid_format['width']}x{vid_format['height']}"
ratio1, ratio2 = vid_ff["streams"][0]["display_aspect_ratio"].split(":", 1)
vid_format["aspect_ratio"] = round(float(ratio1) / float(ratio2), 2)
vid_format["http_headers"] = {
"User-Agent": "Chrome/0.0.0.1",
"Accept": "text/html,application/xhtml+xml,application/xml",
"Accept-Language": "en-us,en;q=0.5",
"Sec-Fetch-Mode": "navigate",
}
info_json["formats"].append(vid_format)
info_json["thumbnails"] = []
info_json["thumbnail"] = ""
info_json["description"] = vid_ff["format"]["tags"]["description"]
info_json["uploader"] = os.getenv("SHOW_NAME")
ch_id = ""
try:
with open(f"{file_dest}/channel.id") as file:
for line in file.readlines():
if len(line) > 0:
ch_id = line.strip()
except BaseException as E:
print(
f"Unable to open channel.id file at the destination: {file_dest}",
"\nNot including a channel ID.",
)
print(E)
info_json["uploader_id"] = ch_id
info_json[
"uploader_url"
] = f"http://www.youtube.com/channel/{info_json['uploader_id']}"
info_json["channel_id"] = ch_id
info_json[
"channel_url"
] = f"http://www.youtube.com/channel/{info_json['uploader_id']}"
info_json["duration"] = int(round(float(vid_ff["format"]["duration"]), 0))
info_json["view_count"] = 0
info_json["age_limit"] = 0
info_json["webpage_url"] = vid_ff["format"]["tags"]["comment"]
info_json["categories"] = []
info_json["categories"].append(reason)
info_json["tags"] = []
info_json["categories"].append(reason)
info_json["playable_in_embed"] = True
info_json["live_status"] = "not_live"
info_json["automatic_captions"] = {}
info_json["subtitles"] = {}
info_json["comment_count"] = 0
info_json["like_count"] = 0
info_json["channel"] = os.getenv("SHOW_NAME")
info_json["channel_follow_count"] = 0
info_json["upload_date"] = vid_ff["format"]["tags"]["date"]
info_json["availability"] = reason
info_json["webpage_url_basename"] = "watch"
info_json["webpage_url_domain"] = "youtube.com"
info_json["extractor"] = "youtube"
info_json["extractor_key"] = "Youtube"
info_json["display_id"] = info_json["id"]
info_json["fulltitle"] = vid_ff["format"]["tags"]["title"]
info_json["duration_string"] = str(
datetime.timedelta(seconds=info_json["duration"])
)
info_json["is_live"] = False
info_json["was_live"] = False
info_json["format_id"] = "0"
info_json["ext"] = "mp4"
info_json["protocol"] = "https"
info_json["format_note"] = vid_format["format_note"]
info_json["filesize_approx"] = vid_ff["format"]["size"]
info_json["tbr"] = 0 # TBR Values are not necessary
info_json["width"] = vid_format["width"]
info_json["height"] = vid_format["height"]
info_json["resolution"] = f"{info_json['width']}x{info_json['height']}"
info_json["format"] = f"{info_json['format_id']} -"
info_json["format"] += f" {info_json['format_note']}"
info_json["format"] += f" ({info_json['resolution']})"
info_json["fps"] = 24 # Assume default
info_json["dynamic_range"] = "SDR" # Assume default
info_json["vcodec"] = vid_format["vcodec"]
info_json["vbr"] = 0 # VBR Values are not necessary
info_json["aspect_ratio"] = vid_format["aspect_ratio"]
info_json["acodec"] = vid_format["acodec"]
info_json["abr"] = 0 # ABR Values are not necessary
info_json["asr"] = 0 # ASR Values are not necessary
info_json["audio_channels"] = vid_ff["streams"][primary_stream["audio"]][
"channels"
]
info_json["epoch"] = int(time.time())
info_json["_type"] = "video"
info_json["_version"] = {}
info_json["_version"]["version"] = "2023.01.01-dummy"
info_json["_version"]["release_git_head"] = "0000000000000000000000000000000000000000"
info_json["_version"]["repository"] = "yt-dlp/yt-dlp"
print("Dictionary for .info.json file is filled. Writing to file.")
with open(f"{file_dest}/{info_file}", "w") as file:
json.dump(info_json, file)
print(f"File {file_dest}/{info_file} successfully written.")
return 0
#Run the function create_info_json(filename,dir)