"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var youtube_exports = {}; __export(youtube_exports, { GroupWatch: () => GroupWatch, Twitch: () => Twitch, TwitchStream: () => TwitchStream, YouTube: () => YouTube, YoutubeInterface: () => YoutubeInterface, commands: () => commands, destroy: () => destroy, pages: () => pages, searchDataCache: () => searchDataCache, videoDataCache: () => videoDataCache }); module.exports = __toCommonJS(youtube_exports); var import_lib = require("../../lib"); const ROOT = "https://www.googleapis.com/youtube/v3/"; const STORAGE_PATH = "config/chat-plugins/youtube.json"; const GROUPWATCH_ROOMS = ["youtube", "pokemongames", "videogames", "smashbros", "pokemongo", "hindi"]; const videoDataCache = Chat.oldPlugins.youtube?.videoDataCache || /* @__PURE__ */ new Map(); const searchDataCache = Chat.oldPlugins.youtube?.searchDataCache || /* @__PURE__ */ new Map(); function loadData() { const raw = JSON.parse((0, import_lib.FS)(STORAGE_PATH).readIfExistsSync() || "{}"); if (!(raw.channels && raw.categories)) { const data = {}; data.channels = raw; data.categories = []; (0, import_lib.FS)(STORAGE_PATH).writeUpdate(() => JSON.stringify(data)); return data; } return raw; } const channelData = loadData(); class YoutubeInterface { constructor(data) { this.linkRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)(\/|$)/i; this.data = data ? data : { categories: [], channels: {} }; this.interval = null; this.intervalTime = 0; if (data?.intervalTime) { this.runInterval(`${data.intervalTime}`); } } async getChannelData(link, username) { if (!Config.youtubeKey) { throw new Chat.ErrorMessage(`This server does not support YouTube commands. If you're the owner, you can enable them by setting up Config.youtubekey.`); } const id = this.getId(link); const raw = await (0, import_lib.Net)(`${ROOT}channels`).get({ query: { part: "snippet,statistics", id, key: Config.youtubeKey } }); const res = JSON.parse(raw); if (!res?.items || res.items.length < 1) { throw new Chat.ErrorMessage(`Channel not found.`); } const data = res.items[0]; const cache = { name: data.snippet.title, description: data.snippet.description, url: data.snippet.customUrl, icon: data.snippet.thumbnails.medium.url, videos: Number(data.statistics.videoCount), subs: Number(data.statistics.subscriberCount), views: Number(data.statistics.viewCount), username }; this.data.channels[id] = { ...cache }; this.save(); return cache; } async generateChannelDisplay(link) { const id = this.getId(link); const { name, description, icon, videos, subs, views, username } = await this.get(id); let buf = `
`; buf += `
`; buf += `
`; buf += ``; buf += `

`; buf += `${name}`; buf += `

`; buf += `

`; buf += `${videos} videos | ${subs} subscribers | ${views} video views

`; buf += `

`; buf += `${description.slice(0, 400).replace(/\n/g, " ")}${description.length > 400 ? "(...)" : ""}

`; if (username) { buf += `

PS username: ${username}

`; } else { buf += ""; } return buf; } randChannel(cat) { let channels = Object.keys(this.data.channels); if (channels.length < 1) { throw new Chat.ErrorMessage(`There are no channels in the database.`); } if (cat) { cat = toID(cat); const categoryIDs = this.data.categories.map(toID); if (!categoryIDs.includes(cat)) { throw new Chat.ErrorMessage(`Invalid category.`); } channels = channels.filter((id2) => { const channel = this.data.channels[id2]; return channel.category && toID(channel.category) === cat; }); } const id = import_lib.Utils.shuffle(channels)[0]; return this.generateChannelDisplay(id); } get(id, username) { if (!(id in this.data.channels)) return this.getChannelData(id, username); return Promise.resolve({ ...this.data.channels[id] }); } async getVideoData(id) { const cached = videoDataCache.get(id); if (cached) return cached; let raw; try { raw = await (0, import_lib.Net)(`${ROOT}videos`).get({ query: { part: "snippet,statistics", id, key: Config.youtubeKey } }); } catch (e) { throw new Chat.ErrorMessage(`Failed to retrieve video data: ${e.message}.`); } const res = JSON.parse(raw); if (!res?.items || res.items.length < 1) return null; const video = res.items[0]; const data = { title: video.snippet.title, id, date: new Date(video.snippet.publishedAt).toString(), description: video.snippet.description, channelTitle: video.snippet.channelTitle, channelUrl: video.snippet.channelId, views: video.statistics.viewCount, thumbnail: video.snippet.thumbnails.default.url, likes: video.statistics.likeCount, dislikes: video.statistics.dislikeCount }; videoDataCache.set(id, data); return data; } channelSearch(search) { let channel; if (this.data.channels[search]) { channel = search; } else { for (const id of Object.keys(this.data.channels)) { const name = toID(this.data.channels[id].name); const username = this.data.channels[id].username; if (name === toID(search) || username && toID(username) === toID(search)) { channel = id; break; } } } return channel; } getId(link) { let id = ""; if (!link) throw new Chat.ErrorMessage("You must provide a YouTube link."); if (this.data.channels[link]) return link; if (!link.includes("channel/")) { if (link.includes("youtube")) { id = link.split("v=")[1] || ""; } else if (link.includes("youtu.be")) { id = link.split("/")[3] || ""; } else { throw new Chat.ErrorMessage("Invalid YouTube channel link."); } } else { id = link.split("channel/")[1] || ""; } if (id.includes("&")) id = id.split("&")[0]; if (id.includes("?")) id = id.split("?")[0]; return id; } async generateVideoDisplay(link, fullInfo = false) { if (!Config.youtubeKey) { throw new Chat.ErrorMessage(`This server does not support YouTube commands. If you're the owner, you can enable them by setting up Config.youtubekey.`); } const id = this.getId(link); const info = await this.getVideoData(id); if (!info) throw new Chat.ErrorMessage(`Video not found.`); if (!fullInfo) { let buf2 = `${info.title} `; buf2 += `(${info.channelTitle})
`; buf2 += ``; return buf2; } let buf = ``; buf += ``; return buf; } save() { return (0, import_lib.FS)(STORAGE_PATH).writeUpdate(() => JSON.stringify(this.data)); } async searchVideo(name, limit) { const cached = searchDataCache.get(toID(name)); if (cached) { return cached.slice(0, limit); } const raw = await (0, import_lib.Net)(`${ROOT}search`).get({ query: { part: "snippet", q: name, key: Config.youtubeKey, order: "relevance" } }); const result = JSON.parse(raw); const resultArray = result.items?.map((item) => item?.id?.videoId).filter(Boolean); searchDataCache.set(toID(name), resultArray); return resultArray.slice(0, limit); } async searchChannel(name, limit = 10) { const raw = await (0, import_lib.Net)(`${ROOT}search`).get({ query: { part: "snippet", q: name, type: "channel", key: Config.youtubeKey, order: "relevance", maxResults: limit } }); const result = JSON.parse(raw); return result?.items.map((item) => item?.snippet?.channelId); } runInterval(time) { let interval = Number(time); if (interval < 10) throw new Chat.ErrorMessage(`${interval} is too low - set it above 10 minutes.`); this.intervalTime = interval; this.data.intervalTime = interval; interval = interval * 60 * 1e3; if (this.interval) clearInterval(this.interval); this.interval = setInterval(() => { void (async () => { const room = Rooms.get("youtube"); if (!room) return; const res = await YouTube.randChannel(); room.add(`|html|${res}`).update(); })(); }, interval); return this.interval; } async createGroupWatch(url, baseRoom, title) { const id = this.getId(url); const videoInfo = await this.getVideoData(id); if (!videoInfo) throw new Chat.ErrorMessage(`Video not found.`); const num = baseRoom.nextGameNumber(); baseRoom.saveSettings(); const gameRoom = Rooms.createGameRoom(`video-watch-${num}`, import_lib.Utils.html`[Group Watch] ${title}`, { isPrivate: "hidden" }); const game = new GroupWatch(gameRoom, url, videoInfo); gameRoom.game = game; gameRoom.setParent(baseRoom); return gameRoom; } } const Twitch = new class { constructor() { this.linkRegex = /(https?:\/\/)?twitch.tv\/([A-Za-z0-9]+)/i; } async getChannel(channel) { channel = toID(channel); let res; try { res = await (0, import_lib.Net)(`https://api.twitch.tv/kraken/search/channels`).get({ headers: { "Client-Id": Config.twitchKey, "Content-Type": "application/json", "Accept": "application/vnd.twitchtv.v5+json" }, query: { query: channel } }); } catch (e) { throw new Chat.ErrorMessage(`Error retrieving twitch channel: ${e.message}`); } const data = JSON.parse(res); import_lib.Utils.sortBy(data.channels, (c) => -c.followers); return data?.channels?.[0]; } visualizeChannel(info) { let buf = `
`; buf += `
`; buf += ``; buf += `

`; buf += `${info.title}`; buf += `

`; buf += `

`; buf += `${info.likes} likes | ${info.dislikes} dislikes | ${info.views} video views

`; buf += `Published on ${info.date} | ID: ${id}
Uploaded by: ${info.channelTitle}

`; buf += `
Video Description

`; buf += `

`; buf += `${info.description.slice(0, 400).replace(/\n/g, " ")}${info.description.length > 400 ? "(...)" : ""}

`; buf += `
`; buf += `
`; buf += ``; buf += `

`; buf += `${info.display_name}`; buf += `

`; buf += `

`; const created = new Date(info.created_at); buf += `${info.followers} subscribers | ${info.views} stream views | created ${Chat.toTimestamp(created).split(" ")[0]}

`; buf += `

Last seen playing ${info.game} (Status: ${info.status})

`; buf += `

`; buf += `${info.description.slice(0, 400).replace(/\n/g, " ")}${info.description.length > 400 ? "..." : ""}

`; buf += "
"; return buf; } }(); class GroupWatch extends Rooms.SimpleRoomGame { constructor(room, url, videoInfo) { super(room); this.started = null; this.url = url; this.info = videoInfo; this.controls(`

Waiting to start the video...

`); } onJoin(user) { const hints = this.hints(); for (const hint of hints) { user.sendTo(this.room.roomid, `|html|${hint}`); } } start() { if (this.started) throw new Chat.ErrorMessage(`We've already started.`); this.controls(this.getStatsDisplay()); this.field(this.getVideoDisplay()); this.started = Date.now(); this.add(`|html|

Group Watch!

`); } hints() { const hints = [ `To watch, all you need to do is click play on the video once staff have started it!`, `We are currently watching: ${this.info.title}` ]; if (this.started) { const diff = Date.now() - this.started; hints.push(`Video is currently at ${Chat.toDurationString(diff)} (${diff / 1e3} seconds)`); } return hints; } getStatsDisplay() { let controlsHTML = `

${this.info.title}

`; controlsHTML += `
Channel: `; controlsHTML += `${this.info.channelTitle}
`; controlsHTML += `Likes: ${this.info.likes} | Dislikes: ${this.info.dislikes}
`; controlsHTML += `Uploaded: ${Chat.toTimestamp(new Date(this.info.date))}
`; controlsHTML += `
Description${this.info.description.replace(/\n/ig, "
")}
`; controlsHTML += `
`; return controlsHTML; } getVideoDisplay() { let buf = `

`; buf += `

${this.info.title}
`; const id = YouTube.getId(this.url); const url = `https://youtube.com/watch?v=${id}`; buf += ``; buf += `
`.repeat(4); buf += `

`; return buf; } controls(html) { this.add(`|controlshtml|
${html}
`); } field(html) { this.add(`|fieldhtml|${html}`); } add(buf) { this.room.add(buf).update(); } destroy() { this.controls(`The group watch has ended.`); let endBuf = `
`; endBuf += this.getStatsDisplay(); endBuf += `
Thanks for watching!
`; this.field(endBuf); this.room = null; } } class TwitchStream extends Rooms.SimpleRoomGame { constructor(room, data) { super(room); this.started = false; this.data = data; } static async createStreamWatch(room, channel) { if ([...Rooms.rooms.values()].some( (r) => r.roomid.startsWith(`twitch-`) && r.parent?.roomid === room?.roomid )) { throw new Chat.ErrorMessage(`Twitch watch already in progress for this room.`); } const data = await Twitch.getChannel(channel); if (!data) throw new Chat.ErrorMessage(`Channel not found`); const watchRoom = Rooms.createGameRoom( `twitch-stream-watch-${room.nextGameNumber()}`, import_lib.Utils.html`[Twitch Watch] ${data.display_name}`, { isPrivate: "hidden" } ); room.saveSettings(); watchRoom.setParent(room); const stream = new TwitchStream(watchRoom, data); watchRoom.game = stream; return watchRoom; } field(buf) { this.add(`|fieldhtml|${buf}`); } controls(buf) { this.add(`|controlshtml|${buf}`); } add(data) { return this.room.add(data).update(); } onJoin(user) { if (!user.named) return; this.controls(this.getControlsDisplay()); } onLeave(user) { if (!user.named) return; this.controls(this.getControlsDisplay()); } start() { if (this.started) { throw new Chat.ErrorMessage(`Stream already started`); } this.controls(this.getControlsDisplay()); this.field(this.getStreamDisplay()); this.add(`|html|

The stream watch has started!

`); this.started = true; } end() { this.field(""); this.controls(`

Stream watch ended

`); this.room.parent?.add(`|uhtmlchange|ts-${this.room.roomid}|`); this.add(`|expire|Stream ended`); this.room.destroy(); } getControlsDisplay() { let buf = `

`; buf += `Watching ${this.data.display_name}
`; buf += `${Chat.count(Object.keys(this.room.users).length, "users")} watching
`; buf += `Playing: ${this.data.game}`; return buf; } getStreamDisplay() { let buf = `

`; buf += ``; return buf; } } const YouTube = new YoutubeInterface(channelData); function destroy() { if (YouTube.interval) clearInterval(YouTube.interval); } const commands = { async randchannel(target, room, user) { room = this.requireRoom("youtube"); if (Object.keys(YouTube.data.channels).length < 1) return this.errorReply(`No channels in the database.`); target = toID(target); this.runBroadcast(); const data = await YouTube.randChannel(target); return this.sendReply(`|html|${data}`); }, randchannelhelp: [`/randchannel - View data of a random channel from the YouTube database.`], yt: "youtube", youtube: { async addchannel(target, room, user) { room = this.requireRoom("youtube"); this.checkCan("mute", null, room); const [id, name] = target.split(",").map((t) => t.trim()); if (!id) return this.errorReply("Specify a channel ID."); await YouTube.getChannelData(id, name); this.modlog("ADDCHANNEL", null, `${id} ${name ? `username: ${name}` : ""}`); return this.privateModAction( `${user.name} added channel with id ${id} ${name ? `and username (${name}) ` : ""} to the random channel pool.` ); }, addchannelhelp: [`/addchannel - Add channel data to the YouTube database. Requires: % @ #`], removechannel(target, room, user) { room = this.requireRoom("youtube"); this.checkCan("mute", null, room); const id = YouTube.channelSearch(target); if (!id) return this.errorReply(`Channel with ID or name ${target} not found.`); delete YouTube.data.channels[id]; YouTube.save(); this.privateModAction(`${user.name} deleted channel with ID or name ${target}.`); return this.modlog(`REMOVECHANNEL`, null, id); }, removechannelhelp: [`/youtube removechannel - Delete channel data from the YouTube database. Requires: % @ #`], async channel(target, room, user) { room = this.requireRoom("youtube"); const channel = YouTube.channelSearch(target); if (!channel) return this.errorReply(`No channels with ID or name ${target} found.`); const data = await YouTube.generateChannelDisplay(channel); this.runBroadcast(); return this.sendReply(`|html|${data}`); }, channelhelp: [ "/youtube channel - View the data of a specified channel. Can be either channel ID or channel name." ], async video(target, room, user) { room = this.requireRoom("youtube"); this.checkCan("mute", null, room); const buffer = await YouTube.generateVideoDisplay(target, true); this.runBroadcast(); this.sendReplyBox(buffer); }, channels(target, room, user) { target = toID(target); return this.parse(`/j view-channels${target ? `-${target}` : ""}`); }, help(target, room, user) { return this.parse("/help youtube"); }, categories() { return this.parse(`/j view-channels-categories`); }, update(target, room, user) { room = this.requireRoom("youtube"); this.checkCan("mute", null, room); const [channel, name] = target.split(","); const id = YouTube.channelSearch(channel); if (!id) return this.errorReply(`Channel ${channel} is not in the database.`); YouTube.data.channels[id].username = name; this.modlog(`UPDATECHANNEL`, null, name); this.privateModAction(`${user.name} updated channel ${id}'s username to ${name}.`); YouTube.save(); }, interval: "repeat", repeat(target, room, user) { room = this.requireRoom("youtube"); this.checkCan("declare", null, room); if (!target) { if (!YouTube.interval) return this.errorReply(`The YouTube plugin is not currently running an interval.`); return this.sendReply(`Interval is currently set to ${Chat.toDurationString(YouTube.intervalTime * 60 * 1e3)}.`); } if (this.meansNo(target)) { if (!YouTube.interval) return this.errorReply(`The interval is not currently running`); clearInterval(YouTube.interval); delete YouTube.data.intervalTime; YouTube.save(); this.privateModAction(`${user.name} turned off the YouTube interval`); return this.modlog(`YOUTUBE INTERVAL`, null, "OFF"); } if (Object.keys(channelData).length < 1) return this.errorReply(`No channels in the database.`); if (isNaN(parseInt(target))) return this.errorReply(`Specify a number (in minutes) for the interval.`); YouTube.runInterval(target); YouTube.save(); this.privateModAction(`${user.name} set a randchannel interval to ${target} minutes`); return this.modlog(`CHANNELINTERVAL`, null, `${target} minutes`); }, addcategory(target, room, user) { room = this.requireRoom("youtube"); this.checkCan("mute", null, room); const categoryID = toID(target); if (!categoryID) return this.parse(`/help youtube`); if (YouTube.data.categories.map(toID).includes(categoryID)) { return this.errorReply(`This category is already added. To change it, remove it and re-add it.`); } YouTube.data.categories.push(target); this.modlog(`YOUTUBE ADDCATEGORY`, null, target); this.privateModAction(`${user.name} added category '${target}' to the categories list.`); YouTube.save(); }, removecategory(target, room, user) { room = this.requireRoom("youtube"); this.checkCan("mute", null, room); const categoryID = toID(target); if (!categoryID) return this.parse(`/help youtube`); const index = YouTube.data.categories.indexOf(target); if (index < 0) { return this.errorReply(`${target} is not a valid category.`); } for (const id in YouTube.data.channels) { const channel = YouTube.data.channels[id]; if (channel.category === target) delete YouTube.data.channels[id].category; } YouTube.save(); this.privateModAction(`${user.name} removed the category '${target}' from the category list.`); this.modlog(`YOUTUBE REMOVECATEGORY`, null, target); }, setcategory(target, room, user) { room = this.requireRoom("youtube"); this.checkCan("mute", null, room); target = target.trim(); const [category, id] = import_lib.Utils.splitFirst(target, ",").map((item) => item.trim()); if (!target || !category || !id) { return this.parse("/help youtube"); } if (!YouTube.data.categories.includes(category)) { return this.errorReply(`Invalid category.`); } const name = YouTube.channelSearch(id); if (!name) return this.errorReply(`Invalid channel.`); const channel = YouTube.data.channels[name]; YouTube.data.channels[name].category = category; YouTube.save(); this.modlog(`YOUTUBE SETCATEGORY`, null, `${id}: to category ${category}`); this.privateModAction(`${user.name} set the channel ${channel.name}'s category to '${category}'.`); }, decategorize(target, room, user) { room = this.requireRoom("youtube"); this.checkCan("mute", null, room); target = target.trim(); if (!target) { return this.parse("/help youtube"); } const name = YouTube.channelSearch(target); if (!name) return this.errorReply(`Invalid channel.`); const channel = YouTube.data.channels[name]; const category = channel.category; if (!category) return this.errorReply(`That channel does not have a category.`); delete channel.category; YouTube.save(); this.modlog(`YOUTUBE DECATEGORIZE`, null, target); this.privateModAction(`${user.name} removed the channel ${channel.name} from the category ${category}.`); }, async groupwatch(target, room, user) { room = this.requireRoom(); if (!GROUPWATCH_ROOMS.includes(room.roomid)) { return this.errorReply(`This room is not allowed to use the groupwatch function.`); } this.checkCan("mute", null, room); const [url, title] = import_lib.Utils.splitFirst(target, ",").map((p) => p.trim()); if (!url || !title) return this.errorReply(`You must specify a video to watch and a title for the group watch.`); const gameRoom = await YouTube.createGroupWatch(url, room, title); this.modlog(`YOUTUBE GROUPWATCH`, null, `${url} (${title})`); room.add( `|uhtml|${gameRoom.roomid}|` ); room.send(`|tempnotify|youtube|New groupwatch - ${title}!`); this.update(); user.joinRoom(gameRoom); }, endwatch(target, room, user) { room = this.requireRoom(); this.checkCan("mute", null, room); this.requireGame(GroupWatch); room.parent.modlog({ action: `GROUPWATCH END`, loggedBy: user.id }); room.parent.add(`|uhtmlchange|${room.roomid}|`).update(); room.destroy(); }, startwatch: "beginwatch", beginwatch(target, room, user) { room = this.requireRoom(); this.checkCan("mute", null, room); const game = this.requireGame(GroupWatch); game.start(); }, groupwatches() { let buf = `Ongoing groupwatches:
`; for (const curRoom of Rooms.rooms.values()) { if (!curRoom.getGame(GroupWatch)) continue; buf += ``; } this.runBroadcast(); this.sendReplyBox(buf); } }, youtubehelp: [ `YouTube commands:`, `/randchannel [optional category]- View data of a random channel from the YouTube database. If a category is given, the random channel will be in the given category.`, `/youtube addchannel [channel] - Add channel data to the YouTube database. Requires: % @ #`, `/youtube removechannel [channel]- Delete channel data from the YouTube database. Requires: % @ #`, `/youtube channel [channel] - View the data of a specified channel. Can be either channel ID or channel name.`, `/youtube video [video] - View data of a specified video. Can be either channel ID or channel name.`, `/youtube update [channel], [name] - sets a channel's PS username to [name]. Requires: % @ #`, `/youtube repeat [time] - Sets an interval for [time] minutes, showing a random channel each time. Requires: # &`, `/youtube addcategory [name] - Adds the [category] to the channel category list. Requires: @ # &`, `/youtube removecategory [name] - Removes the [category] from the channel category list. Requires: @ # &`, `/youtube setcategory [category], [channel name] - Sets the category for [channel] to [category]. Requires: @ # &`, `/youtube decategorize [channel name] - Removes the category for the [channel], if there is one. Requires: @ # &`, `/youtube categores - View all channels sorted by category.`, `/youtube groupwatch [link], [title] - Creates a group watch of the [url] with the given [title]. Requires % @ & #`, `/youtube startwatch - Starts the group watch in the current room, if there is one. Requires % @ & #`, `/youtube stopwatch - Ends the current group watch, if there is one in the current room. Requires % @ & #` ], twitch: { async channel(target, room, user) { room = this.requireRoom("youtube"); if (!Config.twitchKey) return this.errorReply(`Twitch is not configured`); const data = await Twitch.getChannel(target); if (!data) return this.errorReply(`Channel not found`); const html = Twitch.visualizeChannel(data); this.runBroadcast(); return this.sendReplyBox(html); }, async watch(target, room, user) { room = this.requireRoom(); if (!GROUPWATCH_ROOMS.includes(room.roomid)) { throw new Chat.ErrorMessage(`You cannot use this command in this room.`); } this.checkCan("mute", null, room); if (!toID(target)) { return this.errorReply(`Invalid channel`); } const gameRoom = await TwitchStream.createStreamWatch(room, target); user.joinRoom(gameRoom); room.add( `|uhtml|ts-${gameRoom.roomid}|` ).update(); }, start(target, room) { room = this.requireRoom(); const stream = this.requireGame(TwitchStream); stream.start(); }, stop(target, room, user) { room = this.requireRoom(); const stream = this.requireGame(TwitchStream); this.checkCan("mute", null, room); stream.end(); } } }; const pages = { async channels(args, user) { const [type] = args; if (!Config.youtubeKey) return `

Youtube is not configured.

`; const titles = { all: "All channels", categories: "by category" }; const title = titles[type] || "Usernames only"; this.title = `[Channels] ${title}`; let buffer = `

Channels in the YouTube database: (${title})`; buffer += ` `; buffer += `


`; switch (toID(type)) { case "categories": if (!YouTube.data.categories.length) { return this.errorReply(`There are currently no categories in the Youtube channel database.`); } const sorted = {}; const channels = YouTube.data.channels; for (const [id, channel] of Object.entries(channels)) { const category = channel.category || "No category"; if (!sorted[category]) { sorted[category] = []; } sorted[category].push(id); } for (const cat in sorted) { buffer += `

${cat}:

`; for (const id of sorted[cat]) { const channel = channels[id]; buffer += `
${channel.name}`; buffer += await YouTube.generateChannelDisplay(id); buffer += `

`; } } break; default: for (const id of import_lib.Utils.shuffle(Object.keys(YouTube.data.channels))) { const { name, username } = await YouTube.get(id); if (toID(type) !== "all" && !username) continue; buffer += `
${name}`; buffer += ` (Channel ID: ${id})`; if (username) buffer += ` (PS name: ${username})`; buffer += ``; buffer += await YouTube.generateChannelDisplay(id); buffer += `

`; } break; } buffer += `
`; return buffer; } }; //# sourceMappingURL=youtube.js.map