const fs = require('fs').promises const ytdl = require('ytdl-core') const Discord = require('discord.js') const { Manager } = require('./manager') const { Playlist } = require('./playlist'); const { youtube_instance } = require('../src/youtube'); /** * @extends Manager */ class PlaylistsManager extends Manager { #playlists #filepath constructor(gmanager, guild_id, { filepath = "playlists_manager.db", data = null } = {}) { return (async () => { super(...arguments) const playlists = data || await PlaylistsManager.readFile(filepath) Object.entries(playlists).forEach(([title, tracks]) => { playlists[title] = new Playlist({ tracks, name: title }) }) this.#playlists = playlists this.#filepath = filepath return this })() } static async readFile(filename) { try { return JSON.parse(await fs.readFile(filename, 'utf-8')) } catch (e) { console.warn(`> Impossible to read file "${filename}"`) return {} } } static async writeFile(filename, playlists) { return await fs.writeFile(filename, JSON.stringify(playlists, null, 2)) } async register({ message, params }) { const player = this.get_manager('player') if (params[0] || player.get_playlist().is_named()) { const playlist_title = params[0] || player.get_playlist().get_name() this.#playlists[playlist_title] = player.get_playlist().clone() await PlaylistsManager.writeFile(this.#filepath, this.#playlists) message.channel.send(`:white_check_mark: Playlist \`${playlist_title}\` saved`) player.get_playlist().untouch() return true } else { message.channel.send(`:warning: Cannot save playlist without name`) return false } } async load({ message, params }) { const player = this.get_manager('player') const playlist_title = params[0] // TODO handle long names with spaces... const named_playlist = { title: playlist_title, playlist: this.#playlists[playlist_title] } // const playlist_id = params[0] // const named_playlist = this.#playlists[playlist_id - 1] if (named_playlist) { player.set_playlist(named_playlist.playlist.clone()) message.channel.send(`:white_check_mark: Playlist \`${playlist_title}\` loaded`) } else { message.channel.send(`:warning: Cannot find playlist id \`${playlist_title}\``) } } async fork({ message, params }) { const [source, destination] = params if (!this.#playlists[source]) { message.channel.send(`:warning: Cannot find playlist source \`${source}\``) } else { this.#playlists[destination] = this.#playlists[source].clone() await PlaylistsManager.writeFile(this.#filepath, this.#playlists) message.channel.send(`:white_check_mark: Playlist \`${source}\` forked as \`${destination}\``) } } async list({ message, params }) { message.channel.send( "Playlists:\n" + "```json\n" + Object.entries(this.#playlists).map(([title, p], idx) => `${idx+1}: ${title} (${p.get_duration_as_string()})`).join("\n") + "```\n", ) } async import({ message, params }) { const [playlist_title, query] = params const playlist = await youtube_instance.get_playlist(query) this.#playlists[playlist_title] = playlist await PlaylistsManager.writeFile(this.#filepath, this.#playlists) message.channel.send(`:white_check_mark: Playlist \`${playlist_title}\` imported`) } async export({ message, params }) { if (params.length === 0) params = ["db"] switch (params[0]) { case "db": const export_file = new Discord.MessageAttachment(this.#filepath); message.channel.send(export_file) break default: message.channel.send(`:warning: Cannot export this format.`) } } } module.exports = { PlaylistsManager }