1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
"""commonly used navigation paths"""
from typing import Any, Literal, Optional, overload
CONTENT = ["contents", 0]
RUN_TEXT = ["runs", 0, "text"]
TAB_CONTENT = ["tabs", 0, "tabRenderer", "content"]
TAB_1_CONTENT = ["tabs", 1, "tabRenderer", "content"]
TAB_2_CONTENT = ["tabs", 2, "tabRenderer", "content"]
TWO_COLUMN_RENDERER = ["contents", "twoColumnBrowseResultsRenderer"]
SINGLE_COLUMN = ["contents", "singleColumnBrowseResultsRenderer"]
SINGLE_COLUMN_TAB = SINGLE_COLUMN + TAB_CONTENT
SECTION = ["sectionListRenderer"]
SECTION_LIST = [*SECTION, "contents"]
SECTION_LIST_ITEM = SECTION + CONTENT
RESPONSIVE_HEADER = ["musicResponsiveHeaderRenderer"]
ITEM_SECTION = ["itemSectionRenderer", *CONTENT]
MUSIC_SHELF = ["musicShelfRenderer"]
GRID = ["gridRenderer"]
GRID_ITEMS = [*GRID, "items"]
MENU = ["menu", "menuRenderer"]
MENU_ITEMS = [*MENU, "items"]
MENU_LIKE_STATUS = [*MENU, "topLevelButtons", 0, "likeButtonRenderer", "likeStatus"]
MENU_SERVICE = ["menuServiceItemRenderer", "serviceEndpoint"]
TOGGLE_MENU = "toggleMenuServiceItemRenderer"
OVERLAY_RENDERER = ["musicItemThumbnailOverlayRenderer", "content", "musicPlayButtonRenderer"]
PLAY_BUTTON = ["overlay", *OVERLAY_RENDERER]
NAVIGATION_BROWSE = ["navigationEndpoint", "browseEndpoint"]
NAVIGATION_BROWSE_ID = [*NAVIGATION_BROWSE, "browseId"]
PAGE_TYPE = ["browseEndpointContextSupportedConfigs", "browseEndpointContextMusicConfig", "pageType"]
WATCH_VIDEO_ID = ["watchEndpoint", "videoId"]
PLAYLIST_ID = ["playlistId"]
WATCH_PLAYLIST_ID = ["watchEndpoint", *PLAYLIST_ID]
NAVIGATION_VIDEO_ID = ["navigationEndpoint", *WATCH_VIDEO_ID]
QUEUE_VIDEO_ID = ["queueAddEndpoint", "queueTarget", "videoId"]
NAVIGATION_PLAYLIST_ID = ["navigationEndpoint", *WATCH_PLAYLIST_ID]
WATCH_PID = ["watchPlaylistEndpoint", *PLAYLIST_ID]
NAVIGATION_WATCH_PLAYLIST_ID = ["navigationEndpoint", *WATCH_PID]
NAVIGATION_VIDEO_TYPE = [
"watchEndpoint",
"watchEndpointMusicSupportedConfigs",
"watchEndpointMusicConfig",
"musicVideoType",
]
ICON_TYPE = ["icon", "iconType"]
TOGGLED_BUTTON = ["toggleButtonRenderer", "isToggled"]
TITLE = ["title", "runs", 0]
TITLE_TEXT = ["title", *RUN_TEXT]
TEXT_RUNS = ["text", "runs"]
TEXT_RUN = [*TEXT_RUNS, 0]
TEXT_RUN_TEXT = [*TEXT_RUN, "text"]
SUBTITLE = ["subtitle", *RUN_TEXT]
SUBTITLE_RUNS = ["subtitle", "runs"]
SUBTITLE_RUN = [*SUBTITLE_RUNS, 0]
SUBTITLE2 = [*SUBTITLE_RUNS, 2, "text"]
SUBTITLE3 = [*SUBTITLE_RUNS, 4, "text"]
THUMBNAIL = ["thumbnail", "thumbnails"]
THUMBNAILS = ["thumbnail", "musicThumbnailRenderer", *THUMBNAIL]
THUMBNAIL_RENDERER = ["thumbnailRenderer", "musicThumbnailRenderer", *THUMBNAIL]
THUMBNAIL_OVERLAY = ["thumbnailOverlay", *OVERLAY_RENDERER, "playNavigationEndpoint", *WATCH_PID]
THUMBNAIL_CROPPED = ["thumbnail", "croppedSquareThumbnailRenderer", *THUMBNAIL]
FEEDBACK_TOKEN = ["feedbackEndpoint", "feedbackToken"]
BADGE_PATH = [0, "musicInlineBadgeRenderer", "accessibilityData", "accessibilityData", "label"]
BADGE_LABEL = ["badges", *BADGE_PATH]
SUBTITLE_BADGE_LABEL = ["subtitleBadges", *BADGE_PATH]
CATEGORY_TITLE = ["musicNavigationButtonRenderer", "buttonText", *RUN_TEXT]
CATEGORY_PARAMS = ["musicNavigationButtonRenderer", "clickCommand", "browseEndpoint", "params"]
MMRIR = "musicMultiRowListItemRenderer"
MRLIR = "musicResponsiveListItemRenderer"
MTRIR = "musicTwoRowItemRenderer"
MNIR = "menuNavigationItemRenderer"
TASTE_PROFILE_ITEMS = ["contents", "tastebuilderRenderer", "contents"]
TASTE_PROFILE_ARTIST = ["title", "runs"]
SECTION_LIST_CONTINUATION = ["continuationContents", "sectionListContinuation"]
MENU_PLAYLIST_ID = [*MENU_ITEMS, 0, MNIR, *NAVIGATION_WATCH_PLAYLIST_ID]
MULTI_SELECT = ["musicMultiSelectMenuItemRenderer"]
HEADER = ["header"]
HEADER_DETAIL = [*HEADER, "musicDetailHeaderRenderer"]
EDITABLE_PLAYLIST_DETAIL_HEADER = ["musicEditablePlaylistDetailHeaderRenderer"]
HEADER_EDITABLE_DETAIL = [*HEADER, *EDITABLE_PLAYLIST_DETAIL_HEADER]
HEADER_SIDE = [*HEADER, "musicSideAlignedItemRenderer"]
HEADER_MUSIC_VISUAL = [*HEADER, "musicVisualHeaderRenderer"]
DESCRIPTION_SHELF = ["musicDescriptionShelfRenderer"]
DESCRIPTION = ["description", *RUN_TEXT]
CAROUSEL = ["musicCarouselShelfRenderer"]
IMMERSIVE_CAROUSEL = ["musicImmersiveCarouselShelfRenderer"]
CAROUSEL_CONTENTS = [*CAROUSEL, "contents"]
CAROUSEL_TITLE = [*HEADER, "musicCarouselShelfBasicHeaderRenderer", *TITLE]
CARD_SHELF_TITLE = [*HEADER, "musicCardShelfHeaderBasicRenderer", *TITLE_TEXT]
FRAMEWORK_MUTATIONS = ["frameworkUpdates", "entityBatchUpdate", "mutations"]
TIMESTAMPED_LYRICS = [
"contents",
"elementRenderer",
"newElement",
"type",
"componentType",
"model",
"timedLyricsModel",
"lyricsData",
]
@overload
def nav(root: dict[str, Any], items: list[Any], none_if_absent: Literal[False] = False) -> Any:
"""overload for mypy only"""
@overload
def nav(root: dict, items: list[Any], none_if_absent: Literal[True] = True) -> Optional[Any]:
"""overload for mypy only"""
def nav(root: dict, items: list[Any], none_if_absent: bool = False) -> Optional[Any]:
"""Access a nested object in root by item sequence."""
try:
for k in items:
root = root[k]
except (KeyError, IndexError, TypeError) as e:
if none_if_absent:
return None
raise type(e)(f"Unable to find '{k}' using path {items!r} on {root!r}, exception: {e}")
return root
def find_object_by_key(object_list, key, nested=None, is_key=False):
for item in object_list:
if nested:
item = item[nested]
if key in item:
return item[key] if is_key else item
return None
def find_objects_by_key(object_list, key, nested=None):
objects = []
for item in object_list:
if nested:
item = item[nested]
if key in item:
objects.append(item)
return objects
|