101 lines
2.8 KiB
JavaScript
101 lines
2.8 KiB
JavaScript
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<Buffer>
|
|
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<Buffer>
|
|
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))
|