Compare commits

...

3 Commits

Author SHA1 Message Date
Thibaut Broggi 7ebc2b93b8
Add a !leave command 2021-02-20 20:30:11 +01:00
Thibaut Broggi 7a910e03ff
Add methods to get a playlist's duration 2021-02-20 19:36:59 +01:00
Thibaut Broggi f3930a037a
Move duration manipulation functions outside of the Track class 2021-02-20 18:53:50 +01:00
9 changed files with 121 additions and 82 deletions

View File

@ -9,6 +9,7 @@
"stop": { "target": "player", "action": "stop" },
"pause": { "target": "player", "action": "stop" },
"leave": { "target": "player", "action": "leave" },
"resume": { "target": "player", "action": "resume" },

View File

@ -3,7 +3,7 @@
"version": "0.0.0",
"description": "A discord music player",
"scripts": {
"doc": "rm -fr ./doc && jsdoc -a all -R ./README.md -d doc/ ./src",
"doc": "rm -fr ./doc && jsdoc -a all -R ./README.md -d doc/ ./src -r",
"start": "node index.js",
"test": "jest --collectCoverage"
},

34
src/helpers/duration.js Normal file
View File

@ -0,0 +1,34 @@
/**
* @param {durationString}
* @returns {number}
*/
function from_string_to_seconds(str = "") {
return str
.split(':')
.map(v => parseInt(v))
.reduce((acc, v) => acc * 60 + v)
}
/**
* @typedef {string} durationString
* @desc A string representation of the duration, following the [[HH:]mm:]ss format.<br />
* This format is the same as the one used by YouTube
*/
/**
* @param {number}
* @returns {durationString}
*/
function from_seconds_to_string(seconds) {
const secs = parseInt(seconds % 60)
const minutes = parseInt((seconds / 60) % 60)
const hours = parseInt(seconds / 3600)
return ''
+ (hours > 0 ? hours + ':' : '')
+ String(minutes).padStart((hours > 0 ? 2 : 1), '0')
+ ':'
+ String(secs).padStart(2, '0')
}
module.exports = { from_string_to_seconds, from_seconds_to_string }

View File

@ -75,6 +75,14 @@ class PlayerManager {
this.#voice.voice.setSelfDeaf(true)
}
async leave({ message, params }) {
if (this.#voice) {
this.#voice.channel.leave()
this.#is_playing = false
this.#playlist
}
}
async shuffle({ message, params }) {
this.#playlist.shuffle()
message.channel.send('Shuffled ! :twisted_rightwards_arrows:')

View File

@ -1,4 +1,5 @@
const { Track } = require('./track')
const { from_seconds_to_string } = require('./helpers/duration')
// side effect
function shuffle_array(arr) {
@ -119,10 +120,30 @@ class Playlist {
return this.#tracks.length === 0
}
/**
* @method
* @returns {number} The number of tracks in the playlist
*/
get_length() {
return this.#tracks.length
}
/**
* @method
* @return {number} The duration of the playlist, in seconds
*/
get_duration() {
return this.#tracks.reduce((a, t) => a + t.get_length(), 0)
}
/**
* @method
* @return {durationString} The duration of the playlist, as a string
*/
get_duration_as_string() {
return from_seconds_to_string(this.get_duration())
}
/**
* @method
* @returns {string} a string representation of the playlist

View File

@ -76,9 +76,9 @@ class PlaylistsManager {
async list({ message, params }) {
message.channel.send(
"Playlist:\n" +
"Playlists:\n" +
"```json\n" +
Object.entries(this.#playlists).map(([title, p], idx) => `${idx+1}: ${title}`).join("\n") +
Object.entries(this.#playlists).map(([title, p], idx) => `${idx+1}: ${title} (${p.get_duration_as_string()})`).join("\n") +
"```\n",
)
}

View File

@ -1,3 +1,5 @@
const { from_string_to_seconds, from_seconds_to_string } = require('./helpers/duration')
/**
* @class
*/
@ -14,7 +16,7 @@ class Track {
* @param {Object} parameters={}
* @param {string} parameters.url The url of the track
* @param {string} parameters.title The title of the track
* @param {number|string} parameters.length The length of the track, either in seconds or following the [[HH:]mm:]ss format. Strings from YouTube can be used without any modification
* @param {number|durationString} parameters.length The length of the track, either in seconds or following the [[HH:]mm:]ss format.
* @param {string} parameters.source The source where the track comes from. Note that as of now, only <code>'youtube'</code> is supported.
* @param {number|Date} [parameters.last_played=0] The timestamp when this track has been played for the last time
* @param {number} [parameters.play_count=0] The number of times this track has been played
@ -109,18 +111,10 @@ class Track {
}
/**
* @returns {string} A string representation of the track length<br />
* The format is the same as YouTube's one
* @returns {durationString} A string representation of the track length
*/
get_length_as_string() {
const seconds = parseInt(this.#length % 60)
const minutes = parseInt((this.#length / 60) % 60)
const hours = parseInt(this.#length / 3600)
return ''
+ (hours > 0 ? hours + ':' : '')
+ String(minutes).padStart((hours > 0 ? 2 : 1), '0')
+ ':'
+ String(seconds).padStart(2, '0')
return from_seconds_to_string(this.#length)
}
}

View File

@ -0,0 +1,49 @@
const { from_string_to_seconds, from_seconds_to_string } = require('../../src/helpers/duration')
describe('from_string_to_seconds', () => {
test('1 second long, various formats', () => {
expect(from_string_to_seconds("1")).toBe(1)
expect(from_string_to_seconds("0:01")).toBe(1)
expect(from_string_to_seconds("0:00:01")).toBe(1)
})
test('1 minute long, various formats', () => {
expect(from_string_to_seconds("60")).toBe(60)
expect(from_string_to_seconds("1:00")).toBe(60)
expect(from_string_to_seconds("01:00")).toBe(60)
expect(from_string_to_seconds("0:01:00")).toBe(60)
})
test('1 hour long, various formats', () => {
expect(from_string_to_seconds("3600")).toBe(3600)
expect(from_string_to_seconds("60:00")).toBe(3600)
expect(from_string_to_seconds("59:60")).toBe(3600)
expect(from_string_to_seconds("1:00:00")).toBe(3600)
})
test('various values', () => {
expect(from_string_to_seconds("12:34")).toBe(754)
expect(from_string_to_seconds("1:23:45")).toBe(5025)
expect(from_string_to_seconds("100:00:59")).toBe(360059)
})
})
describe('track length formating (output)', () => {
test('1 second long', () => {
expect(from_seconds_to_string(1)).toBe("0:01")
})
test('1 minute long', () => {
expect(from_seconds_to_string(60)).toBe("1:00")
})
test('1 hour long', () => {
expect(from_seconds_to_string(3600)).toBe("1:00:00")
})
test('various values', () => {
expect(from_seconds_to_string(754)).toBe("12:34")
expect(from_seconds_to_string(5025)).toBe("1:23:45")
expect(from_seconds_to_string(360059)).toBe("100:00:59")
})
})

View File

@ -33,71 +33,3 @@ describe('track basic manipulations', () => {
expect(t2.toJSON().last_played).toBeGreaterThan(0)
})
})
describe('track length formating (input)', () => {
test('1 second long, various formats', () => {
const t1 = new Track({ length: "1" })
const t2 = new Track({ length: "0:01" })
const t3 = new Track({ length: "0:00:01" })
expect(t1.get_length()).toBe(1)
expect(t2.get_length()).toBe(1)
expect(t3.get_length()).toBe(1)
})
test('1 minute long, various formats', () => {
const t1 = new Track({ length: "60" })
const t2 = new Track({ length: "1:00" })
const t3 = new Track({ length: "01:00" })
const t4 = new Track({ length: "0:01:00" })
expect(t1.get_length()).toBe(60)
expect(t2.get_length()).toBe(60)
expect(t3.get_length()).toBe(60)
expect(t4.get_length()).toBe(60)
})
test('1 hour long, various formats', () => {
const t1 = new Track({ length: "3600" })
const t2 = new Track({ length: "60:00" })
const t3 = new Track({ length: "59:60" })
const t4 = new Track({ length: "1:00:00" })
expect(t1.get_length()).toBe(3600)
expect(t2.get_length()).toBe(3600)
expect(t3.get_length()).toBe(3600)
expect(t4.get_length()).toBe(3600)
})
test('various values', () => {
const t1 = new Track({ length: "12:34" })
const t2 = new Track({ length: "1:23:45" })
const t3 = new Track({ length: "100:00:59" })
expect(t1.get_length()).toBe(754)
expect(t2.get_length()).toBe(5025)
expect(t3.get_length()).toBe(360059)
})
})
describe('track length formating (output)', () => {
test('1 second long', () => {
const t1 = new Track({ length: 1 })
expect(t1.get_length_as_string()).toBe("0:01")
})
test('1 minute long', () => {
const t1 = new Track({ length: 60 })
expect(t1.get_length_as_string()).toBe("1:00")
})
test('1 hour long', () => {
const t1 = new Track({ length: 3600 })
expect(t1.get_length_as_string()).toBe("1:00:00")
})
test('various values', () => {
const t1 = new Track({ length: 754 })
const t2 = new Track({ length: 5025 })
const t3 = new Track({ length: 360059 })
expect(t1.get_length_as_string()).toBe("12:34")
expect(t2.get_length_as_string()).toBe("1:23:45")
expect(t3.get_length_as_string()).toBe("100:00:59")
})
})