djs-selfbot-v13 3.7.34 → 3.7.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
GNU GENERAL PUBLIC LICENSE
|
|
2
2
|
Version 3, 29 June 2007
|
|
3
3
|
|
|
4
|
-
Copyright (C)
|
|
4
|
+
Copyright (C) 2025 002-sans aiko-chan-ai and discordjs
|
|
5
5
|
Everyone is permitted to copy and distribute verbatim copies
|
|
6
6
|
of this license document, but changing it is not allowed.
|
|
7
7
|
|
|
@@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least
|
|
|
632
632
|
the "copyright" line and a pointer to where the full notice is found.
|
|
633
633
|
|
|
634
634
|
<one line to give the program's name and a brief idea of what it does.>
|
|
635
|
-
Copyright (C)
|
|
635
|
+
Copyright (C) 2025 002-sans aiko-chan-ai and discordjs
|
|
636
636
|
|
|
637
637
|
This program is free software: you can redistribute it and/or modify
|
|
638
638
|
it under the terms of the GNU General Public License as published by
|
|
@@ -647,12 +647,9 @@ the "copyright" line and a pointer to where the full notice is found.
|
|
|
647
647
|
You should have received a copy of the GNU General Public License
|
|
648
648
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
649
649
|
|
|
650
|
-
|
|
650
|
+
notice like this when it starts in an interactive mode:
|
|
651
651
|
|
|
652
|
-
|
|
653
|
-
notice like this when it starts in an interactive mode:
|
|
654
|
-
|
|
655
|
-
<program> Copyright (C) <year> <name of author>
|
|
652
|
+
djs-selfbot-v13 Copyright (C) 2025 002-sans aiko-chan-ai and discordjs
|
|
656
653
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
657
654
|
This is free software, and you are welcome to redistribute it
|
|
658
655
|
under certain conditions; type `show c' for details.
|
package/README.md
CHANGED
|
@@ -108,11 +108,6 @@ Github Discussion: [Here](https://github.com/002-sans/djs-selfbot-v13/discussion
|
|
|
108
108
|
## Credits
|
|
109
109
|
- [Discord.js](https://github.com/discordjs/discord.js)
|
|
110
110
|
|
|
111
|
-
## <strong>Other project(s)
|
|
112
|
-
|
|
113
|
-
- 📘 [***aiko-chan-ai/DiscordBotClient***](https://github.com/aiko-chan-ai/DiscordBotClient) <br/>
|
|
114
|
-
A patched version of discord, with bot login support
|
|
115
|
-
|
|
116
111
|
## Star History
|
|
117
112
|
|
|
118
113
|
[](https://star-history.com/#002-sans/djs-selfbot-v13&Date)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "djs-selfbot-v13",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.36",
|
|
4
4
|
"description": "An unofficial discord.js fork for creating selfbots",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"types": "./typings/index.d.ts",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"lint:typings:fix": "tslint typings/index.d.ts --fix",
|
|
16
16
|
"format": "prettier --write src/**/*.js typings/**/*.ts",
|
|
17
17
|
"lint:all": "npm run lint && npm run lint:typings",
|
|
18
|
-
"docs": "
|
|
19
|
-
"docs:test": "
|
|
18
|
+
"docs": "node scripts/generate-docs.js --source src --custom docs/index.yml --output docs/main.json",
|
|
19
|
+
"docs:test": "node scripts/generate-docs.js --source src --custom docs/index.yml",
|
|
20
20
|
"build": "npm run lint:fix && npm run lint:typings:fix && npm run format && npm run docs"
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
@@ -53,14 +53,44 @@ class WebRtcStreamSession extends EventEmitter {
|
|
|
53
53
|
this._abort = new AbortController();
|
|
54
54
|
this._playPromise = null;
|
|
55
55
|
this._command = null;
|
|
56
|
+
this._ffmpegProc = null;
|
|
56
57
|
this._started = false;
|
|
58
|
+
this._running = false;
|
|
59
|
+
this._paused = false;
|
|
60
|
+
this._stopped = false;
|
|
61
|
+
this._positionMs = 0;
|
|
62
|
+
this._runStartWall = 0;
|
|
63
|
+
this._pausedAt = 0;
|
|
64
|
+
this._pausedTotalMs = 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_getPositionMs() {
|
|
68
|
+
if (!this._running) return this._positionMs;
|
|
69
|
+
if (this._paused) return this._positionMs;
|
|
70
|
+
return this._positionMs + (Date.now() - this._runStartWall - this._pausedTotalMs);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
_resetRunClock() {
|
|
74
|
+
this._runStartWall = Date.now();
|
|
75
|
+
this._pausedAt = 0;
|
|
76
|
+
this._pausedTotalMs = 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
_signalFfmpeg(signal) {
|
|
80
|
+
const pid = this._ffmpegProc?.pid;
|
|
81
|
+
if (!pid) return;
|
|
82
|
+
try {
|
|
83
|
+
process.kill(pid, signal);
|
|
84
|
+
} catch {
|
|
85
|
+
// process already exited
|
|
86
|
+
}
|
|
57
87
|
}
|
|
58
88
|
|
|
59
89
|
/**
|
|
60
90
|
* Construit la commande ffmpeg : transcode en H264 + Opus, sortie nut.
|
|
61
91
|
* Pas de filtre azmq (compatibilité ffmpeg sans libzmq).
|
|
62
92
|
*/
|
|
63
|
-
_buildFfmpeg(url) {
|
|
93
|
+
_buildFfmpeg(url, seekSec = 0) {
|
|
64
94
|
const {
|
|
65
95
|
fps,
|
|
66
96
|
height = 720,
|
|
@@ -78,6 +108,8 @@ class WebRtcStreamSession extends EventEmitter {
|
|
|
78
108
|
const output = new PassThrough();
|
|
79
109
|
const command = ffmpeg(url);
|
|
80
110
|
|
|
111
|
+
if (seekSec > 0) command.seekInput(seekSec);
|
|
112
|
+
|
|
81
113
|
const isHttp = typeof url === 'string' && /^https?:\/\//i.test(url);
|
|
82
114
|
if (isHttp) {
|
|
83
115
|
command.inputOptions([
|
|
@@ -123,13 +155,21 @@ class WebRtcStreamSession extends EventEmitter {
|
|
|
123
155
|
return { command, output };
|
|
124
156
|
}
|
|
125
157
|
|
|
126
|
-
async _run(url, signal) {
|
|
158
|
+
async _run(url, signal, seekSec = 0) {
|
|
127
159
|
await ensureFfmpegPath();
|
|
128
160
|
|
|
129
|
-
const { command, output } = this._buildFfmpeg(url);
|
|
161
|
+
const { command, output } = this._buildFfmpeg(url, seekSec);
|
|
130
162
|
this._command = command;
|
|
163
|
+
this._ffmpegProc = null;
|
|
164
|
+
this._running = true;
|
|
165
|
+
this._paused = false;
|
|
166
|
+
this._stopped = false;
|
|
167
|
+
this._resetRunClock();
|
|
131
168
|
|
|
132
|
-
command.on('start', cmd =>
|
|
169
|
+
command.on('start', cmd => {
|
|
170
|
+
this._ffmpegProc = command.ffmpegProc ?? null;
|
|
171
|
+
this.emit('debug', `[cmd] ${cmd}`);
|
|
172
|
+
});
|
|
133
173
|
command.on('stderr', line => this.emit('debug', String(line)));
|
|
134
174
|
|
|
135
175
|
command.on('error', (err, _stdout, stderr) => {
|
|
@@ -139,7 +179,12 @@ class WebRtcStreamSession extends EventEmitter {
|
|
|
139
179
|
this.emit('error', new Error(stderr ? `${msg}\n${stderr}` : msg));
|
|
140
180
|
});
|
|
141
181
|
|
|
142
|
-
|
|
182
|
+
const onAbort = () => {
|
|
183
|
+
this._running = false;
|
|
184
|
+
this._ffmpegProc = null;
|
|
185
|
+
command.kill('SIGTERM');
|
|
186
|
+
};
|
|
187
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
143
188
|
command.run();
|
|
144
189
|
|
|
145
190
|
const { livestream } = this.options;
|
|
@@ -149,8 +194,17 @@ class WebRtcStreamSession extends EventEmitter {
|
|
|
149
194
|
this._playPromise = playStream(output, this.streamer, playOptions, signal);
|
|
150
195
|
|
|
151
196
|
this._playPromise
|
|
152
|
-
.then(() =>
|
|
197
|
+
.then(() => {
|
|
198
|
+
this._running = false;
|
|
199
|
+
this._ffmpegProc = null;
|
|
200
|
+
if (!signal.aborted) {
|
|
201
|
+
this._positionMs = 0;
|
|
202
|
+
this.emit('finish');
|
|
203
|
+
}
|
|
204
|
+
})
|
|
153
205
|
.catch(err => {
|
|
206
|
+
this._running = false;
|
|
207
|
+
this._ffmpegProc = null;
|
|
154
208
|
if (signal.aborted || err?.name === 'AbortError') return;
|
|
155
209
|
this.emit('error', err);
|
|
156
210
|
});
|
|
@@ -171,14 +225,56 @@ class WebRtcStreamSession extends EventEmitter {
|
|
|
171
225
|
void this._run(url, this._abort.signal);
|
|
172
226
|
}
|
|
173
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Met en pause la lecture (ffmpeg suspendu, connexion vocale conservée).
|
|
230
|
+
*/
|
|
231
|
+
pause() {
|
|
232
|
+
if (!this._running || this._paused || this._stopped) return;
|
|
233
|
+
this._positionMs = this._getPositionMs();
|
|
234
|
+
this._pausedAt = Date.now();
|
|
235
|
+
this._signalFfmpeg('SIGSTOP');
|
|
236
|
+
this._paused = true;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Reprend la lecture (après pause ou stop).
|
|
241
|
+
*/
|
|
242
|
+
async resume() {
|
|
243
|
+
if (this._stopped) {
|
|
244
|
+
const seekSec = this._positionMs / 1000;
|
|
245
|
+
this._stopped = false;
|
|
246
|
+
await this._run(this.options.url, this._abort.signal, seekSec);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
if (!this._running || !this._paused) return;
|
|
250
|
+
this._pausedTotalMs += Date.now() - this._pausedAt;
|
|
251
|
+
this._pausedAt = 0;
|
|
252
|
+
this._signalFfmpeg('SIGCONT');
|
|
253
|
+
this._paused = false;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Arrête la lecture en conservant la position et la connexion vocale.
|
|
258
|
+
*/
|
|
174
259
|
stop() {
|
|
260
|
+
if (!this._running) return;
|
|
261
|
+
this._positionMs = this._getPositionMs();
|
|
262
|
+
this._stopped = true;
|
|
263
|
+
this._paused = false;
|
|
264
|
+
this._running = false;
|
|
265
|
+
this._ffmpegProc = null;
|
|
175
266
|
this._abort.abort();
|
|
267
|
+
this._abort = new AbortController();
|
|
176
268
|
}
|
|
177
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Relance depuis la dernière position enregistrée.
|
|
272
|
+
*/
|
|
178
273
|
async replay() {
|
|
179
|
-
this.
|
|
180
|
-
this.
|
|
181
|
-
|
|
274
|
+
const seekSec = (this._running ? this._getPositionMs() : this._positionMs) / 1000;
|
|
275
|
+
if (this._running) this.stop();
|
|
276
|
+
this._stopped = false;
|
|
277
|
+
await this._run(this.options.url, this._abort.signal, seekSec);
|
|
182
278
|
}
|
|
183
279
|
|
|
184
280
|
disconnect() {
|
|
@@ -198,6 +198,7 @@ class BaseGuildVoiceChannel extends GuildChannel {
|
|
|
198
198
|
return this.edit({ rtcRegion }, reason);
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
+
|
|
201
202
|
/**
|
|
202
203
|
* Sets the user limit of the channel.
|
|
203
204
|
* @param {number} userLimit The new user limit
|
|
@@ -223,6 +224,30 @@ class BaseGuildVoiceChannel extends GuildChannel {
|
|
|
223
224
|
return this.edit({ videoQualityMode }, reason);
|
|
224
225
|
}
|
|
225
226
|
|
|
227
|
+
/**
|
|
228
|
+
* Sets the status of the voice channel.
|
|
229
|
+
* @param {?string} status The new status (max 500 characters). Set to `null` to remove the status
|
|
230
|
+
* @returns {Promise<BaseGuildVoiceChannel>}
|
|
231
|
+
* @example
|
|
232
|
+
* // Set the status of a voice channel
|
|
233
|
+
* voiceChannel.setStatus('Hello!')
|
|
234
|
+
* .then(channel => console.log(`Set status to ${channel.status} for ${channel.name}`))
|
|
235
|
+
* .catch(console.error);
|
|
236
|
+
* @example
|
|
237
|
+
* // Remove the status of a voice channel
|
|
238
|
+
* voiceChannel.setStatus(null);
|
|
239
|
+
*/
|
|
240
|
+
setStatus(status) {
|
|
241
|
+
return this.client.api.channels(this.id, 'voice-status').put({
|
|
242
|
+
data: {
|
|
243
|
+
status,
|
|
244
|
+
},
|
|
245
|
+
}).then(() => {
|
|
246
|
+
this.status = status;
|
|
247
|
+
return this;
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
226
251
|
}
|
|
227
252
|
|
|
228
253
|
TextBasedChannel.applyToClass(BaseGuildVoiceChannel, true, ['lastPinAt']);
|
|
@@ -105,6 +105,13 @@ class VoiceChannel extends BaseGuildVoiceChannel {
|
|
|
105
105
|
* @param {string} [reason] Reason for changing the camera video quality mode.
|
|
106
106
|
* @returns {Promise<VoiceChannel>}
|
|
107
107
|
*/
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Sets the status of the voice channel.
|
|
111
|
+
* @name VoiceChannel#setStatus
|
|
112
|
+
* @param {?string} status The new status (max 500 characters). Set to `null` to remove the status
|
|
113
|
+
* @returns {Promise<VoiceChannel>}
|
|
114
|
+
*/
|
|
108
115
|
}
|
|
109
116
|
|
|
110
117
|
module.exports = VoiceChannel;
|
package/typings/index.d.ts
CHANGED
|
@@ -719,13 +719,14 @@ export class BaseGuildVoiceChannel extends TextBasedChannelMixin(GuildChannel, [
|
|
|
719
719
|
public rateLimitPerUser: number | null;
|
|
720
720
|
public userLimit: number;
|
|
721
721
|
public videoQualityMode: VideoQualityMode | null;
|
|
722
|
-
public status
|
|
722
|
+
public status: string | null;
|
|
723
723
|
public createInvite(options?: CreateInviteOptions): Promise<Invite>;
|
|
724
724
|
public setRTCRegion(rtcRegion: string | null, reason?: string): Promise<this>;
|
|
725
725
|
public fetchInvites(cache?: boolean): Promise<Collection<string, Invite>>;
|
|
726
726
|
public setBitrate(bitrate: number, reason?: string): Promise<VoiceChannel>;
|
|
727
727
|
public setUserLimit(userLimit: number, reason?: string): Promise<VoiceChannel>;
|
|
728
728
|
public setVideoQualityMode(videoQualityMode: VideoQualityMode | number, reason?: string): Promise<VoiceChannel>;
|
|
729
|
+
public setStatus(status: string | null): Promise<this>;
|
|
729
730
|
}
|
|
730
731
|
|
|
731
732
|
export class BaseMessageComponent {
|
|
@@ -918,7 +919,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
|
|
918
919
|
}
|
|
919
920
|
>
|
|
920
921
|
>;
|
|
921
|
-
public startStream(options: StartStreamOptions): Promise<
|
|
922
|
+
public startStream(options: StartStreamOptions): Promise<WebRtcStreamSession>;
|
|
922
923
|
|
|
923
924
|
public on<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => Awaitable<void>): this;
|
|
924
925
|
public on<S extends string | symbol>(
|
|
@@ -1208,10 +1209,30 @@ export interface StartStreamOptions {
|
|
|
1208
1209
|
downloadHttp?: boolean;
|
|
1209
1210
|
/** Max video bitrate in kbps. Default: bitrate * 1.5 */
|
|
1210
1211
|
bitrateMax?: number;
|
|
1212
|
+
/** x264 tune (ex. film). */
|
|
1213
|
+
tune?: string;
|
|
1214
|
+
/** readrateInitialBurst pour sources live. */
|
|
1215
|
+
livestream?: boolean;
|
|
1211
1216
|
/** Low-latency encoding and playback. Default true. */
|
|
1212
1217
|
lowLatency?: boolean;
|
|
1213
1218
|
}
|
|
1214
1219
|
|
|
1220
|
+
/** Session Go Live WebRTC retournée par {@link Client#startStream}. */
|
|
1221
|
+
export class WebRtcStreamSession extends EventEmitter {
|
|
1222
|
+
public readonly client: Client;
|
|
1223
|
+
public pause(): void;
|
|
1224
|
+
public resume(): Promise<void>;
|
|
1225
|
+
public stop(): void;
|
|
1226
|
+
public replay(): Promise<void>;
|
|
1227
|
+
public disconnect(): void;
|
|
1228
|
+
public on(event: 'finish', listener: () => void): this;
|
|
1229
|
+
public on(event: 'debug', listener: (message: string) => void): this;
|
|
1230
|
+
public on(event: 'error', listener: (error: Error) => void): this;
|
|
1231
|
+
public once(event: 'finish', listener: () => void): this;
|
|
1232
|
+
public once(event: 'debug', listener: (message: string) => void): this;
|
|
1233
|
+
public once(event: 'error', listener: (error: Error) => void): this;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1215
1236
|
export class StreamSession extends EventEmitter {
|
|
1216
1237
|
public readonly client: Client;
|
|
1217
1238
|
public readonly voiceConnection: VoiceConnection;
|