Skip to content

Feature/live chat comments#1481

Draft
Ecomont wants to merge 17 commits intoTeamNewPipe:devfrom
Ecomont:feature/live-chat-comments
Draft

Feature/live chat comments#1481
Ecomont wants to merge 17 commits intoTeamNewPipe:devfrom
Ecomont:feature/live-chat-comments

Conversation

@Ecomont
Copy link
Copy Markdown
Contributor

@Ecomont Ecomont commented Apr 24, 2026

This PR adds support for extracting YouTube live chat messages and exposing them through the existing comments API. When a live stream has regular comments disabled, the extractor now falls back to fetching live chat messages instead.

Changes

  • CommentsExtractor / CommentsInfo: Added isLiveChat() flag to distinguish live chat from regular comments.
  • YoutubeCommentsExtractor: Added findLiveChatContinuation() and fetchLiveChat() to retrieve live chat via the live_chat/get_live_chat endpoint.
  • YoutubeLiveChatInfoItemExtractor: New extractor that maps liveChatTextMessageRenderer JSON to CommentsInfoItem, with proper emoji run handling.
  • Page routing: Live chat continuations are marked with a live_chat page identifier so getPage() routes correctly on subsequent extractor instances.

Implementation notes

The approach is based on the live chat implementation in PipePipe, adapted to fit the NewPipe Extractor architecture. Key adaptations include:

  • Reusing the existing CommentsInfoItem type instead of introducing a separate live chat item class.
  • Proper isLiveStream flag handling to avoid hitting the replay endpoint on fresh extractors.
  • Emoji extraction with fallback chain: emojiIdshortcuts[]searchTerms[][emoji].

Checklist

  • I carefully read the contribution guidelines and agree to them.
  • I have tested the API against NewPipe.
  • I agree to create a pull request for NewPipe as soon as possible to make it compatible with the changed API.

@TobiGr TobiGr added enhancement New feature or request YouTube Service, https://www.youtube.com/ labels Apr 24, 2026
Copy link
Copy Markdown
Member

@absurdlylongusername absurdlylongusername left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do proper review later, but for now:

Please add tests. We should not be adding any new functionality to the extractor without adequate testing.

@Ecomont Ecomont marked this pull request as draft April 27, 2026 04:56
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor

@TobiGr TobiGr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you

/**
* Whether this video is / was a live stream.
*/
private boolean isLiveStream;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand why there are two ways to determine whether this extractor handles a live stream/chat. While isLiveStream is used and set individually for internal purposes, isLiveChat() relies on liveChatContinuation. I think isLiveChat can be removed.

Please explain why two different ways are needed. As far as I understand YouTube how handles this, a video can either have comments or a live chat, but not both at the same time. Is this correct?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isLiveChat() cannot be removed because it represents the extractor's configuration mode set externally via setLiveChatContinuation() whereas isLiveStream represents the video's metadata. A live-stream video may or may not have live chat configured on this extractor instance.

However, you are correct that the ternary inside fetchLiveChat() is dead code because isLiveStream is overwriten to true at the top of the method. I will either remove the ternary or pass the replay/live flag as a parameter instead.

Comment on lines +403 to +417
private InfoItemsPage<CommentsInfoItem> fetchLiveChat(final String chatContinuation)
throws IOException, ExtractionException {
isLiveStream = true;
final Localization localization = getExtractorLocalization();
final byte[] json = JsonWriter.string(
prepareDesktopJsonBuilder(localization, getExtractorContentCountry())
.value("continuation", chatContinuation)
.object("currentPlayerState")
.value("playerOffsetMs", "0")
.end()
.done())
.getBytes(StandardCharsets.UTF_8);

final String endpoint = "live_chat/"
+ (isLiveStream ? "get_live_chat" : "get_live_chat_replay");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isLiveChat is always true here

Comment on lines +64 to +66
if (emojiText != null) {
textBuilder.append(emojiText);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emojiText cannot be null. I think the condition can be removed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will remove the null check

Comment on lines +84 to +91
// For standard emojis, emojiId is the Unicode character itself.
// For custom emojis it is an ID, but still better than nothing.
if (emoji.has("emojiId")) {
final String emojiId = emoji.getString("emojiId", "");
if (!emojiId.isEmpty()) {
return emojiId;
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a real id as text is not good. It's way to long and always present (see below). You should check whether isCustomEmoji is false when using the emoji id. You could leave a TODO comment to remind us discussing the inclusion of the thumbnail as img tag to fix this.

JSON
{
  "message": {
    "runs": [
      {
        "emoji": {
          "emojiId": "UCkszU2WH9gy1mb0dV-11UJg/uP90Xq6wNYrK8gTUoo3wAg",
          "shortcuts": [
            ":takeout:"
          ],
          "searchTerms": [
            "takeout"
          ],
          "image": {
            "thumbnails": [
              {
                "url": "https://yt3.ggpht.com/FizHI5IYMoNql9XeP7TV3E0ffOaNKTUSXbjtJe90e1OUODJfZbWU37VqBbTh-vpyFHlFIS0=w24-h24-c-k-nd",
                "width": 24,
                "height": 24
              },
              {
                "url": "https://yt3.ggpht.com/FizHI5IYMoNql9XeP7TV3E0ffOaNKTUSXbjtJe90e1OUODJfZbWU37VqBbTh-vpyFHlFIS0=w48-h48-c-k-nd",
                "width": 48,
                "height": 48
              }
            ],
            "accessibility": {
              "accessibilityData": {
                "label": "takeout"
              }
            }
          },
          "isCustomEmoji": true
        }
      }
    ]
  }
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change it, thanks for the feedback

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request YouTube Service, https://www.youtube.com/

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants