Skip to content

Instantly share code, notes, and snippets.

@larsenv
Last active February 5, 2025 16:30
Show Gist options
  • Save larsenv/432ffbd58978df07dd2e43089a12f8db to your computer and use it in GitHub Desktop.
Save larsenv/432ffbd58978df07dd2e43089a12f8db to your computer and use it in GitHub Desktop.
PBS Kids Video Downloader
import json
import requests
import subprocess
import re
home = requests.get("https://content.services.pbskids.org/v2/kidspbsorg/home/").text
home = json.loads(home)
shows = {}
episodes = {}
print("==========PBS Kids Show Downloader by Larsenv==========\n")
def title(j, k, data):
i = 0
for f in data:
i += 1
number = str(j) + str(i).zfill(2)
number = number.zfill(3)
if k == 0:
shows[number] = f
elif k == 1:
episodes[number] = f
print(number + ". " + f["title"])
print("Show List:")
print("\nWeekly Promo:\n")
promo = home["collections"]["kids-promo"]
shows["000"] = promo
print("000. " + promo["title"])
print("\nSpotlight:\n")
spotlight = home["collections"]["kids-show-spotlight"]["content"]
shows["001"] = spotlight[0]
print("001. " + spotlight[0]["title"])
for i in range(1, 4):
print("\nTier {}:\n".format(i))
title(i, 0, home["collections"]["kids-programs-tier-{}".format(i)]["content"])
selection = input("\nPlease enter the number of the show you want to download: ")
url = shows[selection]["URI"].replace("pbs.org", "pbskids.org")
showhome = json.loads(requests.get(url).text)
print("\nEpisode and Clips List:")
print("\nClips:\n")
title("", 1, showhome["collections"]["clips"]["content"])
print("\nEpisodes:\n")
title(2, 1, showhome["collections"]["episodes"]["content"])
print("\nPromoted Content:\n")
title(3, 1, showhome["collections"]["promoted_content"]["content"])
print("\nWould you like to download a single episode/clip or all episodes/clips?\n")
print("1. Single episode/clip")
print("2. All clips")
print("3. All episodes")
print("4. All promoted content")
choice = input("\nPlease enter your choice: ")
if choice == "1":
selection2 = input("\nPlease enter the number of the episode or clip you want to download: ")
selections_to_download = [selection2]
elif choice == "2":
selections_to_download = [key for key in episodes.keys() if key.startswith('1')]
elif choice == "3":
selections_to_download = [key for key in episodes.keys() if key.startswith('2')]
elif choice == "4":
selections_to_download = [key for key in episodes.keys() if key.startswith('3')]
else:
print("Invalid choice. Exiting.")
exit()
for selection2 in selections_to_download:
print(f"\nDownloading {episodes[selection2]['title']}...")
# Follow the redirect to get the final episode URI
redirected_uri = requests.get(episodes[selection2]["URI"], allow_redirects=True).url
# Modify the episode URI to remove the resolution part
episode_uri = re.sub(r'-\d+p_', '_', redirected_uri)
# Fetch subtitles from 'closedCaptionsMultiLanguage' and pick the most compatible type
preferred_formats = ["WebVTT", "SRT", "DFXP", "Caption-SAMI"]
subtitle_languages = {}
for cc in episodes[selection2]["closedCaptionsMultiLanguage"]:
lang = cc["language"]
if lang not in subtitle_languages:
subtitle_languages[lang] = cc
else:
current_format = cc["format"]
existing_format = subtitle_languages[lang]["format"]
if preferred_formats.index(current_format) < preferred_formats.index(existing_format):
subtitle_languages[lang] = cc
# Collect the chosen subtitle URIs
all_subtitles = [subtitle_languages[lang]["URI"] for lang in subtitle_languages]
filename = (shows[selection]["title"] + " - " + episodes[selection2]["title"] + ".mkv").replace("/", " - ")
# Prepare FFmpeg command
ffmpeg_command = ["ffmpeg", "-i", episode_uri]
# Add each subtitle stream to the command as input
for vtt in all_subtitles:
ffmpeg_command.extend(["-i", vtt])
# Map video, audio, and all subtitles
ffmpeg_command.extend(["-map", "p:0"])
for i in range(len(all_subtitles)):
ffmpeg_command.extend(["-map", str(i + 1)])
# Set codec options
ffmpeg_command.extend(["-c", "copy"])
# Add metadata for language and title after all inputs
for i, (lang, cc) in enumerate(subtitle_languages.items()):
ffmpeg_command.extend([f"-metadata:s:s:{i}", f"language={lang}"])
subtitle_name = cc.get("name", lang)
ffmpeg_command.extend([f"-metadata:s:s:{i}", f"title={subtitle_name}"])
# Add output filename
ffmpeg_command.append(filename)
# Execute FFmpeg command
subprocess.call(ffmpeg_command)
print(f"\n{episodes[selection2]['title']} downloaded successfully!")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment