From ca098cdfeb3963533a3fcb53afd6ede847729344 Mon Sep 17 00:00:00 2001 From: rubegartor Date: Fri, 2 Feb 2024 00:22:22 +0100 Subject: [PATCH] Support Gopro HERO5 --- app/src/provider/Commons.js | 43 +++++++++++++++++++++++ app/src/provider/VideoProcessor.js | 55 ++++++++++++++++++++++++++---- 2 files changed, 91 insertions(+), 7 deletions(-) diff --git a/app/src/provider/Commons.js b/app/src/provider/Commons.js index d6491f5..b542ded 100644 --- a/app/src/provider/Commons.js +++ b/app/src/provider/Commons.js @@ -3,6 +3,11 @@ const fs = require('fs'); const moment = require('moment'); const {ipcRenderer} = require('electron'); +const HERO5LOW = 'hero5-'; +const HERO5HIGH = 'hero+'; +const HEROMAX = 'max'; +const NONE = 'undefined'; + module.exports = { /** * Function that returns if app is packaged or not (Only for main process) @@ -31,6 +36,32 @@ module.exports = { return dirContent; }, + /** + * Function that try to identify GoPro camera model based on file naming convention + * + * @param fileName + * @returns {string} + */ + identifyGoProModel(fileName) { + const validHERO5Pus = ['GH', 'GX']; + + for (const token of validHERO5Pus) { + if (fileName.startsWith(token)) { + return HERO5HIGH; + } + } + + if (fileName.startsWith('GS')) { + return HEROMAX; + } + + if (fileName.startsWith('GOPR') || fileName.startsWith('GP')) { + return HERO5LOW; + } + + return NONE; + }, + /** * Function that sorts gopro names (Main and render process) * Accepts a maximum number of 999 chapters @@ -40,6 +71,14 @@ module.exports = { */ sortGoProNames(arr) { return arr.sort(function (x, y) { + if (module.exports.identifyGoProModel(x) === HERO5LOW) { + return 1; + } + + if (module.exports.identifyGoProModel(y) === HERO5LOW) { + return -1; + } + x = isNaN(x.substring(1, 4)) ? x.substring(2, 4) : x.substring(1, 4); y = isNaN(y.substring(1, 4)) ? y.substring(2, 4) : y.substring(1, 4); @@ -107,5 +146,9 @@ module.exports = { return JSON.parse(JSON.stringify(array)) }, + HERO5LOW, + HERO5HIGH, + HEROMAX, + NONE, version } diff --git a/app/src/provider/VideoProcessor.js b/app/src/provider/VideoProcessor.js index 85dd417..d385ff7 100644 --- a/app/src/provider/VideoProcessor.js +++ b/app/src/provider/VideoProcessor.js @@ -316,7 +316,7 @@ class VideoProcessor { if (fs.existsSync(path.join(project.projectPath, outputNameToCheck))) { const dirFiles = Commons.readDir(path.join(project.projectPath)); - const fileRegex = /^(G[HXS]?(\d{6}|\d{7}))_joined(_\d*)?\.(MP4|mp4|360)/; + const fileRegex = /^(G(OPR)?[HXS]?(\d{6}|\d{7}|\d{4}))_joined(_\d*)?\.(MP4|mp4|360)/; let maxNumber = 1; for (const file of dirFiles) { @@ -542,13 +542,32 @@ class VideoProcessor { * @returns {{}} */ static scanGoProDir(dirPath) { + const HERO5LOWRegex = /^(G(OPR)?(P)?(\d{6}|\d{4}))\.(MP4|mp4)/; + const HERO5HIGHRegex = /^G[PHXS]?(\d{6}|\d{7})\.(MP4|mp4)/; + const MAXRegex = /^GS?(\d{6}|\d{7})\.360/; + const goProGroupedFiles = {}; const goProFiles = []; const files = Commons.readDir(dirPath); //Get GoPro files for (const file of files) { - if (/^(G[HXS]?(\d{6}|\d{7}))\.(MP4|mp4|360)/.test(file) && !goProFiles.includes(file)) { + let rgx; + switch (Commons.identifyGoProModel(file)) { + case Commons.HERO5LOW: + rgx = HERO5LOWRegex; + break; + case Commons.HERO5HIGH: + rgx = HERO5HIGHRegex; + break; + case Commons.HEROMAX: + rgx = MAXRegex; + break; + case Commons.NONE: + continue; + } + + if (rgx.test(file) && !goProFiles.includes(file)) { goProFiles.push(file); } } @@ -571,13 +590,10 @@ class VideoProcessor { //Check consecutive chapters in groups for (const [key, values] of Object.entries(goProGroupedFiles)) { - const firstValue = values[0]; - let lastChapterNum = parseInt(isNaN(firstValue.substring(1, 4)) ? firstValue.substring(2, 4) : firstValue.substring(1, 4)); + let lastChapterNum = this.getChapterNum(values[0]); for (const chapterFile of values) { - const chapterNum = isNaN(chapterFile.substring(1, 4)) ? chapterFile.substring(2, 4) : chapterFile.substring(1, 4); - - if (parseInt(chapterNum) !== lastChapterNum) { + if (this.getChapterNum(chapterFile) !== lastChapterNum) { throw new NotConsecutiveChaptersError(`Group (${key}) have not consecutive chapters`); } else { lastChapterNum++; @@ -588,6 +604,31 @@ class VideoProcessor { return goProGroupedFiles; } + + /** + * Function that gets chapter number of gopro file name + * + * @param chapterFile + * @returns {number} + */ + static getChapterNum(chapterFile) { + let chapterNum = 0; + + switch (Commons.identifyGoProModel(chapterFile)) { + case Commons.HERO5LOW: + if (!chapterFile.startsWith('GOPR')) { + chapterNum = isNaN(chapterFile.substring(1, 4)) ? chapterFile.substring(2, 4) : chapterFile.substring(1, 4); + } + break; + case Commons.HEROMAX: + case Commons.HERO5HIGH: + chapterNum = isNaN(chapterFile.substring(1, 4)) ? chapterFile.substring(2, 4) : chapterFile.substring(1, 4); + break; + } + + return Number(chapterNum); + } + /** * Function that generates the thumbnail of the project *