Skip to content

Commit

Permalink
✨ [#60] Add examples for listing comments for a video using /next end…
Browse files Browse the repository at this point in the history
…point (#66)
  • Loading branch information
tombulled committed Feb 25, 2024
1 parent e25abdd commit 3821e95
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 1 deletion.
102 changes: 102 additions & 0 deletions examples/list-video-comments-highlighted.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from innertube import InnerTube

# YouTube Web CLient
CLIENT = InnerTube("WEB", "2.20240105.01.00")


def parse_text(text):
return "".join(run["text"] for run in text["runs"])


def flatten(items):
flat_items = {}

for item in items:
key = next(iter(item))
val = item[key]

flat_items.setdefault(key, []).append(val)

return flat_items


def flatten_item_sections(item_sections):
return {
item_section["sectionIdentifier"]: item_section
for item_section in item_sections
}


def extract_comments(next_continuation_data):
return [
continuation_item["commentThreadRenderer"]
for continuation_item in next_continuation_data["onResponseReceivedEndpoints"][
1
]["reloadContinuationItemsCommand"]["continuationItems"][:-1]
]


def extract_comments_continuation_token(next_data):
contents = flatten(
next_data["contents"]["twoColumnWatchNextResults"]["results"]["results"][
"contents"
]
)
item_sections = flatten_item_sections(contents["itemSectionRenderer"])
comment_item_section_content = item_sections["comment-item-section"]["contents"][0]
comments_continuation_token = comment_item_section_content[
"continuationItemRenderer"
]["continuationEndpoint"]["continuationCommand"]["token"]

return comments_continuation_token


def get_comments(video_id, params=None):
video = CLIENT.next(video_id, params=params)

continuation_token = extract_comments_continuation_token(video)

comments_continuation = CLIENT.next(continuation=continuation_token)

return extract_comments(comments_continuation)


def print_comment(comment):
comment_renderer = comment["comment"]["commentRenderer"]

comment_author = comment_renderer["authorText"]["simpleText"]
comment_content = parse_text(comment_renderer["contentText"])

print(f"[{comment_author}]")
print(comment_content)
print()


video_id = "BV1O7RR-VoA"

# Get comments for a given video
comments = get_comments(video_id)

# Select a comment to highlight (in this case the 3rd one)
comment = comments[2]

# Print the comment we're going to highlight
print("### Highlighting Comment: ###")
print()
print_comment(comment)
print("---------------------")
print()

# Extract the 'params' to highlight this comment
params = comment["comment"]["commentRenderer"]["publishedTimeText"]["runs"][0][
"navigationEndpoint"
]["watchEndpoint"]["params"]

# Get comments, but highlighting the selected comment
highlighted_comments = get_comments(video_id, params=params)

print("### Comments: ###")
print()

for comment in highlighted_comments:
print_comment(comment)
74 changes: 74 additions & 0 deletions examples/list-video-comments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from innertube import InnerTube

ENGAGEMENT_SECTION_COMMENTS = "engagement-panel-comments-section"
C0MMENTS_TOP = "Top comments"
COMMENTS_NEWEST = "Newest first"


def parse_text(text):
return "".join(run["text"] for run in text["runs"])


def extract_engagement_panels(next_data):
engagement_panels = {}
raw_engagement_panels = next_data.get("engagementPanels", [])

for raw_engagement_panel in raw_engagement_panels:
engagement_panel = raw_engagement_panel.get(
"engagementPanelSectionListRenderer", {}
)
target_id = engagement_panel.get("targetId")

engagement_panels[target_id] = engagement_panel

return engagement_panels


def parse_sort_filter_sub_menu(menu):
menu_items = menu["sortFilterSubMenuRenderer"]["subMenuItems"]

return {menu_item["title"]: menu_item for menu_item in menu_items}


def extract_comments(next_continuation_data):
return [
continuation_item["commentThreadRenderer"]
for continuation_item in next_continuation_data["onResponseReceivedEndpoints"][
1
]["reloadContinuationItemsCommand"]["continuationItems"][:-1]
]


# YouTube Web CLient
client = InnerTube("WEB", "2.20240105.01.00")

# ShortCircuit - Dell just DESTROYED the Surface Pro! - Dell XPS 13 2-in-1
video = client.next("BV1O7RR-VoA")

engagement_panels = extract_engagement_panels(video)
comments = engagement_panels[ENGAGEMENT_SECTION_COMMENTS]
comments_header = comments["header"]["engagementPanelTitleHeaderRenderer"]
comments_title = parse_text(comments_header["title"])
comments_context = parse_text(comments_header["contextualInfo"])
comments_menu_items = parse_sort_filter_sub_menu(comments_header["menu"])
comments_top = comments_menu_items[C0MMENTS_TOP]
comments_top_continuation = comments_top["serviceEndpoint"]["continuationCommand"][
"token"
]

print(f"{comments_title} ({comments_context})...")
print()

comments_continuation = client.next(continuation=comments_top_continuation)

comments = extract_comments(comments_continuation)

for comment in comments:
comment_renderer = comment["comment"]["commentRenderer"]

comment_author = comment_renderer["authorText"]["simpleText"]
comment_content = parse_text(comment_renderer["contentText"])

print(f"[{comment_author}]")
print(comment_content)
print()
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ ignore_missing_imports = true
show_error_codes = true
warn_redundant_casts = true
warn_unused_configs = true
warn_unused_ignores = true
warn_unused_ignores = true
exclude = ["examples/"]

0 comments on commit 3821e95

Please sign in to comment.