Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
uetchy committed Mar 5, 2022
2 parents de00ca1 + c137d95 commit 7f6cc85
Show file tree
Hide file tree
Showing 137 changed files with 2,326 additions and 5,257 deletions.
42 changes: 42 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"projectName": "masterchat",
"projectOwner": "holodata",
"repoType": "github",
"repoHost": "https://github.com",
"files": [
"README.md"
],
"imageSize": 50,
"commit": true,
"commitConvention": "none",
"contributors": [
{
"login": "uetchy",
"name": "uetchy",
"avatar_url": "https://avatars.githubusercontent.com/u/431808?v=4",
"profile": "https://github.com/uetchy",
"contributions": [
"code"
]
},
{
"login": "stu43005",
"name": "Shiaupiau",
"avatar_url": "https://avatars.githubusercontent.com/u/1288549?v=4",
"profile": "http://www.plurk.com/stu43005",
"contributions": [
"code"
]
},
{
"login": "jprochazk",
"name": "Jan Procházka",
"avatar_url": "https://avatars.githubusercontent.com/u/1665677?v=4",
"profile": "https://jan-prochazka.eu/",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7
}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
*.code-workspace
.vscode
.envrc
*.jsonl
*.schema.json
.venv
TODO.md
res.json
/*/**/yarn.lock
yarn.lock
pnpm-lock.yaml

/lib
__nock-fixtures__
Expand Down
32 changes: 30 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
# Changelog

## Unreleased

### New

- New: Support for Video Comment API (see MANUAL):
- `getComments` for fetching video comments
- `getComment` for fetching video comment by id
- New action: `MembershipGiftPurchaseAction` and `MembershipGiftRedemptionAction`
- New action: `AddPollResultAction` (separated from `AddViewerEngagementMessageAction`)
- New params for `AddBannerAction`: `viewerIsCreator`, `targetId`

### Improvements

- BREAKING: remove `messageType` from `AddViewerEngagementMessageAction`
- BREAKING: normalize `ReplaceChatItemAction.replacementItem` interfaces
- BREAKING: incompatible property name changes
- `AddBannerAction.id` which is actually action id has been renamed to `AddBannerAction.actionId`
- `AddBannerAction.id` now refer to chat id
- Move cli tools (`tools/`) to [`masterchat-cli`](https://github.com/holodata/masterchat-cli)

### Fixes

- Properly handle membership tickers where its content are gift purchase actions
- `AddSuperChatItemAction.authorName` becomes optional (as we've observed such events)
- Special handling for cases where addLiveChatItemAction is missing `message`
- AddLiveChatItemAction.message now becomes optional (you can just ignore those anomalous events)
- Special handling for anomalous emoji entities

## v0.13.0

### New
Expand Down Expand Up @@ -36,7 +64,7 @@
- DEPRECATED: props of `AddSuperChatItemAction.superchat` has been flattened into `AddSuperChatItemAction`
- BREAKING: `end` event will provide a reason (`'privated' | 'deleted' | 'disabled' | 'aborted' | null`)
- `streamPool.on('end', (mc) => {})` -> `streamPool.on('end', (reason, mc) => {})`
- BREAKING: instance will emits `end` instead of `error` in some special cases where the unrecoverable error code is either `private` or `unavailable` and it was not occurred during the first request (this usually happens when a streamer deletes or privates their live stream after the stream ends)
- BREAKING: instance will emit `end` instead of `error` in some special cases where the unrecoverable error code is either `private` or `unavailable`, and it did not occur during the first request (this usually happens when a streamer deletes or privates their live stream after the stream ends)
- BREAKING: `runsToPlainText` will expand `watchEndpoint` when `text` is a fragment of URL
- use Uint8Array instead of Buffer in protobuf lib (by @jprochazk)

Expand Down Expand Up @@ -117,7 +145,7 @@ mc.listen()

### chat

- `.fetch` will attempt to switch an API endpoint to the replay chat if failed to fetch chats from the live chat. Explicitly set `isLive` option `true` or `false` when instiantiating Masterchat to disable this behavior.
- `.fetch` will attempt to switch an API endpoint to the replay chat if failed to fetch chats from the live chat. Explicitly set `isLive` option `true` or `false` when instantiating Masterchat to disable this behavior.
- if unset,
- live -> OK
- archive -> first request fails, then try fetching replay chat -> OK
Expand Down
113 changes: 94 additions & 19 deletions MANUAL.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,75 @@
# Manual
# Masterchat Manual

- [Documentation](https://holodata.github.io/masterchat)
- [Usage](#usage)
- [Reference](#reference)

## Usage

[API Documentation](https://holodata.github.io/masterchat)
### Just grab some metadata

```js
import { Masterchat, stringify } from "masterchat";

const { title, channelId, channelName } = await Masterchat.init("<videoId>");

### Iterate live chats
console.log(`info: ${title} @ ${channelName} (${channelId})`);
```

### Iterate over live chats

```js
import { Masterchat, stringify } from "masterchat";

async function main() {
const mc = await Masterchat.init("<videoId>");

// listen for chats
// Listen for live chat
mc.on("chats", (chats) => {
for (const chat of chats) {
console.log(chat.authorName, stringify(chat.rawMessage));
console.log(chat.authorName, stringify(chat.message));
}
});

// listen for every event
// Listen for any events
// See below for a list of available action types
mc.on("actions", (actions) => {
const chats = actions.filter(
(action) => action.type === "addChatItemAction"
);
const superchats = actions.filter(
const superChats = actions.filter(
(action) => action.type === "addSuperChatItemAction"
);
const placeholderEvents = actions.filter(
(action) => action.type === "AddPlaceholderItemAction"
const superStickers = actions.filter(
(action) => action.type === "addSuperStickerItemAction"
);
});

// Handle errors
mc.on("error", (err) => {
console.log(err.code);
// "disabled" => Live chat is disabled
// "membersOnly" => No permission (members-only)
// "private" => No permission (private video)
// "unavailable" => Deleted OR wrong video id
// "unarchived" => Live stream recording is not available
// "denied" => Access denied
// "denied" => Access denied (429)
// "invalid" => Invalid request
// "unknown" => Unknown error
});

// Handle end event
mc.on("end", () => {
console.log("Live stream has ended");
}

// Start polling live chat API
mc.listen();
}

main();
```
### Download replay chat as JSONLines
### Save replay chats in .jsonl
```js
import { Masterchat } from "masterchat";
Expand All @@ -68,8 +83,8 @@ async function main() {
);

mc.on("chats", async (chats) => {
const jsonl = chats.map((chat) => JSON.stringify(chat)).join("\n");
await appendFile("./chats.jsonl", jsonl + "\n");
const jsonl = chats.map((chat) => JSON.stringify(chat)).join("\n") + "\n";
await appendFile("./chats.jsonl", jsonl);

// save checkpoint
await writeFile("./checkpoint", continuation.token);
Expand All @@ -81,7 +96,7 @@ async function main() {
main();
```
### Auto-moderator
### Chat moderation bot
```js
import { Masterchat, stringify } from "masterchat";
Expand All @@ -101,11 +116,15 @@ async function main() {

mc.on("chats", async (chats) => {
for (const chat of chats) {
const message = stringify(chat.rawMessage, {
const message = stringify(chat.message, {
// omit emojis
emojiHandler: (emoji) => "",
});

if (isSpam(message)) {
if (isSpam(message) || /UGLY/.test(message)) {
// delete chat
// if flagged as spam by Spamreaper
// or contains "UGLY"
await mc.remove(action.id);
}
}
Expand All @@ -117,7 +136,30 @@ async function main() {
main();
```
## Advanced Usage
### Get video comments (≠ live chats)
```js
import { getComments, getComment } from "masterchat";

async function main() {
// Iterate over all comments
let res = getComments("<videoId>", { top: true });
while (true) {
console.log(res.comments);

if (!res.next) break;
res = await res.next();
}

// Get comment by id
const comment = await getComment("<videoId>", "<commentId>");
console.log(comment);
}

main();
```
## Advanced usage
### Faster instantiation
Expand Down Expand Up @@ -149,7 +191,40 @@ npm i
npm start
```
## Stream type
## Reference
[API Documentation](https://holodata.github.io/masterchat)
### Action type
| `type` | description |
| ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| [addChatItemAction](https://holodata.github.io/masterchat/interfaces/AddChatItemAction.html) | Live chat message |
| [addSuperChatItemAction](https://holodata.github.io/masterchat/interfaces/AddSuperChatItemAction.html) | Super chat message |
| [addSuperStickerItemAction](https://holodata.github.io/masterchat/interfaces/AddSuperStickerItemAction.html) | Super sticker message |
| [addMembershipItemAction](https://holodata.github.io/masterchat/interfaces/AddMembershipItemAction.html) | Membership joining message |
| [addMembershipMilestoneItemAction](https://holodata.github.io/masterchat/interfaces/AddMembershipMilestoneItemAction.html) | Membership milestone message |
| [addPlaceholderItemAction](https://holodata.github.io/masterchat/interfaces/AddPlaceholderItemAction.html) | Add a placeholder for later usage (invisible) |
| [replaceChatItemAction](https://holodata.github.io/masterchat/interfaces/ReplaceChatItemAction.html) | Replace a live chat or placeholder with a placeholder or live chat |
| [markChatItemAsDeletedAction](https://holodata.github.io/masterchat/interfaces/MarkChatItemAsDeletedAction.html) | Delete live chat by id |
| [markChatItemsByAuthorAsDeletedAction](https://holodata.github.io/masterchat/interfaces/MarkChatItemsByAuthorAsDeletedAction.html) | Delete live chats by authorChannelId |
| [addSuperChatTickerAction](https://holodata.github.io/masterchat/interfaces/AddSuperChatTickerAction.html) | Ticker for super chat |
| [addSuperStickerTickerAction](https://holodata.github.io/masterchat/interfaces/AddSuperStickerTickerAction.html) | Ticker for super sticker |
| [addMembershipTickerAction](https://holodata.github.io/masterchat/interfaces/AddMembershipTickerAction.html) | Ticker for membership joining event |
| [addBannerAction](https://holodata.github.io/masterchat/interfaces/AddBannerAction.html) | Pin a message |
| [removeBannerAction](https://holodata.github.io/masterchat/interfaces/RemoveBannerAction.html) | Remove a pinned message |
| [addViewerEngagementMessageAction](https://holodata.github.io/masterchat/interfaces/AddViewerEngagementMessageAction.html) | Viewer engagement message |
| [showPanelAction](https://holodata.github.io/masterchat/interfaces/ShowPanelAction.html) | Show a panel (generic) |
| [showPollPanelAction](https://holodata.github.io/masterchat/interfaces/ShowPollPanelAction.html) | Show a poll panel |
| [updatePollAction](https://holodata.github.io/masterchat/interfaces/UpdatePollAction.html) | Update a poll panel content |
| [closePanelAction](https://holodata.github.io/masterchat/interfaces/ClosePanelAction.html) | Close a panel |
| [addPollResultAction](https://holodata.github.io/masterchat/interfaces/AddPollResultAction.html) | Poll result |
| [showTooltipAction](https://holodata.github.io/masterchat/interfaces/ShowTooltipAction.html) | Tooltip |
| [modeChangeAction](https://holodata.github.io/masterchat/interfaces/ModeChangeAction.html) | Notify mode changes (slow mode, members-only, subscribers-only) |
| [membershipGiftPurchaseAction](https://holodata.github.io/masterchat/interfaces/MembershipGiftPurchaseAction.html) | Membership gift purchase notification |
| [membershipGiftRedemptionAction](https://holodata.github.io/masterchat/interfaces/MembershipGiftRedemptionAction.html) | Membership gift redemption notification |
### Stream type
| type | metadata.isLive | Masterchat.init() | mode: undefined | mode: "live" | mode: "replay" |
| ----------------------------------------------- | --------------- | ---------------------------- | ---------------------- | ---------------------- | ---------------------- |
Expand Down
41 changes: 31 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,64 @@
[![npm: publish size](https://badgen.net/packagephobia/publish/masterchat)](https://npmjs.org/package/masterchat)
[![typedoc](https://badgen.net/badge/docs/typedoc/purple)](https://holodata.github.io/masterchat/)

> Node.js library for YouTube Live Chat
Battle-tested Node.js library for handling YouTube Live Chat.

## Install

```
npm i masterchat
npm install masterchat
```

See [MANUAL](https://github.com/holodata/masterchat/tree/master/MANUAL.md) for usage.
See [MANUAL](https://github.com/holodata/masterchat/tree/master/MANUAL.md) for further instructions.

## CLI

> See YouTube Live Chat through flexible filtering engine.
```
npm i -g masterchat-cli
```

See [masterchat-cli](https://github.com/holodata/masterchat-cli) for usage.
See [masterchat-cli](https://github.com/holodata/masterchat-cli) for the detailed usage.

## Desktop
## Desktop App

For a desktop app, see [☄️Komet](https://github.com/holodata/komet).
See [☄️Komet](https://github.com/holodata/komet) for further information.

## Community

### Contribute
### Contributing

- Use masterchat with `DEBUG=masterchat` and [report](https://github.com/holodata/masterchat/issues/new) logs prefixed with `[action required]`
- Use masterchat with `DEBUG=masterchat` and [report](https://github.com/holodata/masterchat/issues/new) logs that are prefixed with `[action required]`
- Squash [TODOs](https://github.com/holodata/masterchat/search?l=TypeScript&q=TODO)

See [Contribution Guide](./CONTRIBUTING.md) for more information.
Ask questions in `#masterchat` channel on [holodata Discord server](https://holodata.org/discord).

### Contributors ✨

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://github.com/uetchy"><img src="https://avatars.githubusercontent.com/u/431808?v=4?s=50" width="50px;" alt=""/><br /><sub><b>uetchy</b></sub></a><br /><a href="https://github.com/holodata/masterchat/commits?author=uetchy" title="Code">💻</a></td>
<td align="center"><a href="http://www.plurk.com/stu43005"><img src="https://avatars.githubusercontent.com/u/1288549?v=4?s=50" width="50px;" alt=""/><br /><sub><b>Shiaupiau</b></sub></a><br /><a href="https://github.com/holodata/masterchat/commits?author=stu43005" title="Code">💻</a></td>
<td align="center"><a href="https://jan-prochazka.eu/"><img src="https://avatars.githubusercontent.com/u/1665677?v=4?s=50" width="50px;" alt=""/><br /><sub><b>Jan Procházka</b></sub></a><br /><a href="https://github.com/holodata/masterchat/commits?author=jprochazk" title="Code">💻</a></td>
</tr>
</table>

<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome!

### Users

- [Holodex](https://holodex.net)
- [Luna's Translation](https://github.com/luna-translations-bot/luna-translations-bot)
- [Honeybee](https://github.com/holodata/honeybee)
- [ShipID](https://github.com/holodata/ShipID)
- [Komet](https://github.com/holodata/Komet)
2 changes: 1 addition & 1 deletion docs/assets/search.js

Large diffs are not rendered by default.

Loading

0 comments on commit 7f6cc85

Please sign in to comment.