const yt = require('ytdl-core');
const streamy = require("stream");
const fs = require('fs');
const request = require("request");
const spawn = require("child_process").spawn

module.exports = Player;

function Player(message) {
	var that = this;

	this.message = message;
	this.channel = message.channel;
	this.voicechannel = message.member.voiceChannel;
	this.playlist = [];
	this.current = {};
	this.pid = null;
	this.stream = new streamy.Writable();
	this.connect = function() {
		this.voicechannel
			.join()
			.then(connection => {
				var looper = function() {

					//Get a new song playing on the stream
					that.play();

					//Start playing that stream.
					const dispatcher = connection.playStream(that.stream);

					//When the stream ends, restart the "looper", which gets a new song on the stream
					dispatcher.on('end', () => {
						looper();
					});
				}
				looper();
			});
	}
	this.play = function() {

		if(this.playlist.length === 0) return this.voicechannel.leave();

		this.current = this.playlist.shift();

		//Make an ffmpeg stream
		let ffmpeg = spawn('ffmpeg', [
			'-i', 'pipe:0',
			'-f', 'wav',
			'pipe:1'
		]);

		this.pid = ffmpeg.pid;

		//Try it! If it fails, it skips it.
		try {
			//Send the correct input to the ffmpeg stream
			switch (this.current.type) {

				//Stream from YouTube
				case "youtube":
					yt(this.current.url, {audioonly: true})
						.pipe(ffmpeg.stdin);
					break;

				//Stream from a local file
				case "local":
					fs.createReadStream(this.current.url)
						.pipe(ffmpeg.stdin);

					break;

				//Stream from the internet!
				case "http":
				case "https":
					request.get(this.current.url)
						.on("error", (err) => {
							this.channel.send(`A HTTP error occured. Congratulations!`);
							this.play();
						})
						.pipe(ffmpeg.stdin);

					break;
				default:
					this.channel.send(`${this.current.type} is not a valid audio provider.`);
					this.play();
			}

			this.stream = ffmpeg.stdout;

			ffmpeg.stderr.setEncoding('utf8');
			ffmpeg.stderr.on('data', function(data) {
				if(/^execvp\(\)/.test(data)) {
					console.log('failed to start ' + argv.ffmpeg);
					throw "FFMPEG failed!";
				}
			});

			this.stream.on("close", () => {
				this.play();
			});
		} catch(e) {
			this.channel.send(`${e.message} - Skipping...`);
			this.play();
		}

	}
	this.add = function(type, url, title, thumb) {
		//Push a JSON string into the array
		this.playlist.push({
			type: type,
			url: url,
			title: title,
			thumb_url: thumb
		});

		//If the bot is not playing, enter the channel and start playing
		if (!this.voicechannel.connection) {
			this.connect();
		}
	}
	this.skip = function() {
		if (this.pid) process.kill(this.pid, "SIGINT");
		this.pid = null;
	}
	this.stop = function() {
		this.skip();
		this.current = {};
		this.playlist = [];
	}
}

process.on("unhandledRejection", function(err) {
	console.log("Uncaught Promise Error: \n" + err.stack);
});

process.on("uncaughtException", function(err) {
	console.log(err.stack);
});


@@ -534,372 +534,20 @@
  =%3E 
-%7B%0A%09%09%09%09var looper = function() %7B%0A%0A%09%09%09%09%09//Get a new song playing on the stream%0A%09%09%09%09%09that
+this
 .play
-(
 );%0A
-%0A%09%09%09%09%09//Start playing that stream.%0A%09%09%09%09%09const dispatcher = connection.playStream(that.stream);%0A%0A%09%09%09%09%09//When the stream ends, restart the %22looper%22, which gets a new song on the stream%0A%09%09%09%09%09dispatcher.on('end', () =%3E %7B%0A%09%09%09%09%09%09looper();%0A%09%09%09%09%09%7D);%0A%09%09%09%09%7D%0A%09%09%09%09looper();%0A%09%09%09%7D);%0A
 %09%7D%0A%09
@@ -557,30 +557,40 @@
 s.play = fun
+ction(conne
 ction
-(
 ) %7B%0A%0A%09%09if(th
@@ -800,24 +800,49 @@
 e:1'%0A%09%09%5D);%0A%0A
+%09%09//Set the PID of this.%0A
 %09%09this.pid =
@@ -1635,30 +1635,82 @@
 %09%09%7D%0A%0A%09%09%09
-this.s
+//Send FFMPEG's output to the connection%0A%09%09%09connection.playS
 tream
- = 
+(
 ffmpeg.s
@@ -1714,19 +1714,49 @@
 g.stdout
+)
 ;%0A%0A
+%09%09%09//Check for FFMPEG errors%0A
 %09%09%09ffmpe
@@ -1960,16 +1960,83 @@
 %09%09%09%7D);%0A%0A
+%09%09%09//The stream has ended, therefore it can go on to the next song%0A
 %09%09%09this.
@@ -2083,18 +2083,17 @@
 ();%0A%09%09%09%7D
-);
+%0A
 %0A%09%09%7D cat

Check stream end not dispatcher end