From baf6d2858a74ff1af125324e27e7601da0715fe8 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sat, 11 Jul 2015 05:30:55 -0700 Subject: [PATCH] add experimental video widget. fix 16 colors in _attr. --- lib/program.js | 2 + lib/widget.js | 3 +- lib/widgets/terminal.js | 20 ++++++- lib/widgets/video.js | 122 ++++++++++++++++++++++++++++++++++++++++ test/widget-video.js | 26 +++++++++ 5 files changed, 170 insertions(+), 3 deletions(-) create mode 100644 lib/widgets/video.js create mode 100644 test/widget-video.js diff --git a/lib/program.js b/lib/program.js index 65b4af7..eea1ec3 100644 --- a/lib/program.js +++ b/lib/program.js @@ -2549,12 +2549,14 @@ Program.prototype._attr = function(param, val) { if (color < 8) { color += 30; } else if (color < 16) { + color -= 8; color += 90; } } else if (m[2] === 'bg') { if (color < 8) { color += 40; } else if (color < 16) { + color -= 8; color += 100; } } diff --git a/lib/widget.js b/lib/widget.js index 5ec1c05..bb3b3d2 100644 --- a/lib/widget.js +++ b/lib/widget.js @@ -37,7 +37,8 @@ widget.classes = [ 'Terminal', 'Image', 'Layout', - 'PNG' + 'PNG', + 'Video' ]; widget.classes.forEach(function(name) { diff --git a/lib/widgets/terminal.js b/lib/widgets/terminal.js index 1930eb2..8a494a3 100644 --- a/lib/widgets/terminal.js +++ b/lib/widgets/terminal.js @@ -197,6 +197,10 @@ Terminal.prototype.bootstrap = function() { self.term.resize(self.width - self.iwidth, self.height - self.iheight); }); + this.on('destroy', function() { + self.kill(); + }); + if (this.handler) { return; } @@ -206,12 +210,16 @@ Terminal.prototype.bootstrap = function() { cols: this.width - this.iwidth, rows: this.height - this.iheight, cwd: process.env.HOME, - env: process.env + env: this.options.env || process.env }); this.on('resize', function() { nextTick(function() { - self.pty.resize(self.width - self.iwidth, self.height - self.iheight); + try { + self.pty.resize(self.width - self.iwidth, self.height - self.iheight); + } catch (e) { + ; + } }); }); @@ -379,6 +387,14 @@ Terminal.prototype.screenshot = function(xi, xl, yi, yl) { return this.screen.screenshot(xi, xl, yi, yl, this.term); }; +Terminal.prototype.kill = function() { + if (this.pty) { + this.pty.destroy(); + this.pty.kill(); + } + this.term.write('\x1b[H\x1b[2J'); +}; + /** * Expose */ diff --git a/lib/widgets/video.js b/lib/widgets/video.js new file mode 100644 index 0000000..5881565 --- /dev/null +++ b/lib/widgets/video.js @@ -0,0 +1,122 @@ +/** + * video.js - video element for blessed + * Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License). + * https://github.com/chjj/blessed + */ + +/** + * Modules + */ + +var cp = require('child_process'); + +var nextTick = global.setImmediate || process.nextTick.bind(process); + +var helpers = require('../helpers'); + +var Node = require('./node'); +var Box = require('./box'); +var Terminal = require('./terminal'); + +/** + * Video + */ + +function Video(options) { + var self = this + , shell + , args; + + if (!(this instanceof Node)) { + return new Video(options); + } + + options = options || {}; + + Box.call(this, options); + + if (this.exists('mplayer')) { + shell = 'mplayer'; + args = ['-vo', 'caca', '-quiet', options.file]; + } else if (this.exists('mpv')) { + shell = 'mpv'; + args = ['--vo', 'caca', '--really-quiet', options.file]; + } else { + this.parseTags = true; + this.setContent('{red-fg}{bold}Error:{/bold}' + + ' mplayer or mpv not installed.{/red-fg}'); + return this; + } + + var opts = { + parent: this, + left: 0, + top: 0, + width: this.width - this.iwidth, + height: this.height - this.iheight, + shell: shell, + args: args.slice() + }; + + this.now = Date.now() / 1000 | 0; + this.start = opts.start || 0; + if (this.start) { + opts.args.unshift('--start', this.start + ''); + } + + var DISPLAY = process.env.DISPLAY; + delete process.env.DISPLAY; + this.tty = new Terminal(opts); + process.env.DISPLAY = DISPLAY; + + this.on('click', function() { + self.tty.pty.write('p'); + }); + + // mplayer/mpv cannot resize itself in the terminal, so we have + // to restart it at the correct start time. + this.on('resize', function() { + self.tty.destroy(); + + var opts = { + parent: self, + left: 0, + top: 0, + width: self.width - self.iwidth, + height: self.height - self.iheight, + shell: shell, + args: args.slice() + }; + + var watched = (Date.now() / 1000 | 0) - self.now; + self.now = Date.now() / 1000 | 0; + self.start += watched; + opts.args.unshift('--start', self.start + ''); + + var DISPLAY = process.env.DISPLAY; + delete process.env.DISPLAY; + self.tty = new Terminal(opts); + process.env.DISPLAY = DISPLAY; + self.screen.render(); + }); +} + +Video.prototype.__proto__ = Box.prototype; + +Video.prototype.type = 'video'; + +Video.prototype.exists = function(program) { + try { + return !!+cp.execSync('type ' + + program + ' > /dev/null 2> /dev/null' + + ' && echo 1', { encoding: 'utf8' }).trim(); + } catch (e) { + return false; + } +}; + +/** + * Expose + */ + +module.exports = Video; diff --git a/test/widget-video.js b/test/widget-video.js new file mode 100644 index 0000000..b0b705e --- /dev/null +++ b/test/widget-video.js @@ -0,0 +1,26 @@ +var blessed = require('../'); +var fs = require('fs'); + +var screen = blessed.screen({ + tput: true, + smartCSR: true, + dump: __dirname + '/logs/video.log' +}); + +var video = blessed.video({ + parent: screen, + left: 1, + top: 1, + width: '90%', + height: '90%', + border: 'line', + file: process.argv[2] +}); + +video.focus(); + +screen.render(); + +screen.key(['q', 'C-q', 'C-c'], function() { + process.exit(0); +});