<commit_before>var fs = require('fs');
var exec = require('child_process').exec;
var lame = require('lame');
var Speaker = require('speaker');
var taglib = require('taglib');

var walk = function(dir, done) {
	var results = [];
	fs.readdir(dir, function(err, list) {
		if (err) return done(err);
		var pending = list.length;
		if (!pending) return done(null, results);
		list.forEach(function(file) {
			file = dir + '/' + file;
			fs.stat(file, function(err, stat) {
				if (stat && stat.isDirectory()) {
					walk(file, function(err, res) {
					results = results.concat(res);
					if (!--pending) done(null, results);
					});
				} else {
					results.push(file);
					if (!--pending) done(null, results);
				}
			});
		});
	});
};

// See https://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search
var scan = function (dir, done) {
	var results = [];
	walk(dir, function(err, list) {
		if (err) return done(err);

		for (var i = 0; i < list.length; i++) {
			var path = list[i];
			
			if (path.substr(-4) != '.mp3') { // TODO: support other formats too
				continue;
			}
			results.push(path);
		}

		done(null, results);
	});
}

exec('xdg-user-dir MUSIC', function (err, stdout, stderr) {
	var musicDir = stdout.trim();
	if (err || stderr.trim()) {
		musicDir = process.env.HOME+'/Music';
	}

	scan(musicDir, function (err, results) {
		if (err) return console.error('ERR: could not read music directory', musicDir);

		var index = Math.ceil(Math.random() * results.length);
		var path = results[index];
		taglib.tag(path, function (err, tag) {
			if (err) console.error('WARN: error while reading song tags', err);

			console.log('Now playing:', path, tag);

			fs.createReadStream(path)
				.pipe(new lame.Decoder())
				.on('format', function (format) {
					this.pipe(new Speaker(format));
				})
				.on('end', function () {
					console.log('Finished.');
					process.exit();
				});
		});
	});
});<commit_msg>First working prototype<commit_after>var fs = require('fs');
var path = require('path');
var exec = require('child_process').exec;
var ClementineServer = require('clementine-remote').Server;
var lame = require('lame');
var Speaker = require('speaker');
var taglib = require('taglib');

var server = ClementineServer({
	port: 5500,
	auth_code: 42
});

var walk = function(dir, done) {
	var results = [];
	fs.readdir(dir, function(err, list) {
		if (err) return done(err);
		var pending = list.length;
		if (!pending) return done(null, results);
		list.forEach(function(file) {
			file = dir + '/' + file;
			fs.stat(file, function(err, stat) {
				if (stat && stat.isDirectory()) {
					walk(file, function(err, res) {
					results = results.concat(res);
					if (!--pending) done(null, results);
					});
				} else {
					results.push(file);
					if (!--pending) done(null, results);
				}
			});
		});
	});
};

// See https://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search
var scan = function (dir, done) {
	var results = [];
	walk(dir, function(err, list) {
		if (err) return done(err);

		for (var i = 0; i < list.length; i++) {
			var path = list[i];
			
			if (path.substr(-4) != '.mp3') { // TODO: support other formats too
				continue;
			}
			results.push(path);
		}

		done(null, results);
	});
}

var playing = false;
server.on('playpause', function () {
	if (playing) {
		return;
	}
	playing = true;

	exec('xdg-user-dir MUSIC', function (err, stdout, stderr) {
		var musicDir = stdout.trim();
		if (err || stderr.trim()) {
			musicDir = process.env.HOME+'/Music';
		}

		scan(musicDir, function (err, results) {
			if (err) return console.error('ERR: could not read music directory', musicDir);

			var index = Math.ceil(Math.random() * results.length);
			var file = results[index];
			taglib.tag(file, function (err, tag) {
				if (err) console.error('WARN: error while reading song tags', err);

				console.log('Now playing:', file, tag);

				// TODO: title from basename
				var metadata = {
					id: 0,
					index: 0,
					title: tag.title || path.basename(file),
					filename: path.basename(file), //TODO: absolute path? Relative to music dir
					is_local: true
				};
				var props = ['album', 'artist', 'albumartist', 'track', 'disc', 'genre'];
				for (var i = 0; i < props.length; i++) {
					var name = props[i];
					if (tag[name]) {
						metadata[name] = tag[name];
					}
				}
				if (tag.year) {
					metadata.pretty_year = String(tag.year);
				}
				//TODO: pretty_length, art, length, file_size, rating
				server.broadcast({
					type: 'CURRENT_METAINFO',
					response_current_metadata: {
						song_metadata: metadata
					}
				});

				fs.createReadStream(file)
					.pipe(new lame.Decoder())
					.on('format', function (format) {
						console.log('Started', format);

						server.broadcast({
							type: 'ENGINE_STATE_CHANGED',
							response_engine_state_changed: { state: 'Playing' }
						});

						this.pipe(new Speaker(format));
					})
					.on('end', function () {
						console.log('Finished.');
						playing = false;

						server.broadcast({
							type: 'ENGINE_STATE_CHANGED',
							response_engine_state_changed: { state: 'Idle' }
						});
					});
			});
		});
	});
});
{'fraction_non_alphanumeric': 0.17616679418515685, 'fraction_numerical': 0.005547054322876817, 'mean_word_length': 3.120567375886525, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6007421', 'n_tokens_mistral': 2184, 'n_tokens_neox': 1758, 'n_words': 428}