Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ [#60] Add examples for listing comments for a video using /next endpoint #66

Merged
merged 2 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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/"]
Loading