Explorar el Código

use gifski for mp4

Mike L hace 3 años
padre
commit
b25da3be76
Se han modificado 4 ficheros con 126 adiciones y 2 borrados
  1. 64 0
      dist/gifski.js
  2. 4 1
      dist/wiki.js
  3. 53 0
      src/gifski.ts
  4. 5 1
      src/wiki.ts

+ 64 - 0
dist/gifski.js

@@ -0,0 +1,64 @@
+"use strict";
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const child_process_1 = require("child_process");
+const fs_1 = require("fs");
+const loggers_1 = require("./loggers");
+const logger = (0, loggers_1.getLogger)('gifski');
+const sizeLimit = 10 * Math.pow(2, 20);
+const roundToEven = (n) => Math.ceil(n / 2) * 2;
+exports.default = (inputFilePath, targetWidth) => __awaiter(void 0, void 0, void 0, function* () {
+    const outputFilePath = inputFilePath.replace(/(?:\.[^.]*)?$/, '.gif');
+    try {
+        const args = [
+            inputFilePath,
+            '-o',
+            outputFilePath,
+            '--fps',
+            '12.5',
+            '--quiet',
+            '--quality',
+            '90',
+        ];
+        if (typeof (targetWidth) === 'number') {
+            args.push('--width', roundToEven(targetWidth).toString());
+        }
+        logger.info(` gifski ${args.join(' ')}`);
+        const gifskiSpawn = (0, child_process_1.spawn)('gifski', args);
+        const gifskiResult = new Promise((resolve, reject) => {
+            const sizeChecker = setInterval(() => {
+                if ((0, fs_1.existsSync)(outputFilePath) && (0, fs_1.statSync)(outputFilePath).size > sizeLimit)
+                    gifskiSpawn.kill();
+            }, 5000);
+            gifskiSpawn.on('exit', () => {
+                clearInterval(sizeChecker);
+                if (!(0, fs_1.existsSync)(outputFilePath) || (0, fs_1.statSync)(outputFilePath).size === 0)
+                    return reject('no file was created on exit');
+                logger.info(`gif conversion succeeded, file path: ${outputFilePath}`);
+                resolve(outputFilePath);
+            });
+        });
+        const stderr = [];
+        gifskiSpawn.stderr.on('data', errdata => stderr.push(errdata));
+        gifskiSpawn.stderr.on('end', () => {
+            if (stderr.length !== 0) {
+                if (!gifskiSpawn.killed)
+                    gifskiSpawn.kill();
+                throw Error(Buffer.concat(stderr).toString());
+            }
+        });
+        return yield gifskiResult;
+    }
+    catch (error) {
+        logger.error(`error converting video to gif ${error ? `message: ${error}` : ''}`);
+        throw Error('error converting video to gif');
+    }
+});

+ 4 - 1
dist/wiki.js

@@ -6,6 +6,7 @@ const fs_1 = require("fs");
 const mediawiki2_1 = require("mediawiki2");
 const node_fetch_1 = require("node-fetch");
 const playwright_1 = require("playwright");
+const gifski_1 = require("./gifski");
 const loggers_1 = require("./loggers");
 const twitter_1 = require("./twitter");
 const logger = (0, loggers_1.getLogger)('wiki');
@@ -68,7 +69,9 @@ class default_1 {
                 if (ext) {
                     const mediaFileName = `${filename}.${ext}`;
                     (0, fs_1.writeFileSync)(mediaFileName, Buffer.from(data));
-                    return mediaFileName;
+                    return (ext === 'mp4' ?
+                        (0, gifski_1.default)(mediaFileName) :
+                        Promise.resolve(mediaFileName));
                 }
                 logger.warn('unable to find MIME type of fetched media, failing this fetch');
                 throw Error();

+ 53 - 0
src/gifski.ts

@@ -0,0 +1,53 @@
+import { spawn } from 'child_process';
+import { existsSync, statSync } from 'fs';
+
+import { getLogger } from './loggers';
+
+const logger = getLogger('gifski');
+
+const sizeLimit = 10 * 2 ** 20;
+const roundToEven = (n: number) => Math.ceil(n / 2) * 2;
+
+export default async (inputFilePath: string, targetWidth?: number) => {
+  const outputFilePath = inputFilePath.replace(/(?:\.[^.]*)?$/, '.gif')
+  try {
+    const args = [
+      inputFilePath,
+      '-o',
+      outputFilePath,
+      '--fps',
+      '12.5',
+      '--quiet',
+      '--quality',
+      '90',
+    ];
+    if (typeof(targetWidth) === 'number') {
+      args.push('--width', roundToEven(targetWidth).toString());
+    }
+    logger.info(` gifski ${args.join(' ')}`);
+    const gifskiSpawn = spawn('gifski', args);
+    const gifskiResult = new Promise<string>((resolve, reject) => {
+      const sizeChecker = setInterval(() => {
+        if (existsSync(outputFilePath) && statSync(outputFilePath).size > sizeLimit) gifskiSpawn.kill();
+      }, 5000);
+      gifskiSpawn.on('exit', () => {
+        clearInterval(sizeChecker);
+        if (!existsSync(outputFilePath) || statSync(outputFilePath).size === 0) return reject('no file was created on exit');
+        logger.info(`gif conversion succeeded, file path: ${outputFilePath}`);
+        resolve(outputFilePath);
+      });
+    });
+    const stderr = [];
+    gifskiSpawn.stderr.on('data', errdata => stderr.push(errdata));
+    gifskiSpawn.stderr.on('end', () => {
+      if (stderr.length !== 0) {
+        if (!gifskiSpawn.killed) gifskiSpawn.kill();
+        throw Error(Buffer.concat(stderr).toString());
+      }
+    });
+    return await gifskiResult;
+  } catch (error) {
+    logger.error(`error converting video to gif ${error ? `message: ${error}` : ''}`);
+    throw Error('error converting video to gif');
+  }
+};

+ 5 - 1
src/wiki.ts

@@ -5,6 +5,7 @@ import { MWBot, WikiError } from 'mediawiki2';
 import nodeFetch from 'node-fetch';
 import { firefox } from 'playwright';
 import { CookieJar } from 'tough-cookie';
+import gifski from './gifski';
 
 import { getLogger } from './loggers';
 import { Tweet, processTweetBody } from './twitter';
@@ -81,7 +82,10 @@ export default class {
         if (ext) {
           const mediaFileName = `${filename}.${ext}`;
           writeFileSync(mediaFileName, Buffer.from(data));
-          return mediaFileName;
+          return (ext === 'mp4' ?
+            gifski(mediaFileName) :
+            Promise.resolve(mediaFileName)
+          );
         }
         logger.warn('unable to find MIME type of fetched media, failing this fetch');
         throw Error();