This commit is contained in:
Lechner Julian - FrauJulian
2025-07-07 17:36:48 +02:00
parent 099d6a1367
commit 1104dde075
14 changed files with 3882 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: FrauJulian
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
+4
View File
@@ -0,0 +1,4 @@
.idea
.git
node_modules
dist
+8
View File
@@ -0,0 +1,8 @@
.idea
.git
.gitignore
.npmignore
node_modules
src
tsconfig.json
tsup.config.ts
+28
View File
@@ -0,0 +1,28 @@
BSD 3-Clause License
Copyright (c) 2025, Julian Lechner
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+85
View File
@@ -0,0 +1,85 @@
# Discord Audio Stream
[![npm](https://img.shields.io/npm/dw/discord-audio-stream)](http://npmjs.org/package/discord-audio-stream)
![GitHub package.json version](https://img.shields.io/github/package-json/v/FrauJulian/discord-audio-stream)
![GitHub Repo stars](https://img.shields.io/github/stars/FrauJulian/discord-audio-stream?style=social)
**This module is designed to work with [discord.js/voice](https://www.npmjs.com/package/@discordjs/voice) v0.18. This
package doesn't support older
versions!**
## 👋 Support
Please create an [issue](https://github.com/FrauJulian/DiscordAudioStreamNPM/issues) on github or write [
`fraujulian`](https://discord.com/users/860206216893693973) on discord!
## 📝 Usage
### Install package
```bash
npm install discord-audio-stream opusscript @discordjs/voice ffmpeg-static sodium-native
```
### Create Instance
```js
let audioManager = new AudioManager();
```
or (with parameters)
```js
let audioManager = new AudioManager({
VoiceChannelId: 0, //voice channel id where to play music
GuildId: 0, //guild id
VoiceAdapter: 0 //guild VoiceAdapter
},
{
ResourceType: "", //resource type like link or file
Resource: "" //auto play link or file name
});
```
### Properties of the AudioManager
#### Properties
| Callable with | Type | Description |
|-------------------|------------------------------|-------------------------------------------------|
| `VoiceConnection` | **VoiceConnection** | VoiceConnection instance from discord.js/voice. |
| `AudioPlayer` | **AudioPlayer** | AudioPlayer instance from discord.js/voice. |
| `AudioResource` | **AudioResource** | AudioResource instance from discord.js/voice. |
| `ConnectionData` | **VoiceConnectionDataModel** | Global variable for connection data. |
| `AudioData` | **AudioDataModel** | Global variable for audio data. |
#### Methods
| Callable with | Parameters | Return type | Description |
|--------------------------------|--------------------------------------------------------------------------------------------------------|-------------|--------------------------------------------------------------------|
| `OverrideOptions` | `connectionData` (type of **VoiceConnectionDataModel**), `audioData` (type of **VoiceAudioDataModel**) | void | Method to override global variables, connectionData and audioData. |
| `CreateConnection` | `isRenew` (type of boolean, default value is false) | void | Method to join the voice connection. |
| `PlayAudioOnConnection` | | void | Method to play audio on the existing voice connection. |
| `PauseAudio` | | void | Method to pause the audio. |
| `ResumeAudio` | | void | Method to resume the audio. |
| `StopAudioOnConnection` | | void | Method to stop the audio without destroying voice connection. |
| `CreateConnectionAndPlayAudio` | | void | Method to join the voice connection and play audio. |
| `DestroyConnection` | | void | Method to destroy the voice connection. |
| `SetVolume` | `volume` (type of number, 0 - 100 percent) | void | Method to set the audio volume. | Method to set the volume of the audio. |
| `SetMaxListeners` | `maxListeners` (type of number) | void | Method to set the max listeners of the audio stream. |
##### Types History
- [**VoiceConnection** by discord.js/voice](https://github.com/discordjs/discord.js/blob/main/packages/voice/src/VoiceConnection.ts#L166)
- [**AudioPlayer** by discord.js/voice](https://github.com/discordjs/discord.js/blob/main/packages/voice/src/audio/AudioPlayer.ts#L155)
- [**AudioResource** by discord.js/voice](https://github.com/discordjs/discord.js/blob/main/packages/voice/src/audio/AudioResource.ts#L44)
- [**VoiceConnectionDataModel**](https://github.com/FrauJulian/Discord-Audio-Stream/blob/main/src/Models/VoiceConnectionDataModel.d.ts#L3) (custom type)
- [**VoiceAudioDataModel**](https://github.com/FrauJulian/Discord-Audio-Stream/blob/main/src/Models/VoiceAudioDataModel.d.ts#L1) (custom type)
## 📋 Credits:
~ [**FrauJulian**](https://fraujulian.xyz/).
## 🤝 Enjoy the package?
Give it a star ⭐ on [github](https://github.com/FrauJulian/discord-audio-stream)!
+3462
View File
File diff suppressed because it is too large Load Diff
+48
View File
@@ -0,0 +1,48 @@
{
"name": "discord-audio-stream",
"version": "0.6.8",
"description": "NodeJS library to make stream any audio on discord easier.",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"scripts": {
"updateDependencies": "npx npm-check-updates --upgrade && npm install && echo SUCCEED UPDATE",
"cleanSolution": "del-cli dist && echo SUCCEED CLEAN",
"updateVersion": "npm version patch --no-git-tag-version && echo SUCCEED UPDATE VERSION",
"buildPackage": "tsup && echo SUCCEED BUILD && npm run updateVersion",
"rolloutBuild": "npm run updateDependencies && npm run cleanSolution && tsup"
},
"repository": "https://github.com/FrauJulian/Discord-Audio-Stream",
"bugs": "https://github.com/FrauJulian/Discord-Audio-Stream/issues",
"keywords": [
"discordjs-v14",
"stream",
"audio",
"music"
],
"author": {
"name": "Lechner Julian",
"nickname": "FrauJulian",
"email": "contact@fraujulian.xyz",
"website": "https://fraujulian.xyz/"
},
"private": false,
"dependencies": {
"@discordjs/opus": "^0.10.0",
"@discordjs/voice": "^0.18.0",
"@noble/ciphers": "^1.3.0",
"@stablelib/xchacha20poly1305": "^2.0.1",
"ffmpeg-static": "^5.2.0",
"libsodium-wrappers": "^0.7.15",
"opusscript": "^0.1.1",
"sodium-native": "^5.0.6"
},
"devDependencies": {
"@types/ejs": "^3.1.5",
"@types/node": "^24.0.10",
"del-cli": "^6.0.0",
"npm-check-updates": "^18.0.1",
"tsup": "^8.5.0",
"typescript": "^5.8.3"
}
}
+12
View File
@@ -0,0 +1,12 @@
export interface VoiceAudioDataModel {
/**
* The unique identifier for the audio resource.
*/
ResourceType: "Link" | "File";
/**
* The URL or file path of the audio resource.
* any is to be assumed to require(filepath)
*/
Resource: string | any;
}
+19
View File
@@ -0,0 +1,19 @@
import {DiscordGatewayAdapterCreator} from "@discordjs/voice";
export interface VoiceConnectionDataModel {
/**
* The ID of the voice channel to connect to.
*/
VoiceChannelId: number;
/**
* The Id of the guild (server) to connect to.
*/
GuildId: number;
/**
* The adapter creator for the voice connection.
* Can be archived by the guild instance via the voiceAdapterCreator property.
*/
VoiceAdapter: DiscordGatewayAdapterCreator;
}
+138
View File
@@ -0,0 +1,138 @@
import {
AudioPlayer,
AudioResource,
createAudioPlayer,
createAudioResource,
joinVoiceChannel,
VoiceConnection
} from "@discordjs/voice";
import {IAudioManager} from "./IAudioManager";
import {VoiceConnectionDataModel} from "../Models/VoiceConnectionDataModel";
import {VoiceAudioDataModel} from "../Models/VoiceAudioDataModel";
import {join} from "node:path";
export class AudioManager implements IAudioManager {
public VoiceConnection: VoiceConnection | null = null;
public AudioPlayer: AudioPlayer | null = null;
public AudioResource: AudioResource | null = null;
protected IsActive: boolean = false;
protected IsAudioPlaying: boolean = false;
protected ConnectionData: VoiceConnectionDataModel | null;
protected AudioData: VoiceAudioDataModel | null;
constructor(connectionData: VoiceConnectionDataModel | null = null, audioData: VoiceAudioDataModel | null = null) {
this.ConnectionData = connectionData;
this.AudioData = audioData;
}
public OverrideOptions(connectionData: VoiceConnectionDataModel | null = null, audioData: VoiceAudioDataModel | null = null): void {
this.ConnectionData = connectionData;
this.AudioData = audioData;
}
public CreateConnection(isRenew: boolean = false): void {
this.CheckIfNull(this.ConnectionData);
if (!isRenew) {
if (this.IsActive) {
this.DestroyConnection(false);
} else {
this.IsActive = true;
}
}
this.VoiceConnection = joinVoiceChannel({
channelId: this.ConnectionData!.VoiceChannelId.toString(),
guildId: this.ConnectionData!.GuildId.toString(),
adapterCreator: this.ConnectionData!.VoiceAdapter
});
setTimeout((): void => {
this.RenewConnectionAndAudio();
}, 5400000);
}
public PlayAudioOnConnection(): void {
this.CheckIfNull(this.AudioData);
if (this.AudioData!.ResourceType === "File") {
this.AudioResource = createAudioResource(join(__dirname, this.AudioData!.Resource), {inlineVolume: true});
} else if (this.AudioData!.ResourceType === "Link") {
this.AudioResource = createAudioResource(this.AudioData!.Resource, {inlineVolume: true});
} else {
throw new Error("Invalid resource type.");
}
this.AudioPlayer = createAudioPlayer();
this.AudioPlayer.play(this.AudioResource);
this.VoiceConnection!.subscribe(this.AudioPlayer!);
this.IsAudioPlaying = true;
}
public StopAudioOnConnection(): void {
if (this.IsAudioPlaying) {
this.DestroyConnection(false)
this.CreateConnection();
} else {
throw new Error("Audio is not playing.");
}
}
public PauseAudio(): void {
this.CheckIfNull(this.AudioPlayer);
this.AudioPlayer!.pause();
}
public ResumeAudio(): void {
this.CheckIfNull(this.AudioPlayer);
this.AudioPlayer!.unpause();
}
public CreateConnectionAndPlayAudio(): void {
this.CreateConnection();
this.PlayAudioOnConnection();
}
public DestroyConnection(resetValidationParameters: boolean = true): void {
this.CheckIfNull(this.VoiceConnection);
this.VoiceConnection!.destroy();
if (resetValidationParameters) {
this.IsActive = false;
this.IsAudioPlaying = false;
}
}
public SetMaxListeners(maxListeners: number): void {
this.CheckIfNull(this.VoiceConnection);
this.VoiceConnection!.setMaxListeners(maxListeners);
}
public SetVolume(volumeInPercent: number): void {
if (volumeInPercent < 0 || volumeInPercent > 100) throw new Error("Volume must be between 0 and 100.");
this.AudioResource!.volume!.setVolume(volumeInPercent / 100);
}
private RenewConnectionAndAudio(): void {
this.DestroyConnection(false);
if (this.IsActive) {
this.CreateConnection(true);
if (this.IsAudioPlaying) {
this.PlayAudioOnConnection();
}
}
}
private CheckIfNull<T>(value: T | null): boolean {
if (value === null) {
throw new Error(`${value} cannot be null in this case.`);
}
return true;
}
}
+25
View File
@@ -0,0 +1,25 @@
import {AudioPlayer, AudioResource, VoiceConnection} from "@discordjs/voice";
import {VoiceAudioDataModel} from "../Models/VoiceAudioDataModel";
import {VoiceConnectionDataModel} from "../Models/VoiceConnectionDataModel";
export interface IAudioManager {
OverrideOptions(connectionData?: VoiceConnectionDataModel | null, audioData?: VoiceAudioDataModel | null): void;
CreateConnection(isRenew: boolean): void;
PlayAudioOnConnection(): void;
PauseAudio(): void;
ResumeAudio(): void;
StopAudioOnConnection(): void;
CreateConnectionAndPlayAudio(): void;
DestroyConnection(resetValidationParameters: boolean): void;
SetVolume(volumeInPercent: number): void;
SetMaxListeners(maxListeners: number): void;
}
+3
View File
@@ -0,0 +1,3 @@
export {AudioManager} from "./Services/AudioManager";
export type {VoiceConnectionDataModel} from "./Models/VoiceConnectionDataModel";
export type {VoiceAudioDataModel} from "./Models/VoiceAudioDataModel";
+25
View File
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"strict": true,
"allowJs": false,
"noImplicitAny": true,
"esModuleInterop": true,
"strictNullChecks": true,
"target": "ES2022",
"moduleResolution": "Node",
"module": "CommonJS",
"declaration": true,
"isolatedModules": true,
"noEmit": true,
"outDir": "dist",
"types": [
"node"
],
"typeRoots": [
"node_modules/@types"
]
},
"include": ["src"],
"exclude": ["node_modules"]
}
+10
View File
@@ -0,0 +1,10 @@
import { defineConfig } from "tsup";
export default defineConfig({
format: [ "cjs", "esm" ],
entry: ["./src/index.ts"],
dts: true,
shims: true,
skipNodeModulesBundle: true,
clean: true,
});