Skip to content

Commit

Permalink
Use dotenv instead of config.json.
Browse files Browse the repository at this point in the history
  • Loading branch information
ysdragon committed Jun 10, 2024
1 parent df633a2 commit 8761975
Show file tree
Hide file tree
Showing 10 changed files with 310 additions and 270 deletions.
25 changes: 25 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Selfbot options
TOKEN = "" # Your Discord self-bot token
PREFIX = "$" # The prefix used to trigger your self-bot commands
GUILD_ID = "" # The ID of the Discord server your self-bot will be running on
COMMAND_CHANNEL_ID = "" # The ID of the Discord channel where your self-bot will respond to commands
VIDEO_CHANNEL_ID = "" # The ID of the Discord voice/video channel where your self-bot will stream videos
ADMIN_IDS = [""] # A list of Discord user IDs that are considered administrators for your self-bot (not implemented yet)
VIDEOS_FOLDER = "./videos" # The local path where you store video files
PREVIEW_CACHE = "/tmp/preview-cache" # The local path where your self-bot will cache video preview thumbnails

# Stream options
STREAM_WIDTH = "1280" # The width of the video stream in pixels
STREAM_HEIGHT = "720" # The height of the video stream in pixels
STREAM_FPS = "30" # The frames per second (FPS) of the video stream
STREAM_BITRATE_KBPS = "1000" # The bitrate of the video stream in kilobits per second (Kbps)
STREAM_MAX_BITRATE_KBPS = "2500" # The maximum bitrate of the video stream in kilobits per second (Kbps)
STREAM_HARDWARE_ACCELERATION = "false" # Whether to use hardware acceleration for video decoding, set to "true" to enable, "false" to disable
STREAM_VIDEO_CODEC = "H264" # The video codec to use for the stream, can be "H264" or "H265" or "VP8"

# Videos server options
SERVER_ENABLED = "false" # Whether to enable the built-in video server
SERVER_USERNAME = "admin" # The username for the video server's admin interface
SERVER_PASSWORD = "admin" # The password for the video server's admin interface
SERVER_PORT = "8080" # The port number the video server will listen on

2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
LICENSE
node_modules/
dist/
config.json
.env
bun.lockb
videos/
3 changes: 0 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ RUN pnpm install
# Copy the rest of the application code
COPY . .

# Rename config.json.example to config.json
RUN mv config.json.example config.json

# Build the application
RUN pnpm run build

Expand Down
57 changes: 28 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ bun install
bun run build
```

4. Rename [config.json.example](https://github.com/ysdragon/StreamBot/blob/main/config.json.example) to config.json
4. Rename [.env.example](https://github.com/ysdragon/StreamBot/blob/main/.env.example) to .env

## Usage
Start the built artifacts:
Expand All @@ -63,34 +63,33 @@ help - Show help message.

## 🛠️ Configuration

Configuration is done via `config.json`:

```json
{
"token": "<user bot token>",
"prefix": "<here you can set the bot prefix>",
"guildId": "<guild id (server id)>",
"commandChannel": "<command channel id>",
"videoChannel": "<voice channel id>",
"adminIds": ["<admin id>"],
"videosFolder": "<videos folder path>",
"previewCache": "<here you can set the preview thumbnails cache folder>",
"streamOpts": {
"width": 1920,
"height": 1080,
"fps": 30,
"bitrateKbps": 2500,
"maxBitrateKbps": 2500,
"hardware_acc": false,
"videoCodec": "<Stream/video codec can be set to either (H264), (H265) or (VP8)>"
},
"server": {
"enabled": false,
"username": "<here you can set the username>",
"password": "<here you can set the password>",
"port": 8080
}
}
Configuration is done via `.env`:

```bash
# Selfbot options
TOKEN = "" # Your Discord self-bot token
PREFIX = "$" # The prefix used to trigger your self-bot commands
GUILD_ID = "" # The ID of the Discord server your self-bot will be running on
COMMAND_CHANNEL_ID = "" # The ID of the Discord channel where your self-bot will respond to commands
VIDEO_CHANNEL_ID = "" # The ID of the Discord voice/video channel where your self-bot will stream videos
ADMIN_IDS = [""] # A list of Discord user IDs that are considered administrators for your self-bot (not implemented yet)
VIDEOS_FOLDER = "./videos" # The local path where you store video files
PREVIEW_CACHE = "/tmp/preview-cache" # The local path where your self-bot will cache video preview thumbnails

# Stream options
STREAM_WIDTH = "1280" # The width of the video stream in pixels
STREAM_HEIGHT = "720" # The height of the video stream in pixels
STREAM_FPS = "30" # The frames per second (FPS) of the video stream
STREAM_BITRATE_KBPS = "1000" # The bitrate of the video stream in kilobits per second (Kbps)
STREAM_MAX_BITRATE_KBPS = "2500" # The maximum bitrate of the video stream in kilobits per second (Kbps)
STREAM_HARDWARE_ACCELERATION = "false" # Whether to use hardware acceleration for video decoding, set to "true" to enable, "false" to disable
STREAM_VIDEO_CODEC = "H264" # The video codec to use for the stream, can be "H264" or "H265" or "VP8"

# Videos server options
SERVER_ENABLED = "false" # Whether to enable the built-in video server
SERVER_USERNAME = "admin" # The username for the video server's admin interface
SERVER_PASSWORD = "admin" # The password for the video server's admin interface
SERVER_PORT = "8080" # The port number the video server will listen on
```

## Get Token ?
Expand Down
25 changes: 0 additions & 25 deletions config.json.example

This file was deleted.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@
"license": "MIT",
"dependencies": {
"@dank074/discord-video-stream": "3.2.0",
"@distube/ytdl-core": "^4.13.3",
"@distube/ytdl-core": "^4.13.4",
"axios": "^1.7.2",
"discord.js-selfbot-v13": "^3.1.4",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"fluent-ffmpeg": "^2.1.3",
"multer": "^1.4.5-lts.1",
"play-dl": "^1.9.7",
"random-useragent": "^0.5.0",
"tslib": "^2.6.2"
"tslib": "^2.6.3"
},
"devDependencies": {
"typescript": "^5.4.5"
Expand Down
41 changes: 41 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import dotenv from "dotenv"

dotenv.config()

export default {
// Selfbot options
token: process.env.TOKEN,
prefix: process.env.PREFIX,
guildId: process.env.GUILD_ID ? process.env.GUILD_ID : '',
cmdChannelId: process.env.COMMAND_CHANNEL_ID ? process.env.COMMAND_CHANNEL_ID : '',
videoChannelId: process.env.VIDEO_CHANNEL_ID ? process.env.VIDEO_CHANNEL_ID : '',
previewCache: process.env.PREVIEW_CACHE ? process.env.PREVIEW_CACHE : '/tmp/preview-cache',

// Stream options
width: process.env.STREAM_WIDTH ? parseInt(process.env.STREAM_WIDTH) : 1280,
height: process.env.STREAM_HEIGHT ? parseInt(process.env.STREAM_HEIGHT) : 720,
fps: process.env.STREAM_FPS ? parseInt(process.env.STREAM_FPS) : 30,
bitrateKbps: process.env.STREAM_BITRATE_KBPS ? parseInt(process.env.STREAM_BITRATE_KBPS) : 1000,
maxBitrateKbps: process.env.STREAM_MAX_BITRATE_KBPS ? parseInt(process.env.STREAM_MAX_BITRATE_KBPS) : 2500,
hardwareAcceleratedDecoding: process.env.STREAM_HARDWARE_ACCELERATION ? parseBoolean(process.env.STREAM_HARDWARE_ACCELERATION) : false,
videoCodec: process.env.STREAM_VIDEO_CODEC === 'VP8' ? 'VP8' : 'H264',

// Videos server options
server_enabled: process.env.SERVER_ENABLED ? parseBoolean(process.env.SERVER_ENABLED) : false,
server_username: process.env.SERVER_USERNAME ? process.env.SERVER_USERNAME : 'admin',
server_password: process.env.SERVER_PASSWORD ? process.env.SERVER_PASSWORD : 'admin',
server_port: parseInt(process.env.SERVER_PORT ? process.env.SERVER_PORT : '8080'),
videosFolder: process.env.VIDEOS_FOLDER ? process.env.VIDEOS_FOLDER : './videos'
}

function parseBoolean(value: string | undefined): boolean {
if (typeof value === "string") {
value = value.trim().toLowerCase();
}
switch (value) {
case "true":
return true;
default:
return false;
}
}
79 changes: 43 additions & 36 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Client, TextChannel, CustomStatus, ActivityOptions, MessageAttachment } from "discord.js-selfbot-v13";
import { command, streamLivestreamVideo, MediaUdp, StreamOptions, Streamer } from "@dank074/discord-video-stream";
import config from "../config.json";
import config from "./config"
import fs from 'fs';
import path from 'path';
import ytdl from '@distube/ytdl-core';
Expand All @@ -9,28 +9,25 @@ import yts from 'play-dl';
const streamer = new Streamer(new Client());

const streamOpts: StreamOptions = {
height: config.streamOpts.height,
fps: config.streamOpts.fps,
bitrateKbps: config.streamOpts.bitrateKbps,
maxBitrateKbps: config.streamOpts.maxBitrateKbps,
hardwareAcceleratedDecoding: config.streamOpts.hardware_acceleration,
videoCodec: config.streamOpts.videoCodec === 'H264' ? 'H264' : 'VP8'
}

const prefix = config.prefix;

const videosFolder = config.videosFolder || './videos';
width: config.width,
height: config.height,
fps: config.fps,
bitrateKbps: config.bitrateKbps,
maxBitrateKbps: config.maxBitrateKbps,
hardwareAcceleratedDecoding: config.hardwareAcceleratedDecoding,
videoCodec: config.videoCodec === 'VP8' ? 'VP8' : 'H264'
};

// create videos folder if not exists
if (!fs.existsSync(videosFolder)) {
fs.mkdirSync(videosFolder);
if (!fs.existsSync(config.videosFolder)) {
fs.mkdirSync(config.videosFolder);
}

const videoFiles = fs.readdirSync(videosFolder);
const videoFiles = fs.readdirSync(config.videosFolder);
let videos = videoFiles.map(file => {
const fileName = path.parse(file).name;
// replace space with _
return { name: fileName.replace(/ /g, ''), path: path.join(videosFolder, file) };
return { name: fileName.replace(/ /g, ''), path: path.join(config.videosFolder, file) };
});

// print out all videos
Expand Down Expand Up @@ -61,9 +58,9 @@ let streamStatus = {
joinsucc: false,
playing: false,
channelInfo: {
guildId: '',
channelId: '',
cmdChannelId: ''
guildId: config.guildId,
channelId: config.videoChannelId,
cmdChannelId: config.cmdChannelId
}
}

Expand All @@ -75,9 +72,9 @@ streamer.client.on('voiceStateUpdate', (oldState, newState) => {
streamStatus.joinsucc = false;
streamStatus.playing = false;
streamStatus.channelInfo = {
guildId: '',
channelId: '',
cmdChannelId: streamStatus.channelInfo.cmdChannelId
guildId: config.guildId,
channelId: config.videoChannelId,
cmdChannelId: config.cmdChannelId
}
streamer.client.user?.setActivity(status_idle() as unknown as ActivityOptions)
}
Expand All @@ -95,18 +92,16 @@ streamer.client.on('voiceStateUpdate', (oldState, newState) => {

streamer.client.on('messageCreate', async (message) => {
if (message.author.bot) return; // ignore bots
if (message.author.id == streamer.client.user?.id) return; // ignore self
if (!config.commandChannel.includes(message.channel.id)) return; // ignore non-command channels
if (!message.content.startsWith(prefix)) return; // ignore non-commands

const args = message.content.slice(prefix.length).trim().split(/ +/); // split command and arguments
if (args.length == 0) return;
if (message.author.id === streamer.client.user?.id) return; // ignore self
if (!config.cmdChannelId.includes(message.channel.id.toString())) return; // ignore non-command channels
if (!message.content.startsWith(config.prefix!)) return; // ignore non-commands
const args = message.content.slice(config.prefix!.length).trim().split(/ +/); // split command and arguments

if (args.length === 0) return;
const user_cmd = args.shift()!.toLowerCase();
const [guildId, channelId] = [config.guildId, config.videoChannel];

const [guildId, channelId] = [config.guildId, config.videoChannelId!];

if (config.commandChannel.includes(message.channel.id)) {
if (config.cmdChannelId.includes(message.channel.id)) {
switch (user_cmd) {
case 'play':
if (streamStatus.joined) {
Expand Down Expand Up @@ -275,11 +270,11 @@ streamer.client.on('messageCreate', async (message) => {
break;
case 'refresh':
// refresh video list
const videoFiles = fs.readdirSync(videosFolder);
const videoFiles = fs.readdirSync(config.videosFolder);
videos = videoFiles.map(file => {
const fileName = path.parse(file).name;
// replace space with _
return { name: fileName.replace(/ /g, ''), path: path.join(videosFolder, file) };
return { name: fileName.replace(/ /g, ''), path: path.join(config.videosFolder, file) };
});
message.reply('video list refreshed ' + videos.length + ' videos found.\n' + videos.map(m => m.name).join('\n'));
break;
Expand Down Expand Up @@ -375,7 +370,7 @@ streamer.client.on('messageCreate', async (message) => {

for (const [name, cmd] of Object.entries(commands)) {
help += `**${name}: ${cmd.description}**\n`;
help += `Usage: \`${prefix}${cmd.usage}\`\n`;
help += `Usage: \`${config.prefix}${cmd.usage}\`\n`;

}

Expand All @@ -390,6 +385,18 @@ streamer.client.on('messageCreate', async (message) => {

streamer.client.login(config.token);

function parseBoolean(value: string | undefined): boolean {
if (typeof value === "string") {
value = value.trim().toLowerCase();
}
switch (value) {
case "true":
return true;
default:
return false;
}
}

async function playVideo(video: string, udpConn: MediaUdp) {
console.log("Started playing video");
udpConn.mediaConnection.setSpeaking(true);
Expand All @@ -411,7 +418,7 @@ async function playVideo(video: string, udpConn: MediaUdp) {
}

async function sendFinishMessage() {
const channel = streamer.client.channels.cache.get(streamStatus.channelInfo.cmdChannelId) as TextChannel;
const channel = streamer.client.channels.cache.get(config.cmdChannelId.toString()) as TextChannel;
await channel?.send("**Finished playing video.**");
}

Expand Down Expand Up @@ -547,7 +554,7 @@ async function ffmpegScreenshot(video: string): Promise<string[]> {
}

// run server if enabled in config
if (config.server.enabled) {
if (config.server_enabled) {
// run server.js
require('./server');
}
Loading

0 comments on commit 8761975

Please sign in to comment.