Code to get chapters from Disney+ (for BAMSDK v7.3.0)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def get_chapters(self, title): | |
milestones = [] | |
for type_, type_milestones in title.service_data.get("milestone").items(): | |
for milestone in type_milestones: | |
milestones.append((type_, milestone)) | |
if not milestones: | |
return [] | |
types = { | |
# https://github.com/IMFTool/IMFTool/blob/master/src/ImfCommon.cpp#L458-L504 | |
"FFER": "Recap", # recap_start | |
"LFER": "Scene {i}", # recap_end | |
"FFEI": "Intro", # intro_start | |
"FFTC": "Intro", # First Frame of Title Credits. This may be after the actual episode has already started. | |
"LFEI": "Scene {i}", # intro_end | |
"LFTC": "Scene {i}", # Last Frame of Title Credits (see above). | |
"FPCI": "Scene {i}", # Placeholder for commercial breaks | |
"FFEC": "Credits", | |
# TODO: Are these used for anything else? | |
"tag_start": "Post-Credits Scene {j}", | |
# This is when the player shrinks and the next episode countdown starts. | |
# May be later than the actual start of credits. | |
"up_next": "Credits", | |
} | |
alternate_types = { | |
("FFER",): "recap_start", | |
("LFER",): "recap_end", | |
("FFEI",): "intro_start", | |
("FFEI", "intro_start"): "FFTC", # Not an exact match | |
("LFEI",): "intro_end", | |
("LFEI", "intro_end"): "LFTC", # Not an exact match | |
("FFEC",): "up_next", # Not an exact match | |
} | |
ignore_types = [ | |
"FFOC", # First Frame of Composition. Seems to include intro and maybe recap too. | |
"LFEC", # End of Credits | |
"tag_end", # End of Post-Credits Scene | |
"LFOC", # Last Frame of Composition. Seems to include credits. | |
] | |
chapters = [] | |
scene = 0 | |
post_credit = 0 | |
num_post_credit = len([1 for t, _ in milestones if t == "tag_start"]) | |
for main_types, alternate in alternate_types.items(): | |
if any(type_ in main_types for type_, _ in milestones): | |
ignore_types.append(alternate) | |
for type_, milestone in sorted(milestones, key=lambda tm: tm[1]["milestoneTime"][0]["startMillis"]): | |
if type_ in ignore_types: | |
continue | |
if not (name := types.get(type_)): | |
self.log.warning(f"Skipping unknown chapter type {type_}") | |
continue | |
ms = int(milestone["milestoneTime"][0]["startMillis"]) | |
if "{i}" in name: | |
scene += 1 | |
if "{j}" in name: | |
post_credit += 1 | |
chapter = MenuTrack( | |
number=len(chapters) + 1, | |
title=name.format(i=scene, j=post_credit if num_post_credit > 1 else "").strip(), | |
timecode=ms / 1000, | |
) | |
chapter.note = type_ | |
chapters.append(chapter) | |
return chapters |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment