aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMax Isom <[email protected]>2022-03-13 18:30:36 -0400
committerGitHub <[email protected]>2022-03-13 17:30:36 -0500
commit6c00727a4a22e28c45711b301c7bf4dbaff90117 (patch)
treec23696f95ce0ef9a4f31586af96021329dedf292 /src
parent03d5cfffd1a9cd8a9977de0d24cce1be0cc73210 (diff)
downloadmuse-6c00727a4a22e28c45711b301c7bf4dbaff90117.tar.xz
muse-6c00727a4a22e28c45711b301c7bf4dbaff90117.zip
Parse duration strings for /fseek and /seek (#565)
Diffstat (limited to 'src')
-rw-r--r--src/commands/fseek.ts15
-rw-r--r--src/commands/seek.ts5
-rw-r--r--src/services/player.ts16
-rw-r--r--src/utils/duration-string-to-seconds.ts21
4 files changed, 46 insertions, 11 deletions
diff --git a/src/commands/fseek.ts b/src/commands/fseek.ts
index 985a7c4..3e34438 100644
--- a/src/commands/fseek.ts
+++ b/src/commands/fseek.ts
@@ -5,15 +5,16 @@ import {inject, injectable} from 'inversify';
import PlayerManager from '../managers/player.js';
import Command from '.';
import {prettyTime} from '../utils/time.js';
+import durationStringToSeconds from '../utils/duration-string-to-seconds.js';
@injectable()
export default class implements Command {
public readonly slashCommand = new SlashCommandBuilder()
.setName('fseek')
.setDescription('seek forward in the current song')
- .addNumberOption(option => option
- .setName('seconds')
- .setDescription('the number of seconds to skip forward')
+ .addStringOption(option => option
+ .setName('time')
+ .setDescription('an interval expression or number of seconds (1m, 30s, 100)')
.setRequired(true));
public requiresVC = true;
@@ -37,12 +38,14 @@ export default class implements Command {
throw new Error('can\'t seek in a livestream');
}
- const seekTime = interaction.options.getNumber('seconds');
+ const seekValue = interaction.options.getString('value');
- if (!seekTime) {
- throw new Error('missing number of seconds to seek');
+ if (!seekValue) {
+ throw new Error('missing seek value');
}
+ const seekTime = durationStringToSeconds(seekValue);
+
if (seekTime + player.getPosition() > currentSong.length) {
throw new Error('can\'t seek past the end of the song');
}
diff --git a/src/commands/seek.ts b/src/commands/seek.ts
index 07f6590..00e9c2e 100644
--- a/src/commands/seek.ts
+++ b/src/commands/seek.ts
@@ -5,6 +5,7 @@ import PlayerManager from '../managers/player.js';
import Command from '.';
import {parseTime, prettyTime} from '../utils/time.js';
import {SlashCommandBuilder} from '@discordjs/builders';
+import durationStringToSeconds from '../utils/duration-string-to-seconds.js';
@injectable()
export default class implements Command {
@@ -13,7 +14,7 @@ export default class implements Command {
.setDescription('seek to a position from beginning of song')
.addStringOption(option =>
option.setName('time')
- .setDescription('time to seek')
+ .setDescription('an interval expression or number of seconds (1m, 30s, 100)')
.setRequired(true),
);
@@ -45,7 +46,7 @@ export default class implements Command {
if (time.includes(':')) {
seekTime = parseTime(time);
} else {
- seekTime = parseInt(time, 10);
+ seekTime = durationStringToSeconds(time);
}
if (seekTime > currentSong.length) {
diff --git a/src/services/player.ts b/src/services/player.ts
index 6e99364..b3ed34d 100644
--- a/src/services/player.ts
+++ b/src/services/player.ts
@@ -5,7 +5,17 @@ import ytdl from 'ytdl-core';
import {WriteStream} from 'fs-capacitor';
import ffmpeg from 'fluent-ffmpeg';
import shuffle from 'array-shuffle';
-import {AudioPlayer, AudioPlayerStatus, createAudioPlayer, createAudioResource, joinVoiceChannel, StreamType, VoiceConnection, VoiceConnectionStatus} from '@discordjs/voice';
+import {
+ AudioPlayer,
+ AudioPlayerState,
+ AudioPlayerStatus,
+ createAudioPlayer,
+ createAudioResource,
+ joinVoiceChannel,
+ StreamType,
+ VoiceConnection,
+ VoiceConnectionStatus,
+} from '@discordjs/voice';
import FileCacheProvider from './file-cache.js';
import debug from '../utils/debug.js';
import {prisma} from '../utils/db.js';
@@ -493,7 +503,7 @@ export default class {
}
if (this.audioPlayer.listeners('stateChange').length === 0) {
- this.audioPlayer.on('stateChange', this.onAudioPlayerStateChange.bind(this));
+ this.audioPlayer.on(AudioPlayerStatus.Idle, this.onAudioPlayerIdle.bind(this));
}
}
@@ -501,7 +511,7 @@ export default class {
this.disconnect();
}
- private async onAudioPlayerStateChange(_oldState: {status: AudioPlayerStatus}, newState: {status: AudioPlayerStatus}): Promise<void> {
+ private async onAudioPlayerIdle(_oldState: AudioPlayerState, newState: AudioPlayerState): Promise<void> {
// Automatically advance queued song at end
if (newState.status === AudioPlayerStatus.Idle && this.status === STATUS.PLAYING) {
await this.forward(1);
diff --git a/src/utils/duration-string-to-seconds.ts b/src/utils/duration-string-to-seconds.ts
new file mode 100644
index 0000000..588ba5b
--- /dev/null
+++ b/src/utils/duration-string-to-seconds.ts
@@ -0,0 +1,21 @@
+import parse from 'parse-duration';
+
+/**
+ * Parse duration strings to seconds.
+ * @param str any common duration format, like 1m or 1hr 30s. If the input is a number it's assumed to be in seconds.
+ * @returns seconds
+ */
+const durationStringToSeconds = (str: string) => {
+ let seconds;
+ const isInputSeconds = Boolean(/\d+$/.exec(str));
+
+ if (isInputSeconds) {
+ seconds = Number.parseInt(str, 10);
+ } else {
+ seconds = parse(str) / 1000;
+ }
+
+ return seconds;
+};
+
+export default durationStringToSeconds;