Skip to content

Commit

Permalink
feat: new action AddRedirectBannerAction
Browse files Browse the repository at this point in the history
  • Loading branch information
uetchy committed May 26, 2022
1 parent ff73d0e commit 3f1747d
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 51 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
- `mc.getTranscript()`
- Playlist API
- `mc.getPlaylist()`
- New: `ModerationMessageAction` (type: `moderationMessageAction`)
- New: `ModerationMessageAction` (type: `moderationMessageAction`) for moderation messages for moderators
- New: `AddRedirectBannerAction` (type: `addRedirectBannerAction`) for raid event notifications
- Add support for `Raid` event

### Improvements

Expand Down
117 changes: 68 additions & 49 deletions src/chat/actions/addBannerToLiveChatCommand.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { AddBannerAction } from "../../interfaces/actions";
import {
AddBannerAction,
AddRedirectBannerAction,
} from "../../interfaces/actions";
import { YTAddBannerToLiveChatCommand } from "../../interfaces/yt/chat";
import { debugLog, stringify, tsToDate } from "../../utils";
import { parseBadges } from "../badge";
Expand All @@ -10,16 +13,10 @@ export function parseAddBannerToLiveChatCommand(
// add pinned item
const bannerRdr = payload["bannerRenderer"]["liveChatBannerRenderer"];

if (!bannerRdr.header) {
throw new Error(
"[action required] Invalid banner header: " + JSON.stringify(bannerRdr)
);
}

if (bannerRdr.header.liveChatBannerHeaderRenderer.icon.iconType !== "KEEP") {
if (bannerRdr.header?.liveChatBannerHeaderRenderer.icon.iconType !== "KEEP") {
debugLog(
"[action required] Unknown icon type (addBannerToLiveChatCommand)",
JSON.stringify(bannerRdr.header.liveChatBannerHeaderRenderer.icon)
JSON.stringify(bannerRdr.header)
);
}

Expand All @@ -28,48 +25,70 @@ export function parseAddBannerToLiveChatCommand(
const targetId = bannerRdr.targetId;
const viewerIsCreator = bannerRdr.viewerIsCreator;

// header
const header = bannerRdr.header.liveChatBannerHeaderRenderer;
const title = header.text.runs;

// contents
const liveChatRdr = bannerRdr.contents.liveChatTextMessageRenderer;
const id = liveChatRdr.id;
const message = liveChatRdr.message.runs;
const timestampUsec = liveChatRdr.timestampUsec;
const timestamp = tsToDate(timestampUsec);
const authorName = stringify(liveChatRdr.authorName);
const authorPhoto = pickThumbUrl(liveChatRdr.authorPhoto);
const authorChannelId = liveChatRdr.authorExternalChannelId;
const { isVerified, isOwner, isModerator, membership } =
parseBadges(liveChatRdr);
const contents = bannerRdr.contents;

if (!authorName) {
debugLog(
"[action required] Empty authorName found at addBannerToLiveChatCommand",
JSON.stringify(liveChatRdr)
if ("liveChatTextMessageRenderer" in contents) {
const rdr = contents.liveChatTextMessageRenderer;
const id = rdr.id;
const message = rdr.message.runs;
const timestampUsec = rdr.timestampUsec;
const timestamp = tsToDate(timestampUsec);
const authorName = stringify(rdr.authorName);
const authorPhoto = pickThumbUrl(rdr.authorPhoto);
const authorChannelId = rdr.authorExternalChannelId;
const { isVerified, isOwner, isModerator, membership } = parseBadges(rdr);

// header
const header = bannerRdr.header!.liveChatBannerHeaderRenderer;
const title = header.text.runs;

if (!authorName) {
debugLog(
"[action required] Empty authorName found at addBannerToLiveChatCommand",
JSON.stringify(rdr)
);
}

const parsed: AddBannerAction = {
type: "addBannerAction",
actionId,
targetId,
id,
title,
message,
timestampUsec,
timestamp,
authorName,
authorPhoto,
authorChannelId,
isVerified,
isOwner,
isModerator,
membership,
viewerIsCreator,
contextMenuEndpointParams:
rdr.contextMenuEndpoint?.liveChatItemContextMenuEndpoint.params,
};
return parsed;
} else if ("liveChatBannerRedirectRenderer" in contents) {
// TODO:
const rdr = contents.liveChatBannerRedirectRenderer;
const authorName = rdr.bannerMessage.runs[0].text;
const authorPhoto = pickThumbUrl(rdr.authorPhoto);
const payload: AddRedirectBannerAction = {
type: "addRedirectBannerAction",
actionId,
targetId,
authorName,
authorPhoto,
};
return payload;
} else {
throw new Error(
`[action required] Unrecognized content type found in parseAddBannerToLiveChatCommand: ${JSON.stringify(
payload
)}`
);
}

const parsed: AddBannerAction = {
type: "addBannerAction",
actionId,
targetId,
id,
title,
message,
timestampUsec,
timestamp,
authorName,
authorPhoto,
authorChannelId,
isVerified,
isOwner,
isModerator,
membership,
viewerIsCreator,
contextMenuEndpointParams:
liveChatRdr.contextMenuEndpoint?.liveChatItemContextMenuEndpoint.params,
};
return parsed;
}
9 changes: 9 additions & 0 deletions src/interfaces/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type Action =
| AddMembershipTickerAction
| AddBannerAction
| RemoveBannerAction
| AddRedirectBannerAction
| AddViewerEngagementMessageAction
| ShowPanelAction
| ShowPollPanelAction
Expand Down Expand Up @@ -265,6 +266,14 @@ export interface RemoveBannerAction {
targetActionId: string;
}

export interface AddRedirectBannerAction {
type: "addRedirectBannerAction";
actionId: string;
targetId: string;
authorName: string;
authorPhoto: string;
}

export interface ShowTooltipAction {
type: "showTooltipAction";
targetId: string;
Expand Down
30 changes: 29 additions & 1 deletion src/interfaces/yt/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,10 @@ export interface YTLiveChatModerationMessageRendererContainer {
liveChatModerationMessageRenderer: YTLiveChatModerationMessageRenderer;
}

export interface YTLiveChatBannerRedirectRendererContainer {
liveChatBannerRedirectRenderer: YTLiveChatBannerRedirectRenderer;
}

// LiveChat Renderers

export interface YTLiveChatTextMessageRenderer {
Expand Down Expand Up @@ -461,7 +465,9 @@ export interface YTLiveChatPlaceholderItemRenderer {
export interface YTLiveChatBannerRenderer {
actionId: string;
targetId: string; // live-chat-banner
contents: YTLiveChatTextMessageRendererContainer;
contents:
| YTLiveChatTextMessageRendererContainer
| YTLiveChatBannerRedirectRendererContainer;
header?: YTLiveChatBannerRendererHeader;
viewerIsCreator: boolean;
}
Expand Down Expand Up @@ -510,6 +516,28 @@ export interface YTLiveChatActionPanelRenderer {
targetId: string;
}

export interface YTLiveChatBannerRedirectRenderer {
/**
* "runs": [
{
"text": "Athena Nightingale【AkioAIR】",
"bold": true,
"textColor": 4294967295,
"fontFace": "FONT_FACE_ROBOTO_REGULAR"
},
{
"text": " and their viewers just joined. Say hello!",
"textColor": 4294967295,
"fontFace": "FONT_FACE_ROBOTO_REGULAR"
}
]
*/
bannerMessage: YTRunContainer<YTTextRun>;
authorPhoto: YTThumbnailList;
inlineActionButton: YTActionButtonRendererContainer;
contextMenuButton: YTContextMenuButtonRendererContainer;
}

export interface YTLiveChatPollChoice {
text: YTText;
selected: boolean;
Expand Down

0 comments on commit 3f1747d

Please sign in to comment.