Skip to content

Commit

Permalink
feat(stream): add twitch stream start notifications
Browse files Browse the repository at this point in the history
resolves #16
  • Loading branch information
Lutonite committed Jun 2, 2022
1 parent d18d46d commit 2443cb5
Showing 7 changed files with 1,637 additions and 108 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -3,3 +3,5 @@ REDIS_URL=redis://127.0.0.1:6379
FIREBASE_PROJECT_ID=
FIREBASE_CLIENT_EMAIL=
FIREBASE_PRIVATE_KEY=
TWITCH_CLIENT_ID=
TWITCH_CLIENT_SECRET=
8 changes: 7 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -54,7 +54,13 @@
"ts": "never",
"tsx": "never"
}
]
],
"import/order": ["error", {
"groups": [["index", "sibling", "parent", "internal", "external", "builtin", "object", "type"]],
"alphabetize": {
"order": "asc"
}
}]
},
"settings": {
"import/resolver": {
1,614 changes: 1,510 additions & 104 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -33,6 +33,10 @@
"@sapphire/result": "^1.1.1",
"@sapphire/stopwatch": "^1.4.1",
"@sapphire/utilities": "^3.6.2",
"@twurple/api": "^5.1.6",
"@twurple/auth": "^5.1.6",
"@twurple/eventsub": "^5.1.6",
"@twurple/eventsub-ngrok": "^5.1.6",
"bufferutil": "^4.0.6",
"bull": "^4.8.3",
"dayjs": "^1.11.2",
11 changes: 8 additions & 3 deletions src/bot.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// eslint-disable-next-line import/order
import 'dotenv/config';

import { subscribeTwitchEvents } from '#src/utils/twitch-events';
import { container, LogLevel, SapphireClient } from '@sapphire/framework';
import '@sapphire/plugin-editable-commands/register';
import '@sapphire/plugin-hmr/register';
@@ -10,10 +14,9 @@ import duration from 'dayjs/plugin/duration';
import localizedFormat from 'dayjs/plugin/localizedFormat';
import relativeTime from 'dayjs/plugin/relativeTime';
import utc from 'dayjs/plugin/utc';
import weekday from 'dayjs/plugin/weekday';
import weekOfYear from 'dayjs/plugin/weekOfYear';
import weekday from 'dayjs/plugin/weekday';
import { GatewayIntentBits } from 'discord-api-types/v10';
import 'dotenv/config';
import { cert, initializeApp } from 'firebase-admin/app';
import { type Firestore, getFirestore } from 'firebase-admin/firestore';
import IORedis, { type Redis } from 'ioredis';
@@ -39,7 +42,7 @@ initializeApp({

container.database = getFirestore();

container.redisClient = new IORedis(process.env.REDIS_URL);
container.redisClient = new IORedis(process.env.REDIS_URL ?? '');
const { host, port, password, db } = container.redisClient.options;

const client = new SapphireClient({
@@ -91,6 +94,8 @@ client
client.stores.get('scheduled-tasks').size,
'tasks',
);

return subscribeTwitchEvents(client).catch(console.error);
})
// eslint-disable-next-line no-console
.catch(console.error);
53 changes: 53 additions & 0 deletions src/listeners/stream-online.listener.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ApplyOptions } from '@sapphire/decorators';
import { Listener } from '@sapphire/framework';
import type { EventSubStreamOnlineEvent } from '@twurple/eventsub/lib/events/EventSubStreamOnlineEvent';
import type { Snowflake } from 'discord-api-types/globals';
import { MessageEmbed } from 'discord.js';

const GUILDS: { id: Snowflake; channel: Snowflake }[] = [
{ id: '887670429760749569', channel: '981888025095196702' },
];

@ApplyOptions<Listener.Options>({
event: 'streamOnline',
})
export default class StreamOnlineListener extends Listener {
async run(event: EventSubStreamOnlineEvent): Promise<unknown> {
const { client } = this.container;

const stream = await event.getStream();
const game = await stream?.getGame();

const streamUrl = `https://www.twitch.tv/${event.broadcasterName}`;

const channels = await Promise.all(
GUILDS.map((sfs) => client.channels.cache.get(sfs.channel)),
);

const embed = new MessageEmbed()
.setColor('#9146FF')
.setTitle(
`:tv: ${event.broadcasterDisplayName} - Stream en ligne !`,
)
.setURL(streamUrl)
.addField('Titre', stream?.title ?? 'Aucun titre');

if (game) {
embed.addField('Jeu', game.name);
embed.setThumbnail(game.boxArtUrl);
}

embed.setImage(stream?.thumbnailUrl);

return channels.map((channel) => {
if (channel && channel.isText()) {
return channel.send({
content: '<@&981902175850602566>',
embeds: [embed],
});
}

return Promise.resolve();
});
}
}
53 changes: 53 additions & 0 deletions src/utils/twitch-events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { SapphireClient } from '@sapphire/framework';
import { ApiClient } from '@twurple/api';
import { ClientCredentialsAuthProvider } from '@twurple/auth';
import { EventSubListener, ReverseProxyAdapter } from '@twurple/eventsub';
import type { EventSubStreamOnlineEvent } from '@twurple/eventsub/lib/events/EventSubStreamOnlineEvent';
import { randomBytes } from 'crypto';

const TWITCH_USER_IDS = ['756569499'];
const SUBSCRIPTION_SECRET: string = randomBytes(48).toString('hex');

export const twitchAuthProvider = new ClientCredentialsAuthProvider(
process.env.TWITCH_CLIENT_ID ?? '',
process.env.TWITCH_CLIENT_SECRET ?? '',
);

export const twitchApiClient = new ApiClient({
authProvider: twitchAuthProvider,
});

export const twitchEventSubListener = new EventSubListener({
apiClient: twitchApiClient,
adapter: new ReverseProxyAdapter({
hostName: 'ddc.cc4.ch',
port: 1042,
}),
secret: SUBSCRIPTION_SECRET,
});

export const subscribeTwitchEvents = async (client: SapphireClient) => {
await twitchEventSubListener.listen().catch(console.error);
const subscriptions = await Promise.all(
TWITCH_USER_IDS.map(async (userId) =>
twitchEventSubListener.subscribeToStreamOnlineEvents(
userId,
(e) => {
client.emit('streamOnline', e);
},
),
),
);

await Promise.all(
subscriptions.map(async (sub, i) =>
client.logger.info(`[${i}] => ${await sub.getCliTestCommand()}`),
),
);
};

declare module 'discord.js' {
interface ClientEvents {
streamOnline: [event: EventSubStreamOnlineEvent];
}
}

0 comments on commit 2443cb5

Please sign in to comment.