Filmout supports still images. Uses FFMPEG to convert to png, still. Should use sharp and re-sample the image to the maximum allowed for the screen in the smallest dimension.
This commit is contained in:
parent
0f52812767
commit
b5da7ba233
|
@ -1,5 +1,19 @@
|
|||
'use strict';
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const sharp_1 = __importDefault(require("sharp"));
|
||||
const animated = __importStar(require("animated-gif-detector"));
|
||||
const path_1 = require("path");
|
||||
const fs_extra_1 = require("fs-extra");
|
||||
const delay_1 = require("delay");
|
||||
class FilmOut {
|
||||
/**
|
||||
|
@ -7,9 +21,13 @@ class FilmOut {
|
|||
**/
|
||||
constructor(display, ffmpeg, ffprobe, ui, light) {
|
||||
this.id = 'filmout';
|
||||
this.videoExtensions = ['.mpg', '.mpeg', '.mov', '.mkv', '.avi', '.mp4'];
|
||||
this.stillExtensions = ['.tif', '.tiff', '.png', '.jpg', '.jpeg', '.bmp'];
|
||||
this.gifExtension = '.gif';
|
||||
this.state = {
|
||||
frame: 0,
|
||||
frames: 0,
|
||||
still: false,
|
||||
path: null,
|
||||
fileName: null,
|
||||
info: {},
|
||||
|
@ -56,6 +74,9 @@ class FilmOut {
|
|||
**/
|
||||
async move() {
|
||||
let start = +new Date();
|
||||
if (this.state.still) {
|
||||
return false;
|
||||
}
|
||||
if (this.state.dir) {
|
||||
this.state.frame++;
|
||||
}
|
||||
|
@ -89,8 +110,8 @@ class FilmOut {
|
|||
await delay_1.delay(20);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
*
|
||||
**/
|
||||
async end() {
|
||||
await delay_1.delay(20);
|
||||
this.display.hide();
|
||||
|
@ -100,26 +121,67 @@ class FilmOut {
|
|||
*
|
||||
**/
|
||||
async onConnect(evt, arg) {
|
||||
let info;
|
||||
let frames = 0;
|
||||
try {
|
||||
info = await this.ffprobe.info(arg.path);
|
||||
let isAnimated = false;
|
||||
let info;
|
||||
let ext;
|
||||
ext = path_1.extname(arg.fileName.toLowerCase());
|
||||
console.dir(arg);
|
||||
console.log(ext);
|
||||
if (ext === this.gifExtension) {
|
||||
try {
|
||||
isAnimated = await this.isGifAnimated(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
this.state.still = !isAnimated;
|
||||
}
|
||||
catch (err) {
|
||||
//this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
else if (this.stillExtensions.indexOf(ext) !== -1) {
|
||||
this.state.still = true;
|
||||
}
|
||||
else if (this.videoExtensions.indexOf(ext) !== -1) {
|
||||
this.state.still = false;
|
||||
}
|
||||
else {
|
||||
this.log.error(`File is not of a valid file type`, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
frames = await this.ffprobe.frames(arg.path);
|
||||
if (this.state.still) {
|
||||
try {
|
||||
info = await this.stillInfo(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
frames = 1;
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
else {
|
||||
try {
|
||||
info = await this.ffprobe.info(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
frames = await this.ffprobe.frames(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
console.dir(info);
|
||||
this.state.frame = 0;
|
||||
this.state.path = arg.path;
|
||||
this.state.fileName = arg.fileName;
|
||||
|
@ -130,6 +192,29 @@ class FilmOut {
|
|||
this.state.enabled = true;
|
||||
return await this.ui.send(this.id, { valid: true, state: JSON.stringify(this.state) });
|
||||
}
|
||||
/**
|
||||
* Return true if gif is animated, false if it is a still
|
||||
**/
|
||||
async isGifAnimated(pathStr) {
|
||||
let gifBuffer;
|
||||
try {
|
||||
gifBuffer = await fs_extra_1.readFile(pathStr);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
return animated(gifBuffer);
|
||||
}
|
||||
/**
|
||||
* Return information on a still image using the sharp module
|
||||
**/
|
||||
async stillInfo(pathStr) {
|
||||
return sharp_1.default(pathStr).metadata();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async previewFrame(evt, arg) {
|
||||
const state = JSON.parse(JSON.stringify(this.state));
|
||||
let path;
|
||||
|
@ -144,6 +229,9 @@ class FilmOut {
|
|||
}
|
||||
this.ui.send('preview_frame', { path, frame: arg.frame });
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async preview(evt, arg) {
|
||||
const state = JSON.parse(JSON.stringify(this.state));
|
||||
let path;
|
||||
|
@ -164,6 +252,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async focus(evt, arg) {
|
||||
this.log.info(`Showing focus screen`);
|
||||
try {
|
||||
|
@ -174,6 +265,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async field(evt, arg) {
|
||||
this.log.info(`Showing field guide screen`);
|
||||
try {
|
||||
|
@ -184,6 +278,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async meter(evt, arg) {
|
||||
this.log.info(`Showing meter screen`);
|
||||
try {
|
||||
|
@ -194,6 +291,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async close(evt, arg) {
|
||||
try {
|
||||
await this.display.hide();
|
||||
|
@ -203,6 +303,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
onDisplay(evt, arg) {
|
||||
this.display.change(arg.display);
|
||||
this.log.info(`Changing the display to ${arg.display}`);
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -34,6 +34,8 @@ let filmout;
|
|||
class FilmOut {
|
||||
constructor() {
|
||||
this.id = 'filmout';
|
||||
this.extensions = ['.mpg', '.mpeg', '.mov', '.mkv', '.avi', '.mp4', '.gif',
|
||||
'.tif', '.tiff', '.png', '.jpg', '.jpeg', '.bmp'];
|
||||
this.displays = [];
|
||||
this.state = {
|
||||
frame: 0,
|
||||
|
@ -99,13 +101,12 @@ class FilmOut {
|
|||
$('#filmout_stats_monitor_size').text(`${display.width} x ${display.height}`);
|
||||
$('#filmout_stats_monitor_aspect').text(`${aspect}`);
|
||||
$('#filmout_stats_monitor_scale').text(`${parseFloat(display.scale).toFixed(1)} scale factor`);
|
||||
console.dir(display);
|
||||
//console.dir(display);
|
||||
this.state.display = id;
|
||||
ipcRenderer.send('display', { display: id });
|
||||
}
|
||||
selectFile() {
|
||||
const elem = $('#digital');
|
||||
const extensions = ['mpg', 'mpeg', 'mov', 'mkv', 'avi', 'mp4'];
|
||||
dialog.showOpenDialog({
|
||||
title: `Select video or image sequence`,
|
||||
properties: [`openFile`],
|
||||
|
@ -120,19 +121,18 @@ class FilmOut {
|
|||
if (!files)
|
||||
return false;
|
||||
let valid = false;
|
||||
let path = files[0];
|
||||
let pathStr = files[0];
|
||||
let displayName;
|
||||
if (path && path !== '') {
|
||||
for (let ext of extensions) {
|
||||
if (path.toLowerCase().indexOf(`.${ext}`) !== -1) {
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
if (!valid)
|
||||
let ext;
|
||||
if (pathStr && pathStr !== '') {
|
||||
ext = path.extname(pathStr.toLowerCase());
|
||||
valid = this.extensions.indexOf(ext) === -1 ? false : true;
|
||||
if (!valid) {
|
||||
return false;
|
||||
log.info(`Selected video ${path.split('/').pop()}`, 'DIGITAL', true);
|
||||
elem.attr('data-file', path);
|
||||
displayName = path.split('/').pop();
|
||||
}
|
||||
log.info(`Selected video ${pathStr.split('/').pop()}`, 'DIGITAL', true);
|
||||
elem.attr('data-file', pathStr);
|
||||
displayName = pathStr.split('/').pop();
|
||||
elem.val(displayName);
|
||||
$('#filmout_file').val(displayName);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ const notifier = require('node-notifier');
|
|||
const fs = require('fs');
|
||||
const uuid = require('uuid').v4;
|
||||
const moment = require('moment');
|
||||
const path = require('path');
|
||||
const humanizeDuration = require('humanize-duration');
|
||||
const PACKAGE = require('./package.json');
|
||||
const cfg = require('./data/cfg.json');
|
||||
|
|
|
@ -13,8 +13,12 @@ declare var proj : any;
|
|||
declare var grid : any;
|
||||
declare var dialog : any;
|
||||
declare var ipcRenderer : any;
|
||||
declare var path : any;
|
||||
|
||||
function gcd (a : number, b : number) {
|
||||
/**
|
||||
* Determine the greatest common denominator
|
||||
*/
|
||||
function gcd (a : number, b : number) : any {
|
||||
if (b === 0) return a;
|
||||
return gcd(b, a % b);
|
||||
}
|
||||
|
@ -49,6 +53,9 @@ let filmout : FilmOut;
|
|||
|
||||
class FilmOut {
|
||||
private id : string = 'filmout';
|
||||
private extensions : string[] = ['.mpg', '.mpeg', '.mov', '.mkv', '.avi', '.mp4',
|
||||
'.gif',
|
||||
'.tif', '.tiff', '.png', '.jpg', '.jpeg', '.bmp'];
|
||||
private displays : any[] = [];
|
||||
private state : any = {
|
||||
frame : 0,
|
||||
|
@ -100,6 +107,7 @@ class FilmOut {
|
|||
const w : number = display.width / scale;
|
||||
const elem : any = $('#filmout_monitor');
|
||||
const aspect : any = reduceRatio(display.width, display.height);
|
||||
|
||||
let h : number;
|
||||
let top : number;
|
||||
|
||||
|
@ -120,13 +128,12 @@ class FilmOut {
|
|||
$('#filmout_stats_monitor_size').text(`${display.width} x ${display.height}`);
|
||||
$('#filmout_stats_monitor_aspect').text(`${aspect}`);
|
||||
$('#filmout_stats_monitor_scale').text(`${parseFloat(display.scale).toFixed(1)} scale factor`);
|
||||
console.dir(display);
|
||||
//console.dir(display);
|
||||
this.state.display = id;
|
||||
ipcRenderer.send('display', { display : id });
|
||||
}
|
||||
selectFile () {
|
||||
const elem : any = $('#digital');
|
||||
const extensions : string[] = ['mpg', 'mpeg', 'mov', 'mkv', 'avi', 'mp4'];
|
||||
dialog.showOpenDialog({
|
||||
title : `Select video or image sequence`,
|
||||
properties : [`openFile`], // openDirectory, multiSelection, openFile
|
||||
|
@ -140,18 +147,18 @@ class FilmOut {
|
|||
}, (files : string[]) => {
|
||||
if (!files) return false;
|
||||
let valid : boolean = false;
|
||||
let path : string = files[0];
|
||||
let pathStr : string = files[0];
|
||||
let displayName : string;
|
||||
if (path && path !== '') {
|
||||
for (let ext of extensions) {
|
||||
if (path.toLowerCase().indexOf(`.${ext}`) !== -1) {
|
||||
valid = true;
|
||||
}
|
||||
let ext : string;
|
||||
if (pathStr && pathStr !== '') {
|
||||
ext = path.extname(pathStr.toLowerCase());
|
||||
valid = this.extensions.indexOf(ext) === -1 ? false : true;
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
if (!valid) return false;
|
||||
log.info(`Selected video ${path.split('/').pop()}`, 'DIGITAL', true);
|
||||
elem.attr('data-file', path);
|
||||
displayName = path.split('/').pop();
|
||||
log.info(`Selected video ${pathStr.split('/').pop()}`, 'DIGITAL', true);
|
||||
elem.attr('data-file', pathStr);
|
||||
displayName = pathStr.split('/').pop();
|
||||
elem.val(displayName);
|
||||
$('#filmout_file').val(displayName);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
'use strict';
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const sharp_1 = __importDefault(require("sharp"));
|
||||
const animated = __importStar(require("animated-gif-detector"));
|
||||
const path_1 = require("path");
|
||||
const fs_extra_1 = require("fs-extra");
|
||||
const delay_1 = require("delay");
|
||||
class FilmOut {
|
||||
/**
|
||||
|
@ -7,9 +21,13 @@ class FilmOut {
|
|||
**/
|
||||
constructor(display, ffmpeg, ffprobe, ui, light) {
|
||||
this.id = 'filmout';
|
||||
this.videoExtensions = ['.mpg', '.mpeg', '.mov', '.mkv', '.avi', '.mp4'];
|
||||
this.stillExtensions = ['.tif', '.tiff', '.png', '.jpg', '.jpeg', '.bmp'];
|
||||
this.gifExtension = '.gif';
|
||||
this.state = {
|
||||
frame: 0,
|
||||
frames: 0,
|
||||
still: false,
|
||||
path: null,
|
||||
fileName: null,
|
||||
info: {},
|
||||
|
@ -56,6 +74,9 @@ class FilmOut {
|
|||
**/
|
||||
async move() {
|
||||
let start = +new Date();
|
||||
if (this.state.still) {
|
||||
return false;
|
||||
}
|
||||
if (this.state.dir) {
|
||||
this.state.frame++;
|
||||
}
|
||||
|
@ -89,8 +110,8 @@ class FilmOut {
|
|||
await delay_1.delay(20);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
*
|
||||
**/
|
||||
async end() {
|
||||
await delay_1.delay(20);
|
||||
this.display.hide();
|
||||
|
@ -100,26 +121,67 @@ class FilmOut {
|
|||
*
|
||||
**/
|
||||
async onConnect(evt, arg) {
|
||||
let info;
|
||||
let frames = 0;
|
||||
try {
|
||||
info = await this.ffprobe.info(arg.path);
|
||||
let isAnimated = false;
|
||||
let info;
|
||||
let ext;
|
||||
ext = path_1.extname(arg.fileName.toLowerCase());
|
||||
console.dir(arg);
|
||||
console.log(ext);
|
||||
if (ext === this.gifExtension) {
|
||||
try {
|
||||
isAnimated = await this.isGifAnimated(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
this.state.still = !isAnimated;
|
||||
}
|
||||
catch (err) {
|
||||
//this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
else if (this.stillExtensions.indexOf(ext) !== -1) {
|
||||
this.state.still = true;
|
||||
}
|
||||
else if (this.videoExtensions.indexOf(ext) !== -1) {
|
||||
this.state.still = false;
|
||||
}
|
||||
else {
|
||||
this.log.error(`File is not of a valid file type`, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
frames = await this.ffprobe.frames(arg.path);
|
||||
if (this.state.still) {
|
||||
try {
|
||||
info = await this.stillInfo(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
frames = 1;
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
else {
|
||||
try {
|
||||
info = await this.ffprobe.info(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
frames = await this.ffprobe.frames(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
console.dir(info);
|
||||
this.state.frame = 0;
|
||||
this.state.path = arg.path;
|
||||
this.state.fileName = arg.fileName;
|
||||
|
@ -130,6 +192,29 @@ class FilmOut {
|
|||
this.state.enabled = true;
|
||||
return await this.ui.send(this.id, { valid: true, state: JSON.stringify(this.state) });
|
||||
}
|
||||
/**
|
||||
* Return true if gif is animated, false if it is a still
|
||||
**/
|
||||
async isGifAnimated(pathStr) {
|
||||
let gifBuffer;
|
||||
try {
|
||||
gifBuffer = await fs_extra_1.readFile(pathStr);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
return animated(gifBuffer);
|
||||
}
|
||||
/**
|
||||
* Return information on a still image using the sharp module
|
||||
**/
|
||||
async stillInfo(pathStr) {
|
||||
return sharp_1.default(pathStr).metadata();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async previewFrame(evt, arg) {
|
||||
const state = JSON.parse(JSON.stringify(this.state));
|
||||
let path;
|
||||
|
@ -144,6 +229,9 @@ class FilmOut {
|
|||
}
|
||||
this.ui.send('preview_frame', { path, frame: arg.frame });
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async preview(evt, arg) {
|
||||
const state = JSON.parse(JSON.stringify(this.state));
|
||||
let path;
|
||||
|
@ -164,6 +252,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async focus(evt, arg) {
|
||||
this.log.info(`Showing focus screen`);
|
||||
try {
|
||||
|
@ -174,6 +265,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async field(evt, arg) {
|
||||
this.log.info(`Showing field guide screen`);
|
||||
try {
|
||||
|
@ -184,6 +278,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async meter(evt, arg) {
|
||||
this.log.info(`Showing meter screen`);
|
||||
try {
|
||||
|
@ -194,6 +291,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async close(evt, arg) {
|
||||
try {
|
||||
await this.display.hide();
|
||||
|
@ -203,6 +303,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
onDisplay(evt, arg) {
|
||||
this.display.change(arg.display);
|
||||
this.log.info(`Changing the display to ${arg.display}`);
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,5 +1,19 @@
|
|||
'use strict';
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const sharp_1 = __importDefault(require("sharp"));
|
||||
const animated = __importStar(require("animated-gif-detector"));
|
||||
const path_1 = require("path");
|
||||
const fs_extra_1 = require("fs-extra");
|
||||
const delay_1 = require("delay");
|
||||
class FilmOut {
|
||||
/**
|
||||
|
@ -7,9 +21,13 @@ class FilmOut {
|
|||
**/
|
||||
constructor(display, ffmpeg, ffprobe, ui, light) {
|
||||
this.id = 'filmout';
|
||||
this.videoExtensions = ['.mpg', '.mpeg', '.mov', '.mkv', '.avi', '.mp4'];
|
||||
this.stillExtensions = ['.tif', '.tiff', '.png', '.jpg', '.jpeg', '.bmp'];
|
||||
this.gifExtension = '.gif';
|
||||
this.state = {
|
||||
frame: 0,
|
||||
frames: 0,
|
||||
still: false,
|
||||
path: null,
|
||||
fileName: null,
|
||||
info: {},
|
||||
|
@ -56,6 +74,9 @@ class FilmOut {
|
|||
**/
|
||||
async move() {
|
||||
let start = +new Date();
|
||||
if (this.state.still) {
|
||||
return false;
|
||||
}
|
||||
if (this.state.dir) {
|
||||
this.state.frame++;
|
||||
}
|
||||
|
@ -89,8 +110,8 @@ class FilmOut {
|
|||
await delay_1.delay(20);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
*
|
||||
**/
|
||||
async end() {
|
||||
await delay_1.delay(20);
|
||||
this.display.hide();
|
||||
|
@ -100,26 +121,67 @@ class FilmOut {
|
|||
*
|
||||
**/
|
||||
async onConnect(evt, arg) {
|
||||
let info;
|
||||
let frames = 0;
|
||||
try {
|
||||
info = await this.ffprobe.info(arg.path);
|
||||
let isAnimated = false;
|
||||
let info;
|
||||
let ext;
|
||||
ext = path_1.extname(arg.fileName.toLowerCase());
|
||||
console.dir(arg);
|
||||
console.log(ext);
|
||||
if (ext === this.gifExtension) {
|
||||
try {
|
||||
isAnimated = await this.isGifAnimated(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
this.state.still = !isAnimated;
|
||||
}
|
||||
catch (err) {
|
||||
//this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
else if (this.stillExtensions.indexOf(ext) !== -1) {
|
||||
this.state.still = true;
|
||||
}
|
||||
else if (this.videoExtensions.indexOf(ext) !== -1) {
|
||||
this.state.still = false;
|
||||
}
|
||||
else {
|
||||
this.log.error(`File is not of a valid file type`, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
frames = await this.ffprobe.frames(arg.path);
|
||||
if (this.state.still) {
|
||||
try {
|
||||
info = await this.stillInfo(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
frames = 1;
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
else {
|
||||
try {
|
||||
info = await this.ffprobe.info(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
frames = await this.ffprobe.frames(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
console.dir(info);
|
||||
this.state.frame = 0;
|
||||
this.state.path = arg.path;
|
||||
this.state.fileName = arg.fileName;
|
||||
|
@ -130,6 +192,29 @@ class FilmOut {
|
|||
this.state.enabled = true;
|
||||
return await this.ui.send(this.id, { valid: true, state: JSON.stringify(this.state) });
|
||||
}
|
||||
/**
|
||||
* Return true if gif is animated, false if it is a still
|
||||
**/
|
||||
async isGifAnimated(pathStr) {
|
||||
let gifBuffer;
|
||||
try {
|
||||
gifBuffer = await fs_extra_1.readFile(pathStr);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
return animated(gifBuffer);
|
||||
}
|
||||
/**
|
||||
* Return information on a still image using the sharp module
|
||||
**/
|
||||
async stillInfo(pathStr) {
|
||||
return sharp_1.default(pathStr).metadata();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async previewFrame(evt, arg) {
|
||||
const state = JSON.parse(JSON.stringify(this.state));
|
||||
let path;
|
||||
|
@ -144,6 +229,9 @@ class FilmOut {
|
|||
}
|
||||
this.ui.send('preview_frame', { path, frame: arg.frame });
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async preview(evt, arg) {
|
||||
const state = JSON.parse(JSON.stringify(this.state));
|
||||
let path;
|
||||
|
@ -164,6 +252,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async focus(evt, arg) {
|
||||
this.log.info(`Showing focus screen`);
|
||||
try {
|
||||
|
@ -174,6 +265,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async field(evt, arg) {
|
||||
this.log.info(`Showing field guide screen`);
|
||||
try {
|
||||
|
@ -184,6 +278,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async meter(evt, arg) {
|
||||
this.log.info(`Showing meter screen`);
|
||||
try {
|
||||
|
@ -194,6 +291,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async close(evt, arg) {
|
||||
try {
|
||||
await this.display.hide();
|
||||
|
@ -203,6 +303,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
onDisplay(evt, arg) {
|
||||
this.display.change(arg.display);
|
||||
this.log.info(`Changing the display to ${arg.display}`);
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,12 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
import sharp from 'sharp';
|
||||
import * as animated from 'animated-gif-detector';
|
||||
import { extname } from 'path';
|
||||
import { readFile } from 'fs-extra';
|
||||
import { delay } from 'delay';
|
||||
|
||||
class FilmOut {
|
||||
private id : string = 'filmout';
|
||||
private videoExtensions : string[] = ['.mpg', '.mpeg', '.mov', '.mkv', '.avi', '.mp4'];
|
||||
private stillExtensions : string[] = ['.tif', '.tiff', '.png', '.jpg', '.jpeg', '.bmp'];
|
||||
private gifExtension : string = '.gif';
|
||||
public state : any = {
|
||||
frame : 0,
|
||||
frames : 0,
|
||||
still : false,
|
||||
path : null,
|
||||
fileName : null,
|
||||
info : {},
|
||||
|
@ -45,6 +53,7 @@ class FilmOut {
|
|||
**/
|
||||
private listen () {
|
||||
this.ipc.on(this.id, this.onConnect.bind(this));
|
||||
|
||||
this.ipc.on('focus', this.focus.bind(this));
|
||||
this.ipc.on('field', this.field.bind(this));
|
||||
this.ipc.on('meter', this.meter.bind(this));
|
||||
|
@ -64,6 +73,9 @@ class FilmOut {
|
|||
**/
|
||||
public async move () {
|
||||
let start : number = +new Date();
|
||||
if (this.state.still) {
|
||||
return false;
|
||||
}
|
||||
if (this.state.dir) {
|
||||
this.state.frame++;
|
||||
} else {
|
||||
|
@ -94,7 +106,7 @@ class FilmOut {
|
|||
await this.display.show(this.state.frame);
|
||||
await delay(20);
|
||||
}
|
||||
/**
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private async end () {
|
||||
|
@ -106,26 +118,64 @@ class FilmOut {
|
|||
*
|
||||
**/
|
||||
async onConnect (evt : any, arg : any) {
|
||||
let info;
|
||||
let frames = 0;
|
||||
let frames : number = 0;
|
||||
let isAnimated : boolean = false;
|
||||
let info : any;
|
||||
let ext : string;
|
||||
|
||||
try {
|
||||
info = await this.ffprobe.info(arg.path);
|
||||
} catch (err) {
|
||||
//this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid : false });
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
frames = await this.ffprobe.frames(arg.path);
|
||||
} catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid : false });
|
||||
ext = extname(arg.fileName.toLowerCase());
|
||||
|
||||
console.dir(arg)
|
||||
console.log(ext)
|
||||
|
||||
if (ext === this.gifExtension) {
|
||||
try {
|
||||
isAnimated = await this.isGifAnimated(arg.path);
|
||||
} catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
await this.ui.send(this.id, { valid : false });
|
||||
return false;
|
||||
}
|
||||
this.state.still = !isAnimated;
|
||||
} else if (this.stillExtensions.indexOf(ext) !== -1) {
|
||||
this.state.still = true;
|
||||
} else if (this.videoExtensions.indexOf(ext) !== -1) {
|
||||
this.state.still = false;
|
||||
} else {
|
||||
this.log.error(`File is not of a valid file type`, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.state.still) {
|
||||
try {
|
||||
info = await this.stillInfo(arg.path);
|
||||
} catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid : false });
|
||||
return false;
|
||||
}
|
||||
frames = 1;
|
||||
} else {
|
||||
try {
|
||||
info = await this.ffprobe.info(arg.path);
|
||||
} catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid : false });
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
frames = await this.ffprobe.frames(arg.path);
|
||||
} catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid : false });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
console.dir(info)
|
||||
this.state.frame = 0;
|
||||
this.state.path = arg.path;
|
||||
this.state.fileName = arg.fileName;
|
||||
|
@ -137,7 +187,28 @@ class FilmOut {
|
|||
this.state.enabled = true;
|
||||
return await this.ui.send(this.id, { valid : true, state : JSON.stringify(this.state) });
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if gif is animated, false if it is a still
|
||||
**/
|
||||
async isGifAnimated (pathStr : string) {
|
||||
let gifBuffer : Buffer;
|
||||
try {
|
||||
gifBuffer = await readFile(pathStr);
|
||||
} catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
return animated(gifBuffer);
|
||||
}
|
||||
/**
|
||||
* Return information on a still image using the sharp module
|
||||
**/
|
||||
async stillInfo (pathStr : string) {
|
||||
return sharp(pathStr).metadata();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async previewFrame (evt : any, arg : any) {
|
||||
const state : any = JSON.parse(JSON.stringify(this.state));
|
||||
let path : string;
|
||||
|
@ -152,7 +223,9 @@ class FilmOut {
|
|||
}
|
||||
this.ui.send('preview_frame', { path, frame : arg.frame })
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async preview (evt : any, arg : any) {
|
||||
const state : any = JSON.parse(JSON.stringify(this.state));
|
||||
let path : string;
|
||||
|
@ -174,7 +247,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async focus (evt : any, arg : any) {
|
||||
this.log.info(`Showing focus screen`);
|
||||
try {
|
||||
|
@ -184,7 +259,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async field (evt : any, arg : any) {
|
||||
this.log.info(`Showing field guide screen`);
|
||||
try {
|
||||
|
@ -194,7 +271,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async meter (evt : any, arg : any) {
|
||||
this.log.info(`Showing meter screen`);
|
||||
try {
|
||||
|
@ -204,7 +283,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async close (evt : any, arg : any) {
|
||||
try {
|
||||
await this.display.hide();
|
||||
|
@ -213,7 +294,9 @@ class FilmOut {
|
|||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
onDisplay (evt : any, arg : any) {
|
||||
this.display.change(arg.display);
|
||||
this.log.info(`Changing the display to ${arg.display}`);
|
||||
|
|
Loading…
Reference in New Issue