Search code examples
node.jsgoogle-drive-apidiscord.jsaudio-streaming

Stream an audio file from Google Drive into a Discord voice channel


So I am trying to set up a music library I can access from my discord.js bot. I ideally want to stream a playlist/specific song, all songs from a same genre will be in the same folder, so my idea is to do say !play electronic and the bot will play all the files in a specific folder. Before getting to the entire folder, I've been trying to get a single file to stream, and that's where I'm stuck at. I have also not found a way to stream the audio file itself, but I am rather downloading it and storing it in a temporary mp3 file. I would accept any kind of suggestions as to how stream the file instead of downloading it if that provides any large benefits/is significantly easier to code, otherwise how to download it and temporarily store it while it plays (bear in mind that the hosting service I'm using has limited storage available so downloading the entire folder isn't an option), and as to how to approach loading/pre-loading and queueing of the playlist (the entire music folder) in an efficient way for the bot to stream. Here is the relevant part of my code, following the Google Drive API docs about file downloads:

if (message.member.voiceChannel) {
    var temp = fs.createWriteStream('./tmpsong.mp3');
    drive.files.get({
        fileId: '1JTJ7W9C6NBBtjcLhD6P4G9YeXvPQxaBP',
        alt: 'media'
    }).on('end', function () {
        console.log('Done');
    }).on('error', function (err) {
        console.log('Error during download', err);
    }).pipe(temp).then(() => {
        message.member.voiceChannel.join().then(connection => {
            const dispatcher = connection.playFile('./tmpsong.mp3');
            dispatcher.on("end", end => { message.member.voiceChannel.leave(); });
        });
    }).catch(err => console.log(err));
}

and here is the error I'm getting:

An error occurred while running the command: TypeError: drive.files.get(...).on is not a function.

I tried removing both .on() functions and leave only .pipe(temp) immediately after the .get(), but I got the same error:

An error occurred while running the command: TypeError: drive.files.get(...).pipe is not a function.

For clarification, I already know how to make the bot join a Discord voice channel and make it play an audio file, I just need to know how to get the file(s) I need from Google Drive, and if possible, what'd be the best approach for a queue/playlist system.

Any advice is welcome, thanks in advance.


Solution

    • You want to play a MP3 file at the voice channel on Discord.
    • You have already been able to play the MP3 file at the voice channel.
    • You have already been able to use Drive API.
    • You want to know about the method for downloading the MP3 file and playing it using the downloaded file.

    If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.

    Modification points:

    • In your script, you download the MP3 file and save it as a temporal file, and then you try to play the MP3 file using the temporal file.
      • In this case, I think that the MP3 file can be played without creating the temporal file using the stream.

    Modified script:

    When your script is modified, it becomes as follows.

    if (message.member.voiceChannel) {
      drive.files.get(
        {
          fileId: '1JTJ7W9C6NBBtjcLhD6P4G9YeXvPQxaBP',
          alt: "media"
        },
        { responseType: "stream" },
        (err, { data }) => {
          message.member.voiceChannel
            .join()
            .then(connection => {
              const dispatcher = connection.playStream(data);
              dispatcher.on("end", end => {
                message.member.voiceChannel.leave();
                process.exit();
              });
            })
            .catch(err => console.log(err));
        }
      );
    }
    
    • In this case, when the play of MP3 is finished, the script is exited by process.exit().

    References:

    If I misunderstood your question and this was not the direction you want, I apologize.