Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
bbc8c9e
Disable assertPlayability to avoid error on members only stream
HitomaruKonpaku Sep 3, 2022
2de2a0a
Parse more video metadata from html
HitomaruKonpaku Sep 3, 2022
e5c8b6b
Format & update typing
HitomaruKonpaku Sep 8, 2022
e2e969c
Fix milestone message `durationText` parser
HitomaruKonpaku Dec 10, 2022
f663e17
Skip error actions
HitomaruKonpaku Dec 10, 2022
0849ac9
Add chat metadata isMembersOnly
HitomaruKonpaku Jul 9, 2023
e8d4f5e
Try to fix build issue
HitomaruKonpaku Apr 22, 2024
c4182c3
Fix for membersOnly stream
HitomaruKonpaku May 8, 2024
b902acd
Store video extra metadata
HitomaruKonpaku May 11, 2024
66eaa30
Allow to update metadata & extend masterchat
HitomaruKonpaku May 12, 2024
0132e74
Fix unreachable code
HitomaruKonpaku Sep 24, 2024
820cf71
Update YTLiveChatPollRenderer payload
HitomaruKonpaku Sep 24, 2024
297cb6b
Update function access modifiers
HitomaruKonpaku Jun 4, 2025
29dcb0a
Update metadata parser
HitomaruKonpaku Jun 17, 2025
df729d4
Update metadata interface
HitomaruKonpaku Jun 17, 2025
ad4e10c
Update metadata parser
HitomaruKonpaku Jun 17, 2025
712a012
Add isUpcoming
HitomaruKonpaku Jun 18, 2025
9727fdf
release: v1.2.0
HitomaruKonpaku Jun 18, 2025
5eb75b9
Ignore cheerio type
HitomaruKonpaku Jun 18, 2025
999b6a2
Update README
HitomaruKonpaku Jun 18, 2025
e873c9d
Add membership to addMembershipTickerAction
HitomaruKonpaku Jun 20, 2025
5e03fc6
Update addBannerToLiveChatCommand from stu43005/masterchat
HitomaruKonpaku Jun 20, 2025
b15aa48
Update assertPlayability
HitomaruKonpaku Jun 29, 2025
8666af4
Update assertPlayability
HitomaruKonpaku Jun 29, 2025
5477ae1
Throw some data on MembersOnlyError
HitomaruKonpaku Jul 2, 2025
1ef1a39
Fix error
HitomaruKonpaku Jul 3, 2025
d02f025
Ability to set timeoutLength in timeoutParams
FlashlightXi Jul 4, 2025
8650ff7
Fix flatMap Type Error
FlashlightXi Jul 4, 2025
d2998bd
Delete iterator-helpers-polyfill
FlashlightXi Jul 4, 2025
d7bbf83
Merge pull request #1 from FlashlightXi/master
HitomaruKonpaku Jul 4, 2025
d796dd5
Add bot error
HitomaruKonpaku Jul 5, 2025
1ab38d7
Refactor
HitomaruKonpaku Jul 6, 2025
baa1066
Update docs url
HitomaruKonpaku Jul 6, 2025
036f789
Update CHANGELOG
HitomaruKonpaku Jul 6, 2025
ae0d899
release: v1.3.0
HitomaruKonpaku Jul 6, 2025
97a8c22
Fix MembersOnly chat
HitomaruKonpaku Dec 28, 2025
1fc8b05
Update error info
HitomaruKonpaku Dec 28, 2025
af71d08
Rollback & Refactor as YT not allow membersOnly without credentials a…
HitomaruKonpaku Dec 29, 2025
1ef4811
Add more detail to addOutgoingRaidBannerAction & addIncomingRaidBanne…
HitomaruKonpaku Jan 16, 2026
6054388
Ignore BotError
HitomaruKonpaku Jan 29, 2026
44fcc04
Add emojis
HitomaruKonpaku Apr 15, 2026
794f4b2
Emit payload for more control
HitomaruKonpaku Apr 15, 2026
44fd4ce
Allow custom cookies
HitomaruKonpaku Apr 25, 2026
49ef0fb
Update doc
HitomaruKonpaku Apr 25, 2026
23d2638
Fix channel parser for `Collaborators` case
HitomaruKonpaku Apr 27, 2026
873d50b
Update by pass YT check
HitomaruKonpaku Apr 28, 2026
89cfd18
Update bypass condition
HitomaruKonpaku Apr 28, 2026
617ca5c
Send more data on error
HitomaruKonpaku Apr 30, 2026
40bcf40
Update error data
HitomaruKonpaku Apr 30, 2026
8bdd7cd
Allow to provide custom clientVersion
HitomaruKonpaku May 18, 2026
d10f430
Change access
HitomaruKonpaku May 18, 2026
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
],
"dependencies": {
"axios": "^0.27.2",
"cheerio": "^1.0.0-rc.12",
"debug": "^4.3.2",
"iterator-helpers-polyfill": "^2.2.8",
"sha1": "^1.1.1"
Expand Down
58 changes: 56 additions & 2 deletions src/context/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as cheerio from "cheerio";
import {
MembersOnlyError,
NoPermissionError,
Expand Down Expand Up @@ -107,7 +108,7 @@ export function parseMetadataFromWatch(html: string) {
const initialData = findInitialData(html)!;

const playabilityStatus = findPlayabilityStatus(html);
assertPlayability(playabilityStatus);
// assertPlayability(playabilityStatus);

// TODO: initialData.contents.twoColumnWatchNextResults.conversationBar.conversationBarRenderer.availabilityMessage.messageRenderer.text.runs[0].text === 'Chat is disabled for this live stream.'
const results =
Expand All @@ -120,7 +121,8 @@ export function parseMetadataFromWatch(html: string) {
const title = runsToString(primaryInfo.title.runs);
const channelId = videoOwner.navigationEndpoint.browseEndpoint.browseId;
const channelName = runsToString(videoOwner.title.runs);
const isLive = primaryInfo.viewCount!.videoViewCountRenderer.isLive ?? false;
const metadata = parseVideoMetadataFromHtml(html);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

you parsed the metadata but I don't think you're exposing it anywhere at all?

@HitomaruKonpaku HitomaruKonpaku Nov 30, 2022

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Currently we just return simple data (title/channelId/channelName)

But I just think we can return full metadata in case anyone need 🤔

const isLive = !metadata?.publication?.endDate ?? false;

return {
title,
Expand All @@ -129,3 +131,55 @@ export function parseMetadataFromWatch(html: string) {
isLive,
};
}

/**
* @see http://schema.org/VideoObject
*/
function parseVideoMetadataFromHtml(html: string) {
const $ = cheerio.load(html);
const meta = parseVideoMetadataFromElement(
$("[itemtype=http://schema.org/VideoObject]")?.[0]
);
return meta;
}

function parseVideoMetadataFromElement(
root: any,
meta: Record<string, any> = {}
) {
root?.children?.forEach((child: cheerio.Element) => {
const attributes = child?.attribs;
const key = attributes?.itemprop;
if (!key) {
return;
}

if (child.children.length) {
meta[key] = parseVideoMetadataFromElement(child);
return;
}

const value = parseVideoMetaValueByKey(
key,
attributes?.href || attributes?.content
);
meta[key] = value;
});

return meta;
}

function parseVideoMetaValueByKey(key: string, value: string) {
switch (key) {
case "paid":
case "unlisted":
case "isFamilyFriendly":
case "interactionCount":
case "isLiveBroadcast":
return /true/i.test(value);
case "width":
case "height":
return Number(value);
}
return value;
}