Coder Social home page Coder Social logo

const { Client } = require('discord.js'); const ytdl = require('ytdl-core'); const { token } = require('./token.json'); const { prefix } = require('./config.json'); const client = new Client();

// 建立一個類別來管理 Property 及 Method class Music {

constructor() {
    /**
     * 下面的物件都是以 Discord guild id 當 key,例如:
     * this.isPlaying = {
     *     724145832802385970: false
     * }
     */

    /**
     * 機器人是否正在播放音樂
     * this.isPlaying = {
     *     724145832802385970: false
     * }
     */
    this.isPlaying = {};

    /**
     * 等待播放的音樂隊列,例如:
     * this.queue = {
     *     724145832802385970: [{
     *         name: 'G.E.M.鄧紫棋【好想好想你 Missing You】Official Music Video',
     *         url: 'https://www.youtube.com/watch?v=P6QXo88IG2c&ab_channel=GEM%E9%84%A7%E7%B4%AB%E6%A3%8B'
     *     }]
     * }
     */
    this.queue = {};

    // https://discord.js.org/#/docs/main/stable/class/VoiceConnection
    this.connection = {};

    // https://discord.js.org/#/docs/main/stable/class/StreamDispatcher
    this.dispatcher = {};
}

async join(msg) {

    // 如果使用者正在頻道中
    if (msg.member.voice.channel !== null) {
        // Bot 加入語音頻道
        this.connection[msg.guild.id] = await msg.member.voice.channel.join();
    } else {
        msg.channel.send('請先進入語音頻道');
    }

}

async play(msg) {

    // 語音群的 ID
    const guildID = msg.guild.id;

    // 如果 Bot 還沒加入該語音群的語音頻道
    if (!this.connection[guildID]) {
        msg.channel.send('請先將機器人 `!!join` 加入頻道');
        return;
    }

    // 如果 Bot leave 後又未加入語音頻道
    if (this.connection[guildID].status === 4) {
        msg.channel.send('請先將機器人 `!!join` 重新加入頻道');
        return;
    }

    // 處理字串,將 !!play 字串拿掉,只留下 YouTube 網址
    const musicURL = msg.content.replace(`${prefix}play`, '').trim();

    try {

        // 取得 YouTube 影片資訊
        const res = await ytdl.getInfo(musicURL);
        const info = res.videoDetails;

        // 將歌曲資訊加入隊列
        if (!this.queue[guildID]) {
            this.queue[guildID] = [];
        }

        this.queue[guildID].push({
            name: info.title,
            url: musicURL
        });

        // 如果目前正在播放歌曲就加入隊列,反之則播放歌曲
        if (this.isPlaying[guildID]) {
            msg.channel.send(`歌曲加入隊列:${info.title}`);
        } else {
            this.isPlaying[guildID] = true;
            this.playMusic(msg, guildID, this.queue[guildID][0]);
        }

    } catch(e) {
        console.log(e);
    }

}

playMusic(msg, guildID, musicInfo) {

    // 提示播放音樂
    msg.channel.send(`播放音樂:${musicInfo.name}`);

    // 播放音樂
    this.dispatcher[guildID] = this.connection[guildID].play(ytdl(musicInfo.url, { filter: 'audioonly' }));

    // 把音量降 50%,不然第一次容易被機器人的音量嚇到 QQ
    this.dispatcher[guildID].setVolume(0.5);

    // 移除 queue 中目前播放的歌曲
    this.queue[guildID].shift();

    // 歌曲播放結束時的事件
    this.dispatcher[guildID].on('finish', () => {

        // 如果隊列中有歌曲
        if (this.queue[guildID].length > 0) {
            this.playMusic(msg, guildID, this.queue[guildID][0]);
        } else {
            this.isPlaying[guildID] = false;
            msg.channel.send('目前沒有音樂了,請加入音樂 :D');
        }

    });

}

resume(msg) {

    if (this.dispatcher[msg.guild.id]) {
        msg.channel.send('恢復播放');

        // 恢復播放
        this.dispatcher[msg.guild.id].resume();
    }

}

pause(msg) {

    if (this.dispatcher[msg.guild.id]) {
        msg.channel.send('暫停播放');

        // 暫停播放
        this.dispatcher[msg.guild.id].pause();
    }

}

skip(msg) {

    if (this.dispatcher[msg.guild.id]) {
        msg.channel.send('跳過目前歌曲');

        // 跳過歌曲
        this.dispatcher[msg.guild.id].end();
    }

}

nowQueue(msg) {

    // 如果隊列中有歌曲就顯示
    if (this.queue[msg.guild.id] && this.queue[msg.guild.id].length > 0) {
        // 字串處理,將 Object 組成字串
        const queueString = this.queue[msg.guild.id].map((item, index) => `[${index+1}] ${item.name}`).join();
        msg.channel.send(queueString);
    } else {
        msg.channel.send('目前隊列中沒有歌曲');
    }

}

leave(msg) {

    // 如果機器人在頻道中
    if (this.connection[msg.guild.id] && this.connection[msg.guild.id].status === 0) {

        // 如果機器人有播放過歌曲
        if (this.queue.hasOwnProperty(msg.guild.id)) {

            // 清空播放列表
            delete this.queue[msg.guild.id];

            // 改變 isPlaying 狀態為 false
            this.isPlaying[msg.guild.id] = false;
        }

        // 離開頻道
        this.connection[msg.guild.id].disconnect();
    } else {
        msg.channel.send('機器人未加入任何頻道');
    }

}

}

const music = new Music();

// 當 Bot 接收到訊息時的事件 client.on('message', async (msg) => {

// 如果發送訊息的地方不是語音群(可能是私人),就 return
if (!msg.guild) return;

// !!join
if (msg.content === `${prefix}join`) {

    // 機器人加入語音頻道
    music.join(msg);
}

// 如果使用者輸入的內容中包含 !!play
if (msg.content.indexOf(`${prefix}play`) > -1) {

    // 如果使用者在語音頻道中
    if (msg.member.voice.channel) {

        // 播放音樂
        await music.play(msg);
    } else {

        // 如果使用者不在任何一個語音頻道
        msg.reply('你必須先加入語音頻道');
    }
}

// !!resume
if (msg.content === `${prefix}resume`) {

    // 恢復音樂
    music.resume(msg);
}

// !!pause
if (msg.content === `${prefix}pause`) {

    // 暫停音樂
    music.pause(msg);
}

// !!skip
if (msg.content === `${prefix}skip`) {

    // 跳過音樂
    music.skip(msg);
}

// !!queue
if (msg.content === `${prefix}queue`) {

    // 查看隊列
    music.nowQueue(msg);
}

// !!leave
if (msg.content === `${prefix}leave`) {

    // 機器人離開頻道
    music.leave(msg);
}

});

// 連上線時的事件 client.on('ready', () => { console.log(Logged in as ${client.user.tag}!); });

client.login(token);

ryan9611's Projects

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.