const spawn = require('child_process').spawn const fs = require('fs') const youtubedl = require('youtube-dl-exec') const tmp = require('tmp') const STREAM_URL = "https://www.youtube.com/henrikomagnifico/live" function readText(tmpfile, charWhitelist) { return new Promise((resolve, reject) => { const tesseract = charWhitelist ? spawn('tesseract', [tmpfile.name, '-', '-c', `tessedit_char_whitelist="${charWhitelist}`]) : spawn('tesseract', [tmpfile.name, '-']) let recognizedString = '' tesseract.stdout.on('data', (data) => { recognizedString += data; }) tesseract.on('exit', (code) => { tmpfile.removeCallback() if (code !== 0) { reject() } else { resolve(recognizedString) } }) }) } function thresholdImage(image, threshold) { } function getRegion(frame, x, y, width, height) { // Returns Promise console.log("retrieving region") const threshold = "15%" return new Promise(function (resolve, reject) { const tmpFile = tmp.fileSync() const convert = spawn('convert', [`png:${frame.name}`, '-negate', '-crop', `${width}x${height}+${x}+${y}`, '-white-threshold', threshold, `png:${tmpFile.name}`]) convert.stderr.on('data', data => console.error(data.toString())) convert.on('exit', (code) => { if (code !== 0) { reject() } else { console.log("got region", tmpFile.name) resolve(tmpFile); } }); }); } function getFrame(url) { return new Promise((resolve, reject) => { // Returns Promise const frameFile = tmp.fileSync() const ffmpeg = spawn('ffmpeg', ['-i', url, '-y', '-f', 'image2', '-c:v', 'png', '-frames:v', '1', frameFile.name]) ffmpeg.stderr.on('data', data => console.error(data.toString())) ffmpeg.on('exit', (code) => { if (code !== 0) { reject() } else { console.log("got frame", frameFile.name) resolve(frameFile) } }) }); } function getYoutubeStream() { return new Promise((resolve, reject) => { youtubedl(STREAM_URL, { dumpJson: true, format: "best" }).then(output => resolve(output.url)) .catch(err => reject(err)) }) } getYoutubeStream() .then(url => getFrame(url)) .then(frame => { let title = '', album = '', duration = '' const titlePromise = getRegion(frame, 432, 906, 1487, 54).then(titleRegion => readText(titleRegion)) const albumPromise = getRegion(frame, 440, 957, 1487, 32).then(albumRegion => readText(albumRegion)) const durationPromise = getRegion(frame, 0, 1028, 235, 34).then(durationRegion => readText(durationRegion, "1234567890:/")) console.log("waiting for processors") Promise.all([titlePromise, albumPromise, durationPromise]).then(values => { frame.removeCallback() title = values[0].trim() album = values[1].trim() duration = values[2].trim() console.log(`${album}: ${title} (${duration})`) }).catch(err => console.error(err)) }).catch(err => console.error(err))