├── .gitattributes ├── .gitignore ├── AnimationBulletin.js ├── AnimationRun.js ├── DemoOutputVideos ├── Type-Photo!AlignH-Center!AlignV-Center!Crop-Full │ └── 1080p.mp4 ├── Type-Photo!AlignH-Left!AlignV-Top!Crop-Full │ └── 1080p.mp4 ├── Type-Photo!AlignH-Right!AlignV-Bottom!Crop-Full │ └── 1080p.mp4 ├── Type-Video!AlignH-Center!AlignV-Center!Crop-Full │ └── 1080p.mp4 ├── Type-Video!AlignH-Left!AlignV-Top!Crop-FitToFrame │ └── 1080p.mp4 ├── Type-Video!AlignH-Left!AlignV-Top!Crop-Full │ └── 1080p.mp4 ├── Type-Video!AlignH-Left!AlignV-Top!Crop-Left │ └── 1080p.mp4 ├── Type-Video!AlignH-Left!AlignV-Top!Crop-Right │ └── 1080p.mp4 └── Type-Video!AlignH-Right!AlignV-Bottom!Crop-Full │ └── 1080p.mp4 ├── LICENSE ├── README.md ├── app.js ├── assets ├── Audio │ └── audio.mpeg ├── Font │ ├── Roboto-Bold.ttf │ └── Roboto-Light.ttf ├── Footage │ └── id │ │ └── 720p-sample1.mp4 ├── Image │ └── id │ │ ├── block_1.jpg │ │ ├── block_3.jpg │ │ └── o.jpg ├── index.html └── template_index ├── classes └── Text.js ├── config.js ├── download └── id ├── ffmpeg_wrapper.js ├── fontcode ├── generate.js ├── metric.json ├── robotobold.json └── robotolight.json ├── multi_worker.js ├── package-lock.json ├── package.json ├── utils.js ├── worker.js └── workerChild.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # parcel-bundler cache (https://parceljs.org/) 61 | .cache 62 | 63 | # next.js build output 64 | .next 65 | 66 | # nuxt.js build output 67 | .nuxt 68 | 69 | # vuepress build output 70 | .vuepress/dist 71 | 72 | # Serverless directories 73 | .serverless 74 | 75 | # FuseBox cache 76 | .fusebox/ 77 | 78 | backup 79 | metrics 80 | fontcode/text.js 81 | fontcode/test.js -------------------------------------------------------------------------------- /AnimationBulletin.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const fs = require('fs'); 3 | const Utils = require('./utils'); 4 | const Config = require('./config'); 5 | const AnimationRun = require('./AnimationRun'); 6 | class AnimBulletin extends AnimationRun { 7 | reset = function (user, blockId) { 8 | user["blockList"][blockId].lineslistheightMax = 0; 9 | user["blockList"][blockId].increment = 0; 10 | user["blockList"][blockId].maxFirst = 0; 11 | user["blockList"][blockId].currentInY = 0; 12 | user["blockList"][blockId].wordsListMain = []; 13 | user["blockList"][blockId].wordsListSub = []; 14 | user["blockList"][blockId].linesListMain = []; 15 | user["blockList"][blockId].linesListSub = []; 16 | } 17 | run = async function (id, isPreview) { 18 | await this.runAnimation(id, isPreview); 19 | let user = Config.users[id]; 20 | try { 21 | this.font = this.global_data.font 22 | let offsetY = 0; 23 | for (let blockId = 0; blockId < user["blockList"].length; blockId++) { 24 | this.reset(user, blockId); 25 | await this.doProcessText(id, blockId, user.animation_style); 26 | await this.processDimensions(user, blockId, user.animation_style); 27 | let maxWidthBound = user.maxWidthBound; 28 | let maxFirstCrop = user.maxFirstCrop; 29 | let destY = 0; 30 | let y = 0; 31 | let timing = 0; 32 | let cmdText = ""; 33 | let frameIncrement = 0; 34 | if (user["blockList"][blockId].type == "photo" || user["blockList"][blockId].type == "quoteImage") { 35 | cmdText = ""; 36 | let percentTotal = 100 37 | if (user["blockList"][blockId].background_settings.crop != "Fittoframe") { 38 | let yHeight = 1080 39 | percentTotal = this.processResolution(id, Config.hdWidth, yHeight, user["blockList"][blockId].width, user["blockList"][blockId].height) 40 | } 41 | 42 | let startY = 0; 43 | y = startY; 44 | let duration = 0 45 | destY = 5; 46 | if (blockId > 0) { 47 | startY = 0; 48 | y = startY; 49 | destY = 5; duration = 300; 50 | } 51 | else { 52 | startY = 0; 53 | destY = 134; 54 | } 55 | let start = Date.now(); 56 | let stop = false 57 | let end = start + duration; 58 | startY = -(user.iHeight); 59 | y = startY; 60 | destY = 0; 61 | duration = 0; 62 | if (blockId > 0) duration = 300; 63 | start = Date.now(); 64 | stop = false; 65 | end = start + duration; 66 | frameIncrement = 0; 67 | startY = user.iHeight == 1080 ? 125 : 125; 68 | y = startY; 69 | destY = user.iHeight == 1080 ? 200 : 200 70 | duration = 0 71 | if (blockId > 0) duration = user["blockList"][blockId].timing * 1000 - 300 72 | else { 73 | duration = user["blockList"][blockId].timing * 1000; 74 | y = startY; 75 | destY = user.iHeight == 1080 ? 200 : 200; 76 | } 77 | start = Date.now(); 78 | timing = (user["blockList"][blockId].timing) * 30 79 | end = start + duration; 80 | let currentIncrement = 1; 81 | let resize_command = []; 82 | if (isPreview) { 83 | resize_command.push("-resize") 84 | if (user["blockList"][blockId].background_settings.crop == "left" || user["blockList"][blockId].background_settings.crop == "right") { 85 | resize_command.push(213 + "x" + Config.previewHeight) 86 | } else { 87 | resize_command.push(Config.previewWidth + "x" + Config.previewHeight) 88 | } 89 | } 90 | for (let iFrame = 0; iFrame < timing; iFrame += currentIncrement) { 91 | frameIncrement++ 92 | if (stop) { 93 | break; 94 | } 95 | 96 | let val = iFrame / timing; 97 | let heightAfter = user["blockList"][blockId].height * percentTotal; 98 | offsetY = heightAfter - user["blockList"][blockId].height 99 | cmdText = ["convert", "-depth", "8", "-define", "PNG:compression-level=9", 100 | "-define", "PNG:compression-strategy=2", "-size", 101 | user["blockList"][blockId].hHeight + "x1080", "xc:white", 102 | "(", user["blockList"][blockId].url, "-quality", "40", "-gravity", 103 | "center", "-resize", (percentTotal) + "%", "-extent", 104 | +user["blockList"][blockId].hHeight + "x1080+0+" + 0, 105 | "-define", 106 | "distort:viewport=" + user["blockList"][blockId].hHeight + "x1080+0+0", 107 | "-gravity", "center", "-distort", "SRT", (1 + (val * 0.05)) + " 0", ")", 108 | "-composite", "-gravity", "center", ...resize_command, "-define", 109 | "PNG:compression-level=9", "-define", "PNG:compression-strategy=2", 110 | Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (blockId + 1) + path.sep + "fie-" + frameIncrement.toLocaleString('en-US', { minimumIntegerDigits: 4, useGrouping: false }) + "." + "jpg"]; 111 | if (this.isDebug) { 112 | if (this.which == -1) 113 | this.add_command(id, 'convert', cmdText); 114 | else if (this.which == blockId) { this.add_command(id, 'convert', cmdText); } 115 | } else { 116 | this.add_command(id, 'convert', cmdText); 117 | } 118 | } 119 | 120 | 121 | } else if (user["blockList"][blockId].type == "logoVideo") { 122 | await this.generateLogo(user, id, blockId); 123 | } else if (user["blockList"][blockId].type == "logoText") { 124 | let size = Config.previewWidth + "x" + Config.previewHeight; 125 | if (!isPreview) { 126 | size = (Config.hdWidth + "x" + Config.hdHeight); 127 | } 128 | cmdText = ["-size", size, "xc:" + user["blockList"][blockId].accent, "-quality", "50", 129 | Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (blockId + 1) + path.sep + "fiebg.jpg"]; 130 | this.add_command(id, 'convert', cmdText); 131 | await this.generateLogo(user, id, blockId); 132 | } else if (user["blockList"][blockId].type == "logoImage") { 133 | await this.generateLogo(user, id, blockId); 134 | await this.generateCommands(user, id, blockId); 135 | } 136 | offsetY = 90; 137 | if (user["blockList"][blockId].type == "text" || user["blockList"][blockId].background_settings.crop == "right" || user["blockList"][blockId].background_settings.crop == "left" || user["blockList"][blockId].type == "quoteImage" || user["blockList"][blockId].type == "quoteVideo") { 138 | if (user["blockList"][blockId].type == "text" || user["blockList"][blockId].background_settings.crop == "right" || user["blockList"][blockId].background_settings.crop == "left") { 139 | offsetY = user["blockList"][blockId].linesListYAxis[0] + 90; 140 | } else { 141 | offsetY = user["blockList"][blockId].linesListYAxis[0]; 142 | } 143 | } 144 | 145 | if (user["blockList"][blockId].type == "logoImage" || user["blockList"][blockId].type == "logoVideo" || user["blockList"][blockId].type == "logoText") { 146 | await generateTextBulletin(id, blockId) 147 | } else { 148 | /*TEXT AND SUBTITLE*/ 149 | let startY = user.iHeight == 1080 ? 200 : 200; 150 | destY = user.iHeight == 1080 ? 125 : 125; 151 | timing = (user["blockList"][blockId].timing) * 30; 152 | if (blockId <= 0) { 153 | startY = user.iHeight == 1080 ? 200 : 200; 154 | timing = ((user["blockList"][blockId].timing) * 30); 155 | y = startY; 156 | } 157 | 158 | if (user["blockList"][blockId].type == "text") { 159 | timing = (user["blockList"][blockId].timing - 1) * 30; 160 | } 161 | 162 | let secondAnimStart = 16; 163 | let thirdAnimStart = 24; 164 | let forthAnimStart = (user["blockList"][blockId].timing == 3) ? 49 : 165 | (user["blockList"][blockId].timing == 4) ? 54 : 59; 166 | let textYAxis = 0; 167 | let yAxis = 0; 168 | let vopacity = 0; 169 | let totalY = 0; 170 | let valX = 0; 171 | let xAxis = 0; 172 | let curIndex = 0; 173 | let valueOpacity = 0; 174 | let currentTIndex = 0; 175 | let halfTiming = timing < 30 ? 20 : 30; 176 | let currentLine = user["blockList"][blockId].linesListMain.length 177 | let xStart = forthAnimStart 178 | for (let i = 0; i < user["blockList"][blockId].linesListSub.length; i++) { 179 | user["blockList"][blockId].linesListSub[i]["preStartRectangle"] = xStart + 1 180 | user["blockList"][blockId].linesListSub[i]["start"] = xStart 181 | user["blockList"][blockId].linesListSub[i]["end"] = ( 182 | (user["blockList"][blockId].timing == 3) ? 9 : 183 | (user["blockList"][blockId].timing == 4) ? 15 : 20); 184 | 185 | user["blockList"][blockId].linesListSub[i]["iAfter"] = 0; 186 | user["blockList"][blockId].linesListSub[i]["t"] = 0; 187 | user["blockList"][blockId].linesListSub[i]["preEndRectangle"] = xStart + 1 + ( 188 | (user["blockList"][blockId].timing == 3) ? 12 : 189 | (user["blockList"][blockId].timing == 4) ? 17 : 22) 190 | xStart += 1 + ( 191 | (user["blockList"][blockId].timing == 3) ? 5 : 192 | (user["blockList"][blockId].timing == 4) ? 6 : 7) 193 | user["blockList"][blockId].linesListSub[i]["nextStartRectangle"] = xStart + 1 194 | 195 | } 196 | let totalSubLines = 1; 197 | let resize_command = [] 198 | if (isPreview) { 199 | resize_command.push("-resize") 200 | if (user["blockList"][blockId].background_settings.crop == "left" || user["blockList"][blockId].background_settings.crop == "right") { 201 | 202 | resize_command.push(213 + "x" + Config.previewHeight) 203 | 204 | } else { 205 | resize_command.push(Config.previewWidth + "x" + (user["blockList"][blockId].lineslistheightMax / 1080) * Config.previewHeight) 206 | 207 | } 208 | 209 | } 210 | for (let d = 0; d < timing; d++) { 211 | if (d > 15) { 212 | vopacity = curIndex / halfTiming > 1.0 ? 1.0 : (curIndex / halfTiming); 213 | curIndex++; 214 | } 215 | valueOpacity = (currentTIndex / timing) >= 1.0 ? 1.0 : (currentTIndex / timing); 216 | currentTIndex++; 217 | frameIncrement++; 218 | let cmdText = [] 219 | if (user["blockList"][blockId].type == "text") { 220 | cmdText = ["convert", "-quality", "40", "-size"]; 221 | if (valueOpacity > 0) { 222 | cmdText.push(this.mainWidth + "x" + this.mainHeight) 223 | } else { 224 | if (isPreview) { 225 | cmdText.push(Config.previewWidth + "x" + Config.previewHeight) 226 | } else { 227 | cmdText.push(Config.hdWidth + "x" + 1080) 228 | } 229 | } 230 | cmdText.push("xc:" + user["blockList"][blockId].background_settings["color"]) 231 | } else if (user["blockList"][blockId].background_settings.crop == "left" || user["blockList"][blockId].background_settings.crop == "right") { 232 | cmdText = ["convert", "-define", "png:color-type=6", "-quality", "40", "-size"]; 233 | if (valueOpacity > 0) { 234 | cmdText.push(this.mainWidth + "x" + 1080) 235 | } else { 236 | if (isPreview) { 237 | cmdText.push(Config.previewWidth + "x" + Config.previewHeight) 238 | } else { 239 | cmdText.push(Config.hdWidth + "x" + user["blockList"][blockId].lineslistheightMax) 240 | } 241 | } 242 | cmdText.push("xc:none") 243 | } 244 | else { 245 | cmdText = ["convert", "-define", "png:color-type=6", "-quality", "40", "-size"]; 246 | if (valueOpacity > 0) { 247 | cmdText.push(this.mainWidth + "x" + user["blockList"][blockId].lineslistheightMax) 248 | } else { 249 | if (isPreview) { 250 | 251 | cmdText.push(Config.previewWidth + "x" + user["blockList"][blockId].lineslistheightMax) 252 | } else { 253 | 254 | 255 | cmdText.push(Config.hdWidth + "x" + user["blockList"][blockId].lineslistheightMax) 256 | } 257 | } 258 | cmdText.push("xc:none") 259 | } 260 | cmdText.push("-fill") 261 | cmdText.push(user["blockList"][blockId].text[0]["color"]) 262 | cmdText.push("-font") 263 | cmdText.push(this.fontBold) 264 | cmdText.push("-pointsize") 265 | cmdText.push(user["blockList"][blockId].text[0]["fontSize"]) 266 | 267 | if (valueOpacity > 0) { 268 | let finalX = user["blockList"][blockId].linesListXAxis[0] 269 | if (user["blockList"][blockId].increment >= 0) { 270 | cmdText.push("(") 271 | cmdText.push("xc:transparent") 272 | let n = (user["blockList"][blockId].increment / 15) 273 | let valYVerticalLine = user["blockList"][blockId].increment >= 15 ? 1 : n * (2 - n); 274 | 275 | textYAxis = user["blockList"][blockId].type == "text" || user["blockList"][blockId].background_settings.crop == "left" || user["blockList"][blockId].background_settings.crop == "right" ? user["blockList"][blockId].linesListYAxis[0] : 0 276 | cmdText.push("-fill") 277 | cmdText.push(user["blockList"][blockId].accent) 278 | cmdText.push("-draw") 279 | totalY = textYAxis + this.getHeightCharacter(user.animation_style, currentLine, user["blockList"][blockId].linesListMain, "Main") 280 | let vY = user["blockList"][blockId].type == "text" || user["blockList"][blockId].background_settings.crop == "left" || user["blockList"][blockId].background_settings.crop == "right" ? user["blockList"][blockId].linesListYAxis[0] : 0 281 | let tY = vY + ((totalY - vY) * valYVerticalLine) 282 | yAxis = user["blockList"][blockId].type == "text" || user["blockList"][blockId].background_settings.crop == "left" || user["blockList"][blockId].background_settings.crop == "right" ? user["blockList"][blockId].linesListYAxis[0] : 0 283 | 284 | 285 | let startX = finalX; 286 | let incValueFinalX = finalX + 18; 287 | let endRect = parseInt(Math.max(...user["blockList"][blockId].linesWidthMain) + incValueFinalX + 30) 288 | if (user["blockList"][blockId].alignH == "right") { 289 | finalX = maxWidthBound; 290 | incValueFinalX = finalX + 18; 291 | endRect = incValueFinalX - parseInt(Math.max(...user["blockList"][blockId].linesWidthMain)) - 30 292 | } else { 293 | startX += 18; 294 | } 295 | 296 | cmdText.push("rectangle " + finalX + "," + tY + " " + incValueFinalX + "," + parseInt(vY)) 297 | if (user["blockList"][blockId].increment >= secondAnimStart && user["blockList"][blockId].legibility) { 298 | cmdText.push("-fill"); 299 | let clr = Utils.hexToRgb(user["blockList"][blockId].legibilityColor); 300 | cmdText.push("rgba(" + clr.r + "," + clr.g + "," + clr.b + "," + ((valueOpacity * 0.50) + 0.1) + ")"); 301 | cmdText.push("-draw"); 302 | cmdText.push("rectangle " + startX + "," + (vY) + " " + endRect + "," + (totalY + 1)); 303 | } 304 | cmdText.push(")"); 305 | cmdText.push("-composite"); 306 | } 307 | if (user["blockList"][blockId].increment >= secondAnimStart) { 308 | cmdText.push("(") 309 | cmdText.push("xc:transparent") 310 | let ne = (user["blockList"][blockId].increment - secondAnimStart) / (thirdAnimStart - secondAnimStart) 311 | valX = user["blockList"][blockId].increment > thirdAnimStart >= 1 ? 1 : ne * (2 - ne) 312 | 313 | //textYAxis = 90 + (Math.abs(user["blockList"][blockId].linesListMain[0]["nDescentLine"]) + 5) 314 | textYAxis = 40 + (Math.abs(user["blockList"][blockId].linesListMain[0]["nDescentLine"]) + 5); 315 | for (let ieg = 0; ieg < currentLine; ieg++) { 316 | let gf = ieg + 1; 317 | if (user["blockList"][blockId].alignH == "right") { 318 | finalX = (maxWidthBound) 319 | } else { 320 | finalX = user["blockList"][blockId].linesListXAxis[ieg] + 30 321 | } 322 | let text = user["blockList"][blockId].linesListMain[ieg]["textLine"] 323 | if (valueOpacity > 0) { 324 | cmdText.push("-fill") 325 | let clr = Utils.hexToRgb(user["blockList"][blockId].text[0]["color"]) 326 | cmdText.push("rgba(" + clr.r + "," + clr.g + "," + clr.b + "," + 1 + ")"); 327 | cmdText.push("-annotate") 328 | if (user["blockList"][blockId].alignH == "right") { 329 | let width_line = Math.max(...user["blockList"][blockId].linesWidthMain) 330 | let current_width_line = user["blockList"][blockId].linesWidthMain[ieg] 331 | cmdText.push("+" + ((width_line - current_width_line)) + "+" + textYAxis) 332 | } else if (user["blockList"][blockId].alignH == "center") { 333 | cmdText.push("+" + (maxFirstCrop + 10) + "+" + textYAxis); 334 | } else { 335 | if (ieg > 0) { 336 | cmdText.push("+" + (finalX + 10) + "+" + textYAxis); 337 | } else { 338 | cmdText.push("+" + (finalX + 10) + "+" + textYAxis); 339 | } 340 | } 341 | 342 | cmdText.push(text); 343 | } 344 | if (ieg < currentLine - 1) { 345 | textYAxis += 20+(+(user["blockList"][blockId].linesListMain[ieg + 1]["nDescentLine"])) 346 | } 347 | } 348 | 349 | if (user["blockList"][blockId].alignH == "right") { 350 | let width_line = Math.max(...user["blockList"][blockId].linesWidthMain) 351 | let xMovement = (1 + ((width_line - 1) * valX)) 352 | xAxis = xMovement 353 | let xFinal = (finalX - Math.abs(xAxis)) - 18 354 | cmdText.push("-crop") 355 | cmdText.push(xAxis + "x" + user["blockList"][blockId].lineslistheightMax + "+" + 0 + "-" + 0) 356 | cmdText.push("-geometry") 357 | cmdText.push("+" + xFinal + "+" + (yAxis)) 358 | 359 | } else 360 | if (user["blockList"][blockId].alignH == "center") { 361 | let width_line = Math.max(...user["blockList"][blockId].linesWidthMain) 362 | let xMovement = (width_line 363 | + (((maxFirstCrop + 10) - width_line) * valX)) 364 | let xAxis = xMovement; 365 | cmdText.push("-crop") 366 | cmdText.push((width_line + 30) + "x" + user["blockList"][blockId].lineslistheightMax + "+" + xAxis + "+" + 0) 367 | cmdText.push("-geometry") 368 | cmdText.push("+" + finalX + "+" + (yAxis)) 369 | } else { 370 | let width_line = Math.max(...user["blockList"][blockId].linesWidthMain); 371 | let xMovement = ((width_line) 372 | + ((finalX - width_line) * valX)) 373 | let xAxis = xMovement 374 | cmdText.push("-crop") 375 | cmdText.push((width_line + 30) + "x" + user["blockList"][blockId].lineslistheightMax + "+" + xAxis + "+" + 0) 376 | cmdText.push("-geometry") 377 | cmdText.push("+" + finalX + "+" + (yAxis)) 378 | } 379 | 380 | cmdText.push(")") 381 | cmdText.push("-composite") 382 | } 383 | totalY += (30 / Config.hdHeight) * user.iHeight 384 | let totalYY = totalY 385 | 386 | if (user["blockList"][blockId].increment >= forthAnimStart) { 387 | for (let i = 0; i < totalSubLines; i++) { 388 | let text = user["blockList"][blockId].linesListSub[i]["textLine"] 389 | 390 | cmdText.push("(") 391 | cmdText.push("xc:transparent") 392 | 393 | 394 | textYAxis = offsetY 395 | 396 | let clr = Utils.hexToRgb(user["blockList"][blockId].text[0]["color"]) 397 | 398 | cmdText.push("-fill") 399 | cmdText.push("rgba(" + clr.r + "," + clr.g + "," + clr.b + "," + valueOpacity + ")"); 400 | 401 | 402 | textYAxis += (60 / Config.hdHeight) * user.iHeight 403 | if (user["blockList"][blockId].alignH == "right") { 404 | finalX = (maxWidthBound) + 30 405 | } else { 406 | finalX = user["blockList"][blockId].linesListXAxis[0] + 30 407 | } 408 | cmdText.push("-fill") 409 | cmdText.push(user["blockList"][blockId].accent) 410 | let cX = (finalX) - 30 411 | let endX = cX + user["blockList"][blockId].linesWidthSub[i] + 30 412 | let ne = (user["blockList"][blockId].increment - user["blockList"][blockId].linesListSub[i]["preStartRectangle"]) / (user["blockList"][blockId].linesListSub[i]["preEndRectangle"] - user["blockList"][blockId].linesListSub[i]["preStartRectangle"]) 413 | valX = ne >= 1 ? 1 : ne <= 0 ? 0 : Math.sin(ne * Math.PI / 2) 414 | valX = valX < 0 ? 0 : valX 415 | if (user["blockList"][blockId].alignH == "right") { 416 | cX = maxWidthBound - 30 - 18 417 | let cxS = (cX - user["blockList"][blockId].linesWidthSub[i]) 418 | endX = cX + 30 + 18 + 18 419 | let xMovement = cX 420 | + (cxS - cX) * valX 421 | cX = xMovement + 4 422 | } else { 423 | cX = (finalX) 424 | let cxS = cX + user["blockList"][blockId].linesWidthSub[i] + 30 425 | endX = cX - 30 426 | let xMovement = cX 427 | + (cxS - cX) * valX 428 | cX = xMovement 429 | } 430 | if (valX != 0) { 431 | cmdText.push("-draw") 432 | cmdText.push("rectangle " + ((cX)) + "," + (totalYY - 4) + " " + endX + "," + (totalYY + user["blockList"][blockId].linesListSub[i]["ascentLine"] + user["blockList"][blockId].linesListSub[i]["descentLine"] + 4)) 433 | } 434 | cmdText.push(")"); 435 | cmdText.push("-composite") 436 | if (user["blockList"][blockId].increment >= user["blockList"][blockId].linesListSub[i]["start"]) { 437 | cmdText.push("(") 438 | 439 | cmdText.push("xc:transparent") 440 | cmdText.push("-fill") 441 | clr = Utils.hexToRgb(user["blockList"][blockId].text[1]["color"]) 442 | cmdText.push("rgba(" + clr.r + "," + clr.r + "," + clr.r + "," + (vopacity) + ")") 443 | 444 | 445 | if (user["blockList"][blockId].linesListSub[i]["iAfter"] > user["blockList"][blockId].linesListSub[i]["end"]) { 446 | 447 | user["blockList"][blockId].linesListSub[i]["t"] = 1 448 | } else { 449 | 450 | user["blockList"][blockId].linesListSub[i]["t"] = parseFloat(user["blockList"][blockId].linesListSub[i]["iAfter"] / user["blockList"][blockId].linesListSub[i]["end"]) 451 | user["blockList"][blockId].linesListSub[i]["iAfter"] += 1 452 | 453 | } 454 | let valX = Math.sin(user["blockList"][blockId].linesListSub[i]["t"] * Math.PI / 2); 455 | cmdText.push("-font") 456 | cmdText.push(this.subFont) 457 | cmdText.push("-pointsize") 458 | cmdText.push(user["blockList"][blockId].text[1]["fontSize"]) 459 | if (user["blockList"][blockId].alignH == "right") { 460 | let current_width_line = user["blockList"][blockId].linesWidthSub[i] 461 | 462 | let xMovement = (1 + ((current_width_line - 1) * valX)) 463 | let xAxis = xMovement 464 | 465 | let xFinal = finalX - Math.abs(xAxis) - 18 466 | 467 | if (valueOpacity > 0) { 468 | cmdText.push("-annotate") 469 | cmdText.push("+" + (0) + "+" + (totalYY + user["blockList"][blockId].linesListSub[i]["ascentLine"])) 470 | cmdText.push(text) 471 | cmdText.push("-crop") 472 | cmdText.push(xAxis + "x" + (user["blockList"][blockId].linesListSub[i]["descentLine"] + user["blockList"][blockId].linesListSub[i]["ascentLine"] + totalYY) + "+" + 0 + "+" + 0) 473 | cmdText.push("-geometry") 474 | cmdText.push("+" + (xFinal - 30) + "+" + 0) 475 | } 476 | } else { 477 | let width_line = user["blockList"][blockId].linesWidthSub[i] + 18 478 | 479 | let xMovement = (1 + (width_line - 1) * valX) 480 | xAxis = xMovement 481 | 482 | 483 | 484 | if (valueOpacity > 0) { 485 | cmdText.push("-annotate") 486 | 487 | cmdText.push("+" + 18 + "+" + (totalYY + user["blockList"][blockId].linesListSub[i]["ascentLine"])) 488 | cmdText.push(text) 489 | cmdText.push("-crop") 490 | cmdText.push(xAxis + "x" + (user["blockList"][blockId].linesListSub[i]["heightLine"] + totalYY) + "+" + (width_line - xAxis) + "+" + 0) 491 | cmdText.push("-geometry") 492 | cmdText.push("+" + (finalX) + "+" + 0) 493 | } 494 | 495 | } 496 | cmdText.push(")") 497 | cmdText.push("-composite") 498 | 499 | } 500 | 501 | totalYY += user["blockList"][blockId].linesListSub[i]["ascentLine"] + user["blockList"][blockId].linesListSub[i]["descentLine"] 502 | totalYY += (40 / Config.hdHeight) * user.iHeight 503 | } 504 | 505 | if (user["blockList"][blockId].increment > (user["blockList"][blockId].linesListSub.length >= totalSubLines) ? user["blockList"][blockId].linesListSub[totalSubLines - 1]["nextStartRectangle"] : user["blockList"][blockId].linesListSub[totalSubLines]["nextStartRectangle"]) { 506 | if (totalSubLines >= user["blockList"][blockId].linesListSub.length) { 507 | totalSubLines = user["blockList"][blockId].linesListSub.length 508 | } else { 509 | totalSubLines++; 510 | } 511 | } 512 | } 513 | } 514 | 515 | if (user["blockList"][blockId].background_settings.crop != "left" && user["blockList"][blockId].background_settings.crop != "right") { 516 | cmdText.push("-background") 517 | cmdText.push("transparent") 518 | } else { 519 | cmdText.push("-background") 520 | cmdText.push(user["blockList"][blockId].background_settings.color) 521 | 522 | } 523 | 524 | if (user["blockList"][blockId].type == "quoteImage" || user["blockList"][blockId].type == "quoteVideo") { 525 | cmdText.push("-resize") 526 | cmdText.push((100) + "%") 527 | 528 | } 529 | if (valueOpacity >= 0) { 530 | cmdText.push("-extent") 531 | } 532 | if (user["blockList"][blockId].background_settings.crop != "left" && user["blockList"][blockId].background_settings.crop != "right") { 533 | 534 | 535 | if (user["blockList"][blockId].type == "text" || user.isPreview) { 536 | if (valueOpacity > 0) { 537 | cmdText.push(user.iWidth + "x" + user.iHeight) 538 | cmdText.push("-resize") 539 | if (user["blockList"][blockId].type == "text" && !user.isPreview) { 540 | cmdText.push(user.iWidth + "x" + user.iHeight) 541 | } else { 542 | cmdText.push(Config.previewWidth + "x" + (user["blockList"][blockId].lineslistheightMax / Config.hdHeight) * Config.previewHeight) 543 | } 544 | } 545 | } else { 546 | cmdText.push(user.iWidth + "x" + user["blockList"][blockId].lineslistheightMax) 547 | } 548 | } else { 549 | if (user.isPreview) { 550 | cmdText.push(user.iWidth / 2 + "x" + user.iHeight) 551 | if (valueOpacity > 0) { 552 | cmdText.push("-resize") 553 | cmdText.push((Config.previewWidth / 2) + "x" + Config.previewHeight) 554 | 555 | } 556 | } else { cmdText.push(user.iWidth / 2 + "x" + user.iHeight) } 557 | 558 | } 559 | let format = "png" 560 | let appendFormat = "PNG32:" 561 | if (user["blockList"][blockId].type == "text") { 562 | format = "jpg" 563 | appendFormat = "" 564 | } 565 | 566 | if (valueOpacity >= 0) { 567 | user["blockList"][blockId].increment++ 568 | cmdText.push(...resize_command, appendFormat + Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (blockId + 1) + path.sep + "fim-" + user["blockList"][blockId].increment.toLocaleString('en-US', { minimumIntegerDigits: 4, useGrouping: false }) + "." + format); 569 | 570 | 571 | } 572 | 573 | if (this.isDebug) { 574 | if (this.which == -1) 575 | this.add_command(id, 'convert', cmdText); 576 | else if (this.which == blockId) { 577 | this.add_command(id, 'convert', cmdText); 578 | } 579 | } else { 580 | 581 | this.add_command(id, 'convert', cmdText); 582 | 583 | } 584 | } 585 | } 586 | } 587 | let queue_reply = ''; 588 | let queueName = this.queue; 589 | let tLimit = this.totalLimit; 590 | const onMessage = function (msg) { 591 | try { 592 | let data = JSON.parse(msg.content.toString()) 593 | if (data.status == "error") { 594 | let obj = new Object() 595 | obj.socket = Config.users[data.id].socket; 596 | if (!isPreview) 597 | obj.data = { 598 | 'status': 'error', videos_progress: { '360p': Config.users[data.id].p_360, '480p': Config.users[data.id].p_480, '720p': Config.users[data.id].p_720, '1080p': Config.users[data.id].p_1080 } 599 | , videos_url: { '360p': 'none', '480p': 'none', '720p': 'none', '1080p': 'none' } 600 | } 601 | else 602 | obj.data = { 603 | 'status': 'error', 604 | 'is_preview': 'false' 605 | , video_url: { url: 'none' } 606 | } 607 | Config.users[data.id].eventEmitter.emit('onProgress', obj); 608 | return; 609 | } 610 | 611 | if (Config.users[data.id].processedVideos >= Config.users[data.id].totalVideos) { 612 | if (Config.users[data.id].isPreview) 613 | this.processHDVideo(Config.users, data.id) 614 | else { 615 | this.processHDVideo(Config.users, data.id, Config.users[data.id].p_360, Config.users[data.id].p_480, Config.users[data.id].p_720, Config.users[data.id].p_1080) 616 | 617 | } 618 | } 619 | 620 | } catch (e) { 621 | throw (e) 622 | } 623 | } 624 | const queuefunction = function (err1, eq) { 625 | 626 | if (err1) { 627 | throw err1; 628 | } 629 | 630 | Config.ch.consume(eq.queue, onMessage.bind(this), { 631 | noAck: true 632 | 633 | }); 634 | 635 | let obj = new Object() 636 | obj.socket = user.socket; 637 | if (!isPreview) 638 | obj.data = { 639 | 'status': 'inprogress', videos_progress: { '360p': user.p_360, '480p': user.p_480, '720p': user.p_720, '1080p': user.p_1080 } 640 | , videos_url: { '360p': 'none', '480p': 'none', '720p': 'none', '1080p': 'none' } 641 | } 642 | else 643 | obj.data = { 644 | 'status': 'in_progress', 645 | 'is_preview': 'true' 646 | , video_url: { url: 'none' } 647 | } 648 | user.eventEmitter.emit('onProgress', obj); 649 | let correlationId = Utils.generateUuid(); 650 | let date = new Date() 651 | Config.ch.sendToQueue(queueName, 652 | Buffer.from(JSON.stringify({ tLimit: tLimit, commands: user.commands, id: id, date: date })), { 653 | correlationId: correlationId, 654 | replyTo: eq.queue, persistent: true 655 | }, function (e, r) { 656 | 657 | 658 | }); 659 | 660 | } 661 | Config.ch.assertQueue('', { 662 | exclusive: true 663 | }, queuefunction.bind(this)) 664 | } catch (e) { 665 | console.log("err", e) 666 | 667 | } 668 | 669 | } 670 | processHDVideo = function (users, id, p_360 = null, p_480 = null, p_720 = null, p_1080 = null) { 671 | let isPreview = false 672 | let finalLine = ""; 673 | let user = users[id]; 674 | if (p_1080 == null) { 675 | isPreview = true; 676 | finalLine = this.makeCommand(true, id); 677 | } else { 678 | finalLine = this.makeCommand(false, id); 679 | } 680 | user.total_ms = user.total_sec * 1000; 681 | const { FFMpeg_Wrapper } = require('./ffmpeg_wrapper.js'); 682 | const args = finalLine; 683 | const ffmpegProgress = new FFMpeg_Wrapper(); 684 | const ffmpeg = require('child_process').spawn("ffmpeg", args); 685 | function logProgress(progressData) { 686 | let c_progress = (progressData.time_ms / user.total_ms) 687 | let p1080_progress = parseInt(parseFloat(c_progress / 1.0) * 100) 688 | 689 | let obj = new Object() 690 | obj.socket = user.socket 691 | if (isPreview) { 692 | 693 | obj.data = { 694 | 'status': 'in_progress', 695 | 'is_preview': 'true' 696 | , video_url: { url: 'none' } 697 | } 698 | } else { 699 | 700 | obj.data = { 701 | 'status': 'inprogress', 702 | videos_progress: { '360p': user.p_360, '480p': user.p_480, '720p': user.p_720, '1080p': p1080_progress } 703 | , videos_url: { '360p': 'none', '480p': 'none', '720p': 'none', '1080p': 'none' } 704 | } 705 | 706 | } 707 | user.eventEmitter.emit('onProgress', obj); 708 | } 709 | ffmpeg.stderr.pipe(ffmpegProgress).on('data', logProgress); 710 | ffmpeg.on('close', code => { 711 | if (code) { 712 | let obj = new Object() 713 | obj.socket = user.socket 714 | if (!isPreview) 715 | obj.data = { 716 | 'status': 'error', videos_progress: { '360p': user.p_360, '480p': user.p_480, '720p': user.p_720, '1080p': user.p_1080 } 717 | , videos_url: { '360p': 'none', '480p': 'none', '720p': 'none', '1080p': 'none' } 718 | } 719 | else 720 | obj.data = { 721 | 'status': 'error', 722 | 'is_preview': 'false' 723 | , video_url: { url: 'none' } 724 | } 725 | user.eventEmitter.emit('onProgress', obj); 726 | 727 | console.error(`FFMPEG ERROR: ${ffmpegProgress.exitMessage}`); 728 | } else { 729 | if (!user.isPreview) { 730 | this.ffmpeg_run(user, Config.output_directory + path.sep + id + path.sep + "1080p.mp4", Config.output_directory + path.sep + id + path.sep, id) 731 | } 732 | let obj = new Object() 733 | obj.socket = user.socket 734 | if (isPreview) { 735 | obj.data = { 736 | 'status': 'completed', 737 | 'is_preview': 'true' 738 | , video_url: { url: "http://" + Config.socket_ip + "/" + id + "/" + "270p.mp4" } 739 | } 740 | user.eventEmitter.emit('onProgress', obj); 741 | 742 | user.eventEmitter.removeAllListeners(); 743 | users.splice(id, 1) 744 | } 745 | let endTime = new Date() - this.startTime 746 | fs.appendFile(Config.output_directory + id + path.sep + "time.txt", id + "--" + endTime.toString(), function (err) { 747 | if (err) throw err; 748 | console.log('Saved!'); 749 | }); 750 | } 751 | }); 752 | 753 | } 754 | makeCommand = function (isPreview, id) { 755 | let user = Config.users[id]; 756 | user.total_sec = Math.ceil(user.total_sec) 757 | if (isPreview) { 758 | user.iWidth = Config.previewWidth; 759 | user.iHeight = Config.previewHeight; 760 | } else { 761 | user.iWidth = Config.hdWidth 762 | user.iHeight = Config.hdHeight 763 | } 764 | let imgType = "jpg" 765 | let finalAnswer = ""; 766 | let addition = []; 767 | for (let i = 0; i < user["blockList"].length; i++) { 768 | if (user["blockList"][i].type == "logoImage") { 769 | addition.push("-thread_queue_size", "512", "-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fie-%04d.png"); 770 | addition.push("-thread_queue_size", "512", "-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fim-%04d.png"); 771 | addition.push("-thread_queue_size", "512", "-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "logo-%04d.png"); 772 | } else if (user["blockList"][i].type == "logoText") { 773 | addition.push("-thread_queue_size", "512", "-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fiebg.jpg"); 774 | addition.push("-thread_queue_size", "512", "-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fim-%04d.png"); 775 | addition.push("-thread_queue_size", "512", "-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "logo-%04d.png"); 776 | 777 | } else if (user["blockList"][i].type == "logoVideo") { 778 | 779 | addition.push("-thread_queue_size", "512", "-i", user["blockList"][i].url); 780 | addition.push("-thread_queue_size", "512", "-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fim-%04d.png"); 781 | addition.push("-thread_queue_size", "512", "-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "logo-%04d.png"); 782 | 783 | } else if (user["blockList"][i].type == "video" || user["blockList"][i].type == "quoteVideo") { 784 | 785 | if (user["blockList"][i].background_settings.crop == "left" || user["blockList"][i].background_settings.crop == "right") { 786 | addition.push("-i", user["blockList"][i].url); 787 | addition.push("-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fim-%04d.png"); 788 | 789 | } else { 790 | addition.push("-i", user["blockList"][i].url); 791 | addition.push("-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fim-%04d.png"); 792 | } 793 | 794 | } else if (user["blockList"][i].type == "text") { 795 | if (i == 0) { 796 | addition.push("-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fim-%04d.jpg"); 797 | } else { 798 | if (user["blockList"][i].background_settings.crop == "left" || user["blockList"][i].background_settings.crop == "right") { 799 | addition.push("-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fim-%04d.jpg"); 800 | addition.push("-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fie-%04d.jpg"); 801 | } else { 802 | addition.push("-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fim-%04d.jpg"); 803 | } 804 | } 805 | } 806 | else if (user["blockList"][i].type == "photo" || user["blockList"][i].type == "quoteImage") { 807 | if (i == 0) { 808 | addition.push("-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fie-%04d." + imgType); 809 | 810 | addition.push("-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fim-%04d.png"); 811 | 812 | 813 | } else { 814 | if (user["blockList"][i].background_settings.crop == "left" || user["blockList"][i].background_settings.crop == "right") { 815 | 816 | 817 | addition.push("-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fie-%04d.jpg"); 818 | addition.push("-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fim-%04d.png"); 819 | 820 | } else { 821 | 822 | addition.push("-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fie-%04d." + imgType); 823 | addition.push("-framerate", "30", "-i", Config.output_directory + id + path.sep + "data" + path.sep + "frames" + (i + 1) + path.sep + "fim-%04d.png"); 824 | 825 | 826 | } 827 | 828 | } 829 | } 830 | } 831 | 832 | 833 | 834 | let check_first_index = false 835 | for (let i = 0; i < user["blockList"].length; i++) { 836 | if (user["blockList"][i].voice_over.exist) { 837 | 838 | addition.push("-i", user["blockList"][i].voice_over.local_source) 839 | 840 | 841 | } 842 | 843 | } 844 | 845 | if (this.global_data.local_src.length > 0) { 846 | if (this.global_data.loop) { 847 | addition.push("-stream_loop", "-1"); 848 | } 849 | addition.push("-i", this.global_data.local_src); 850 | if (this.global_data.isTrim) { 851 | addition.push("-ss", this.global_data.trimValueStart, "-to", this.global_data.trimValueEnd) 852 | } 853 | } 854 | let lmS = 0; 855 | let f = 0 856 | let globalFilters = "brightness" 857 | let filter = "" 858 | if (globalFilters == "grayscale") { 859 | filter = ",format=gray" 860 | } else if (globalFilters == "brightness") { 861 | filter = ",eq=brightness=-0.01" 862 | } 863 | let delay_command = "" 864 | let enable_command = "" 865 | let currentTime = 0 866 | for (let i = 0; i < user["blockList"].length; i += 1) { 867 | if (i != 0) { 868 | 869 | f += parseFloat(user["blockList"][i - 1].timing) 870 | if (user.animation_style == "blankslate") { 871 | delay_command = "PTS-STARTPTS+" + ((f - 1)) + "/TB" 872 | enable_command = ":enable='between(t\," + ((f - 1.4)) + "," + user.total_sec + ")'" 873 | } else if (user.animation_style == "standout") { 874 | 875 | delay_command = "PTS-STARTPTS+" + ((f - 1)) + "/TB" 876 | enable_command = ":enable='between(t\," + ((f - 1.4)) + "," + user.total_sec + ")'" 877 | } else { 878 | 879 | if (user["blockList"][i].type != "text") { 880 | delay_command = "PTS-STARTPTS+" + (f + (0.5)) + "/TB" 881 | 882 | } else { 883 | delay_command = "PTS-STARTPTS+" + (f + (currentTime)) + "/TB" 884 | } 885 | } 886 | } else { 887 | if (user.animation_style == "blankslate") { 888 | delay_command = "PTS-STARTPTS" 889 | 890 | enable_command = "" 891 | } else { 892 | delay_command = "PTS-STARTPTS" 893 | 894 | } 895 | } 896 | let finalY = user["blockList"][i].linesListYAxis[0] 897 | if (user.animation_style == "blankslate") { 898 | finalY = 0 899 | 900 | } 901 | 902 | if (user["blockList"][i].type == "quoteImage" || user["blockList"][i].type == "quoteVideo" || user["blockList"][i].type == "text") { 903 | finalY = 0 904 | } 905 | 906 | if (i == 0) { 907 | if (user["blockList"][i].type == "text") { 908 | 909 | if (user["blockList"][i].background_settings.crop == "left") { 910 | 911 | finalAnswer += "[0:v][1:v]overlay=x=" + (user.iWidth / 2) + "[mv];"; 912 | finalAnswer += "[mv]pad=iw*2:0[left" + (lmS + 2) + "];[left" + (lmS + 2) + "][" + (lmS + 1) + ":v]overlay=x=960[out" + (i + 1) + "];"; 913 | lmS += 2; 914 | } else if (user["blockList"][i].background_settings.crop == "right") { 915 | 916 | finalAnswer += "[0:v][1:v]overlay=x=" + (user.iWidth / 2) + "[mv];"; 917 | finalAnswer += "[mv]pad=(iw/2)*2:0[left" + (lmS + 1) + "];[left" + (lmS + 1) + "][" + (lmS + 2) + ":v]overlay=x=" + (user.iWidth / 2) + "[out" + (i + 1) + "];"; 918 | 919 | lmS += 2; 920 | } else { 921 | 922 | lmS += 1; 923 | 924 | finalAnswer += "[0:v][1:v]overlay=y=" + finalY + "[out1];"; 925 | } 926 | } else if (user["blockList"][i].type == "logoText") { 927 | finalAnswer += "[0:v][1:v]overlay[mv];"; 928 | finalAnswer += "[mv][" + (lmS + 2) + ":v]overlay=(main_w-overlay_w)/2:H-h-" + ((50 / Config.hdHeight) * user.iHeight) + "[outelogo1];"; 929 | finalAnswer += "[outelogo1][" + (lmS + 3) + ":v]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2[out1];"; 930 | lmS += 3 931 | } else if (user["blockList"][i].type == "logoImage") { 932 | finalAnswer += "[0:v][1:v]overlay[mv];"; 933 | finalAnswer += "[mv][" + (lmS + 2) + ":v]overlay=(main_w-overlay_w)/2:H-h-" + ((50 / Config.hdHeight) * user.iHeight) + "[outelogo1];"; 934 | finalAnswer += "[outelogo1][" + (lmS + 3) + ":v]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2[out1];"; 935 | lmS += 3 936 | } else if (user["blockList"][i].type == "logoVideo") { 937 | finalAnswer += "[0:v][1:v]overlay[mv];"; 938 | finalAnswer += "[mv][" + (lmS + 2) + ":v]overlay=(main_w-overlay_w)/2:H-h-" + ((50 / Config.hdHeight) * user.iHeight) + "[outelogo1];"; 939 | finalAnswer += "[outelogo1][" + (lmS + 3) + ":v]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2[out1];"; 940 | lmS += 3 941 | } else if (user["blockList"][i].type == "photo" || user["blockList"][i].type == "quoteImage") { 942 | if (user["blockList"][i].background_settings.crop == "left" || user["blockList"][i].background_settings.crop == "right") { 943 | if (user["blockList"][i].background_settings.crop == "left") { 944 | 945 | finalAnswer += "[0:v][1:v]overlay=x=0[mv];"; 946 | finalAnswer += "[mv][" + (lmS + 2) + ":v]overlay=x=" + (user.iWidth / 2) + "[out1];"; 947 | 948 | } else { 949 | finalAnswer += "[0:v][" + (lmS + 2) + ":v]overlay=x=0[mv];"; 950 | finalAnswer += "[mv][1:v]overlay=x=" + (user.iWidth / 2) + "[out1];"; 951 | 952 | } 953 | lmS += 2 954 | } else { 955 | finalAnswer += "[0:v][1:v]overlay[mv];"; 956 | finalAnswer += "[" + (lmS + 2) + ":v]setpts=" + delay_command + "[outjm" + (i + 1) + "];"; 957 | finalAnswer += "[mv][outjm" + (i + 1) + "]overlay=x=" + 0 + ":y=" + finalY + enable_command + "[out1];" 958 | lmS += 2; 959 | } 960 | 961 | 962 | 963 | 964 | 965 | } else if (user["blockList"][i].type == "video") { 966 | 967 | if (user["blockList"][i].background_settings.crop == "left") { 968 | finalAnswer += "[0:v][1:v]overlay=x=0[mv];"; 969 | finalAnswer += "[mv][" + (lmS + 2) + ":v]overlay=x=" + (user.iWidth / 2) + "[out" + (i + 1) + "];"; 970 | 971 | } else if (user["blockList"][i].background_settings.crop == "right") { 972 | finalAnswer += "[0:v][1:v]overlay=x=0[mv];"; 973 | finalAnswer += "[mv]pad=(iw/2)*2:0[left" + (lmS + 1) + "];[left" + (lmS + 1) + "][" + (lmS + 2) + ":v]overlay=x=" + (user.iWidth / 2) + "[out" + (i + 1) + "];"; 974 | } else { 975 | finalAnswer += "[0:v][1:v]overlay[mv];"; 976 | finalAnswer += "[" + (lmS + 2) + ":v]setpts=" + delay_command + "[outjm" + (i + 1) + "];"; 977 | finalAnswer += "[mv][outjm" + (i + 1) + "]overlay=x=0:y=" + finalY + enable_command + "[out1];"; 978 | } 979 | 980 | lmS += 2; 981 | } else if (user["blockList"][i].type == "logoVideo") { 982 | 983 | finalAnswer += "[" + (lmS + 1) + ":v]setpts=" + delay_command + "[outjm" + (i + 2) + "];"; 984 | finalAnswer += "[" + (lmS + 2) + ":v]setpts=PTS-STARTPTS+" + (f) + "/TB[outjm" + (i + 1) + "];"; 985 | finalAnswer += "[" + (lmS + 3) + ":v]setpts=PTS-STARTPTS[outlogotext" + (i + 1) + "];"; 986 | finalAnswer += "[outjm" + (i + 2) + "][outjm" + (i + 1) + "]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2" + enable_command + "[outjmlogovideo" + (i + 1) + "];"; 987 | finalAnswer += "[outjmlogovideo" + (i + 1) + "][outlogotext" + (i + 1) + "]overlay=(main_w-overlay_w)/2:H-h-" + ((200 / Config.hdHeight) * user.iHeight) + enable_command + "[out" + (i + 1) + "];"; 988 | lmS += 3; 989 | 990 | } 991 | 992 | } else if (user["blockList"][i].type == "video" || user["blockList"][i].type == "quoteVideo") { 993 | let cropped = 0 994 | if (user["blockList"][i].background_settings.crop == "right") { 995 | cropped = user.iWidth + ":" + user.iHeight + ":" + (user.iWidth / 3) + ":0,pad=" + user.iWidth / 2 + "*2:0" 996 | finalAnswer += "[" + (lmS + 2) + ":v]crop=" + cropped + "[left" + (lmS + 2) + "];[left" + (lmS + 2) + "][" + (lmS + 1) + ":v]overlay=x=" + user.iWidth / 2 + "[out" + (i + 1) + "];"; 997 | 998 | } else if (user["blockList"][i].background_settings.crop == "left") { 999 | cropped = (user.iWidth / 2) + ":" + user.iHeight + ":" + (user.iWidth / 3) + ":0,pad=" + user.iWidth / 2 + "*2:0" 1000 | 1001 | finalAnswer += "[" + (lmS + 1) + ":v]crop=" + cropped + "[left" + (lmS + 1) + "];[left" + (lmS + 1) + "][" + (lmS + 2) + ":v]overlay=x=" + user.iWidth / 2 + "[out" + (i + 1) + "];"; 1002 | 1003 | } else { 1004 | finalAnswer += "[" + (lmS + 1) + ":v]setpts=" + delay_command + "[outjm" + (i + 2) + "];"; 1005 | 1006 | finalAnswer += "[" + (lmS + 2) + ":v]setpts=PTS-STARTPTS+" + (f) + "/TB[outjm" + (i + 1) + "];"; 1007 | 1008 | finalAnswer += "[outjm" + (i + 2) + "][outjm" + (i + 1) + "]overlay=x=" + 0 + ":y=" + finalY + enable_command + "[out" + (i + 1) + "];"; 1009 | //finalAnswer += "[oust" + (i + 1) + "][outsub" + (i + 1) + "]overlay=x=" + 0 + ":y=" + ( finalY+offsetFFMPEGY) + "[out" + (i + 1) + "];"; 1010 | 1011 | 1012 | 1013 | } 1014 | 1015 | 1016 | lmS += 2; 1017 | 1018 | } else if (user["blockList"][i].type == "logoImage") { 1019 | finalAnswer += "[" + (lmS + 1) + ":v]setpts=" + delay_command + "[outjm" + (i + 2) + "];"; 1020 | 1021 | finalAnswer += "[" + (lmS + 2) + ":v]setpts=PTS-STARTPTS+" + (f) + "/TB[outjm" + (i + 1) + "];"; 1022 | finalAnswer += "[" + (lmS + 3) + ":v]setpts=PTS-STARTPTS[outlogotext" + (i + 1) + "];"; 1023 | 1024 | 1025 | 1026 | finalAnswer += "[outjm" + (i + 2) + "][outjm" + (i + 1) + "]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2" + enable_command + "[outlogovideo" + (i + 1) + "];"; 1027 | finalAnswer += "[outjmlogovideo" + (i + 1) + "][outlogotext" + (i + 1) + "]overlay=(main_w-overlay_w)/2:H-h-" + ((200 / Config.hdHeight) * user.iHeight) + enable_command + "[out" + (i + 1) + "];"; 1028 | lmS += 3; 1029 | } else if (user["blockList"][i].type == "logoText") { 1030 | finalAnswer += "[" + (lmS + 1) + ":v]setpts=" + delay_command + "[outjm" + (i + 2) + "];"; 1031 | finalAnswer += "[" + (lmS + 2) + ":v]setpts=PTS-STARTPTS+" + (f) + "/TB[outjm" + (i + 1) + "];"; 1032 | finalAnswer += "[" + (lmS + 3) + ":v]setpts=PTS-STARTPTS[outlogotext" + (i + 1) + "];"; 1033 | finalAnswer += "[outjm" + (i + 2) + "][outjm" + (i + 1) + "]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2" + enable_command + "[outlogovideo" + (i + 1) + "];"; 1034 | finalAnswer += "[outjmlogovideo" + (i + 1) + "][outlogotext" + (i + 1) + "]overlay=(main_w-overlay_w)/2:H-h-" + ((200 / Config.hdHeight) * user.iHeight) + enable_command + "[out" + (i + 1) + "];"; 1035 | lmS += 3; 1036 | } else { 1037 | let cropped = 0; 1038 | if (user["blockList"][i].background_settings.crop == "left" || user["blockList"][i].background_settings.crop == "right") { 1039 | 1040 | if (user["blockList"][i].background_settings.crop == "left") { 1041 | cropped = 0; 1042 | finalAnswer += "[" + (lmS + 1) + ":v][" + (lmS + 2) + ":v]hstack=inputs=2[out" + (i + 1) + "];"; 1043 | } else { 1044 | cropped = (user.iWidth / 2) 1045 | finalAnswer += "[" + (lmS + 2) + ":v][" + (lmS + 1) + ":v]hstack=inputs=2[out" + (i + 1) + "];"; 1046 | } 1047 | lmS += 2; 1048 | } else { 1049 | if (user["blockList"][i].type != "text") { 1050 | finalAnswer += "[" + (lmS + 1) + ":v]setpts=" + delay_command + "[outdes" + (i + 1) + "];"; 1051 | finalAnswer += "[" + (lmS + 2) + ":v]setpts=PTS-STARTPTS+" + (f) + "/TB[outjes" + (i + 1) + "];"; 1052 | finalAnswer += "[outdes" + (i + 1) + "][outjes" + (i + 1) + "]overlay=y=" + finalY + enable_command + "[outes" + (i + 1) + "];" 1053 | } else { 1054 | finalAnswer += "[" + (lmS + 1) + ":v]setpts=PTS-STARTPTS+" + (f) + "/TB[outes" + (i + 1) + "];"; 1055 | } 1056 | 1057 | 1058 | if (user["blockList"][i].type == "text") { lmS += 1 } else { lmS += 2 } 1059 | 1060 | 1061 | 1062 | } 1063 | ; 1064 | } 1065 | 1066 | } 1067 | let format = "outse"; f = 0; 1068 | for (let i = 0; i < user["blockList"].length; i++) { 1069 | if (i != 0) { 1070 | f += (user["blockList"][i - 1].timing) 1071 | } 1072 | if (user["blockList"][i].voice_over.exist) { 1073 | format = "outse" 1074 | 1075 | user.current_audio_index++ 1076 | } 1077 | else { 1078 | format = "oute" 1079 | } 1080 | if (i == 0) { 1081 | finalAnswer += "[out1]setpts=PTS-STARTPTS" + filter + "[oute1];"; 1082 | } 1083 | else 1084 | if (user["blockList"][i].type == "text") { 1085 | 1086 | if (user["blockList"][i].background_settings.crop == "left" || user["blockList"][i].background_settings.crop == "right") { 1087 | finalAnswer += "[out" + (i + 1) + "]setpts=PTS-STARTPTS+" + f + "/TB" + filter + "[" + format + (i + 1) + "];"; 1088 | } else { 1089 | finalAnswer += "[outes" + (i + 1) + "]" + filter.substr(1, filter.length - 1) + "[" + format + (i + 1) + "];"; 1090 | } 1091 | 1092 | } else if (user["blockList"][i].type == "photo" || user["blockList"][i].type == "quoteImage") { 1093 | 1094 | if (user["blockList"][i].background_settings.crop == "left" || user["blockList"][i].background_settings.crop == "right") { 1095 | finalAnswer += "[out" + (i + 1) + "]setpts=PTS-STARTPTS+" + (f + currentTime) + "/TB" + filter + "[" + format + (i + 1) + "];"; 1096 | } else { 1097 | finalAnswer += "[outes" + (i + 1) + "]" + filter.substr(1, filter.length - 1) + "[" + format + (i + 1) + "];"; 1098 | } 1099 | 1100 | } else if (user["blockList"][i].type == "video" || user["blockList"][i].type == "logoText" || user["blockList"][i].type == "logoImage" || user["blockList"][i].type == "logoVideo" || user["blockList"][i].type == "quoteVideo") { 1101 | 1102 | finalAnswer += "[out" + (i + 1) + "]setpts=PTS-STARTPTS+" + f + "/TB" + filter + "[" + format + (i + 1) + "];"; 1103 | 1104 | } 1105 | } 1106 | 1107 | for (let i = 0; i < user["blockList"].length; i++) { 1108 | if (user["blockList"][i].voice_over.exist) { 1109 | if (!check_first_index) { 1110 | user.current_audio_index = lmS; 1111 | check_first_index = true; 1112 | } 1113 | addition.push("-i", user["blockList"][i].voice_over.local_source); 1114 | lmS++; 1115 | 1116 | } 1117 | 1118 | } 1119 | for (let i = 0; i < user["blockList"].length; i++) { 1120 | if (user["blockList"][i].voice_over.exist) { 1121 | finalAnswer += "[outse" + (i + 1) + ":a][" + user.current_audio_index + ":a]amerge=inputs=2" + "[oute" + (i + 1) + "]"; 1122 | user.current_audio_index++; 1123 | } 1124 | } 1125 | let lastP = "[oute1]"; 1126 | let nextParam = "oute"; 1127 | let currentParam = "oute"; 1128 | f = 0; 1129 | for (let ie = 1; ie <= user["blockList"].length; ie++) { 1130 | let i = ie - 1; 1131 | f += (user["blockList"][i].timing); 1132 | if (i == 0) { 1133 | nextParam = "outnje"; 1134 | 1135 | } 1136 | if (i >= 1) { 1137 | currentParam = "outnje"; 1138 | } 1139 | 1140 | if (i == user["blockList"].length - 2) { 1141 | if (user["blockList"].length == 2) { 1142 | nextParam = "oute" 1143 | } 1144 | 1145 | if (user["blockList"][i].type == "video" || user["blockList"][i].type == "logoText" || 1146 | user["blockList"][i].type == "logoVideo" || 1147 | user["blockList"][i].type == "logoImage" 1148 | || user["blockList"][i].type == "photo" || user["blockList"][i].type == "text" || user["blockList"][i].type == "quoteVideo" || user["blockList"][i].type == "quoteImage") { 1149 | 1150 | if (user.animation_style == "blankslate") { 1151 | 1152 | finalAnswer += "[" + nextParam + (i + 1) + "]format=rgba,fade=t=out:st=" + f + ":d=" + 2 + ":alpha=1[a" + nextParam + (i + 1) + "];"; 1153 | finalAnswer += "[oute" + (i + 2) + "]format=rgba,fade=t=in:st=" + f + ":d=" + 2 + ":alpha=1[aoute" + (i + 2) + "];" 1154 | finalAnswer += "[a" + nextParam + (i + 1) + "][aoute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")':y=0:x=0[outnjse" + (i + 1) + "];"; 1155 | 1156 | } else { 1157 | finalAnswer += "[" + nextParam + (i + 1) + "][oute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")':y=0:x=0[outnjse" + (i + 1) + "];"; 1158 | } 1159 | } else { 1160 | finalAnswer += "[" + nextParam + (i + 1) + "][oute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")'[outnjse" + (i + 1) + "];"; 1161 | 1162 | } 1163 | lastP = "[outnjse" + (i + 1) + "]"; 1164 | 1165 | 1166 | } else if (i != user["blockList"].length - 1) { 1167 | if (user["blockList"][i].type == "video" || user["blockList"][i].type == "quoteVideo" || user["blockList"][i].type == "logoText" || 1168 | user["blockList"][i].type == "logoVideo" || 1169 | user["blockList"][i].type == "logoImage" || user["blockList"][i].type == "quoteVideo") { 1170 | 1171 | 1172 | 1173 | 1174 | if (user["blockList"].length - 1 >= i + 1) { 1175 | 1176 | if (user["blockList"][i + 1].type == "video" || user["blockList"][i].type == "quoteVideo" || user["blockList"][i].type == "logoText" || 1177 | user["blockList"][i].type == "logoVideo" || 1178 | user["blockList"][i].type == "logoImage" || user["blockList"][i].type == "quoteVideo" || user["blockList"][i].type == "quoteImage" || user["blockList"][i + 1].type == "photo" || user["blockList"][i + 1].type == "text") { 1179 | let overLayY = ":y=0:x=0" 1180 | if (user["blockList"][i + 1].type == "photo") { 1181 | overLayY = "" 1182 | 1183 | } 1184 | if (user.animation_style == "blankslate") { 1185 | 1186 | finalAnswer += "[" + currentParam + (i + 1) + "]format=rgba,fade=t=out:st=" + f + ":d=" + 2 + ":alpha=1[a" + currentParam + (i + 1) + "]"; 1187 | finalAnswer += ";[oute" + (i + 2) + "]format=rgba,fade=t=out:st=" + f + ":d=" + 2 + ":alpha=1[aoute" + (i + 2) + "];" 1188 | finalAnswer += "[a" + currentParam + (i + 1) + "][aoute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")'" + overLayY + "[" + nextParam + (i + 2) + "];"; 1189 | 1190 | } else { 1191 | finalAnswer += "[" + currentParam + (i + 1) + "][oute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")'" + overLayY + "[" + nextParam + (i + 2) + "];"; 1192 | } 1193 | lastP = "[outnje" + (i + 2) + "]"; 1194 | 1195 | } 1196 | } else { 1197 | let overLayY = ":y=0:x=0" 1198 | finalAnswer += "[oute" + (i + 1) + "][oute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")'" + overLayY + "[" + nextParam + (i + 2) + "];"; 1199 | lastP = "[outnje" + (i + 2) + "]"; 1200 | 1201 | } 1202 | // finalAnswer += "["+nextParam + (i+1) + "][oute" + (i + 2) + "]overlay=enable='between(t\\,"+f +","+(user .total_sec)+")':y='if(gte(t,"+f +"),if(gte(h-(t-"+f +")*(1/0.5)*h,0),h-(t-"+f +")*(1/0.5)*h,0))':x=0["+nextParam + (i + 2) + "];"; 1203 | //lastP = "[outnje" + (i + 2) + "]"; 1204 | } else if (user["blockList"][i].type == "photo" || user["blockList"][i].type == "quoteImage") { 1205 | if (user["blockList"].length - 1 >= i + 1) { 1206 | if (user["blockList"][i + 1].type == "video" || user["blockList"][i].type == "quoteVideo" || user["blockList"][i].type == "quoteImage" || user["blockList"][i + 1].type == "photo" || user["blockList"][i + 1].type == "text") { 1207 | let overLayY = ":y=0:x=0" 1208 | if (user["blockList"][i + 1].type == "photo" || user["blockList"][i].type == "quoteImage") { 1209 | overLayY = "" 1210 | 1211 | } 1212 | 1213 | if (user.animation_style == "blankslate") { 1214 | 1215 | finalAnswer += "[" + currentParam + (i + 1) + "]format=rgba,fade=t=out:st=" + f + ":d=" + 2 + ":alpha=1[a" + currentParam + (i + 1) + "]"; 1216 | finalAnswer += ";[oute" + (i + 2) + "]format=rgba,fade=t=in:st=" + f + ":d=" + 2 + ":alpha=1[aoute" + (i + 2) + "];" 1217 | finalAnswer += "[a" + currentParam + (i + 1) + "][aoute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")'" + overLayY + "[" + nextParam + (i + 2) + "];"; 1218 | 1219 | } else { 1220 | finalAnswer += "[" + currentParam + (i + 1) + "][oute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")'" + overLayY + "[" + nextParam + (i + 2) + "];"; 1221 | } 1222 | 1223 | lastP = "[outnje" + (i + 2) + "]"; 1224 | 1225 | } 1226 | } else { 1227 | if (user["blockList"][i].type == "photo" || user["blockList"][i].type == "quoteImage") { 1228 | overLayY = "" 1229 | 1230 | } 1231 | 1232 | if (user.animation_style == "blankslate") { 1233 | 1234 | finalAnswer += "[" + currentParam + (i + 1) + "]format=rgba,fade=t=out:st=" + f + ":d=" + 2 + ":alpha=1[a" + currentParam + (i + 1) + "]"; 1235 | finalAnswer += ";[oute" + (i + 2) + "]format=rgba,fade=t=in:st=" + f + ":d=" + 2 + ":alpha=1[aoute" + (i + 2) + "];" 1236 | finalAnswer += "[a" + currentParam + (i + 1) + "][aoute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")'" + overLayY + "[" + nextParam + (i + 2) + "];"; 1237 | 1238 | } else { 1239 | finalAnswer += "[" + currentParam + (i + 1) + "][oute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")'" + overLayY + "[" + nextParam + (i + 2) + "];"; 1240 | } 1241 | lastP = "[outnje" + (i + 2) + "]"; 1242 | 1243 | } 1244 | 1245 | 1246 | } else if (user["blockList"][i].type == "text") { 1247 | if (user["blockList"].length - 1 >= i + 1) { 1248 | if (user["blockList"][i + 1].type == "video" || user["blockList"][i].type == "quoteVideo" || user["blockList"][i].type == "quoteImage" || user["blockList"][i + 1].type == "photo" || user["blockList"][i + 1].type == "text") { 1249 | let overLayY = ":y=0:x=0" 1250 | if (user["blockList"][i + 1].type == "photo" || user["blockList"][i].type == "quoteImage") { 1251 | overLayY = "" 1252 | 1253 | } 1254 | finalAnswer += "[" + currentParam + (i + 1) + "][oute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")'" + overLayY + "[" + nextParam + (i + 2) + "];"; 1255 | lastP = "[outnje" + (i + 2) + "]"; 1256 | } 1257 | } else { 1258 | if (user["blockList"][i].type == "photo" || user["blockList"][i].type == "quoteImage") { 1259 | overLayY = "" 1260 | } 1261 | if (user.animation_style == "blankslate") { 1262 | finalAnswer += "[oute" + (i + 1) + "]format=rgba,fade=t=out:st=" + f + ":d=" + 2 + ":alpha=1[aoute" + (i + 1) + "]"; 1263 | finalAnswer += ";[oute" + (i + 2) + "]format=rgba,fade=t=in:st=" + f + ":d=" + 2 + ":alpha=1[aoute" + (i + 2) + "];" 1264 | finalAnswer += "[aoute" + (i + 1) + "][aoute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")'" + overLayY + "[" + nextParam + (i + 2) + "];"; 1265 | 1266 | } else { 1267 | finalAnswer += "[oute" + (i + 1) + "][oute" + (i + 2) + "]overlay=enable='between(t\\," + f + "," + (user.total_sec) + ")'" + overLayY + "[" + nextParam + (i + 2) + "];"; 1268 | } 1269 | 1270 | lastP = "[outnje" + (i + 2) + "]"; 1271 | } 1272 | 1273 | 1274 | } 1275 | 1276 | } 1277 | } 1278 | let ap = [] 1279 | if (this.global_data.source.length > 0) { 1280 | ap.push("-map", (lmS + 1) + ":a") 1281 | } 1282 | let finalLine = ["-y", "-r", "30", "-f", "lavfi", "-i", "color=black:s=" + user.iWidth + "x" + user.iHeight] 1283 | finalLine.push(...addition); 1284 | let fileName = "1080p"; 1285 | if (isPreview) 1286 | fileName = "270p"; 1287 | globalFilters = "yuv444p"; 1288 | finalLine.push("-filter_complex", finalAnswer.substr(0, finalAnswer.length - 1), "-map", lastP, ...ap, "-t", user.total_sec, "-profile:v", "baseline", "-level", "3.0", "-movflags", "+faststart", "-pix_fmt", "yuv420p", Config.output_directory + path.sep + id + path.sep + fileName + ".mp4"); 1289 | return finalLine; 1290 | } 1291 | } 1292 | module.exports = AnimBulletin; -------------------------------------------------------------------------------- /DemoOutputVideos/Type-Photo!AlignH-Center!AlignV-Center!Crop-Full/1080p.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/DemoOutputVideos/Type-Photo!AlignH-Center!AlignV-Center!Crop-Full/1080p.mp4 -------------------------------------------------------------------------------- /DemoOutputVideos/Type-Photo!AlignH-Left!AlignV-Top!Crop-Full/1080p.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/DemoOutputVideos/Type-Photo!AlignH-Left!AlignV-Top!Crop-Full/1080p.mp4 -------------------------------------------------------------------------------- /DemoOutputVideos/Type-Photo!AlignH-Right!AlignV-Bottom!Crop-Full/1080p.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/DemoOutputVideos/Type-Photo!AlignH-Right!AlignV-Bottom!Crop-Full/1080p.mp4 -------------------------------------------------------------------------------- /DemoOutputVideos/Type-Video!AlignH-Center!AlignV-Center!Crop-Full/1080p.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/DemoOutputVideos/Type-Video!AlignH-Center!AlignV-Center!Crop-Full/1080p.mp4 -------------------------------------------------------------------------------- /DemoOutputVideos/Type-Video!AlignH-Left!AlignV-Top!Crop-FitToFrame/1080p.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/DemoOutputVideos/Type-Video!AlignH-Left!AlignV-Top!Crop-FitToFrame/1080p.mp4 -------------------------------------------------------------------------------- /DemoOutputVideos/Type-Video!AlignH-Left!AlignV-Top!Crop-Full/1080p.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/DemoOutputVideos/Type-Video!AlignH-Left!AlignV-Top!Crop-Full/1080p.mp4 -------------------------------------------------------------------------------- /DemoOutputVideos/Type-Video!AlignH-Left!AlignV-Top!Crop-Left/1080p.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/DemoOutputVideos/Type-Video!AlignH-Left!AlignV-Top!Crop-Left/1080p.mp4 -------------------------------------------------------------------------------- /DemoOutputVideos/Type-Video!AlignH-Left!AlignV-Top!Crop-Right/1080p.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/DemoOutputVideos/Type-Video!AlignH-Left!AlignV-Top!Crop-Right/1080p.mp4 -------------------------------------------------------------------------------- /DemoOutputVideos/Type-Video!AlignH-Right!AlignV-Bottom!Crop-Full/1080p.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/DemoOutputVideos/Type-Video!AlignH-Right!AlignV-Bottom!Crop-Full/1080p.mp4 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Shubham Dawra 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Animated VideoMaker 2 | ### Create animatied text videos like Animoto using NodeJS -> ImageMagick & Ffmpeg 3 | 4 | Note: On low configuration machine it can take time to process frames because it uses imagemagick to generate frame by frame transition or movement animation and after generating all blocks animation it merges them in a Video. 5 | # Installation 6 | # Prerequisite 7 | **Install ImageMagick-7.1.0-Q16** 8 | **Install Ffmpeg-20180209-e752da5** 9 | **Download "Roboto" font** 10 | Install RabbitMQ 3.8.2 11 | Install imagemagick & extract ffmpeg 12 | ``` 13 | Open config.js and edit 14 | ffmpeg_path = "Installed path" (E:\\Ffmpeg\\ffmpeg.exe) Line : 3 15 | magick_path = "Installed path" (E:\\Imagemagick\\magick.exe) Line : 5 16 | convert_path = "Installed path" (E:\\Imagemagick\\convert.exe) Line : 4 17 | roboto_light = Robot Light font ttf file (E:\\Font\\Robot-Light.ttf) Line : 8 18 | roboto_bold = Robot Bold font ttf file (E:\\Font\\Robot-Bold.ttf) Line : 7 19 | socket_ip = Get current local ip of your local computer (ipconfig) Line : 10 20 | port = Port number must be same used in socket IP Line : 20 21 | ``` 22 | Open console window cd in the directory & run npm install 23 | 24 | After that run command npm run start in one console window 25 | 26 | run second command in other console window npm run worker 27 | 28 | Run your ip address and port like http://192.168.1.107:82/assets/ 29 | 30 | Put video or pic url in url box 31 | 32 | Select Type photo or video 33 | 34 | Put timing greater then 3 and less then 15 (Use less timing if you are on low configured machine because it take too much time too process frames and merge them in a video) 35 | 36 | **Font size = Main text font size** 37 | 38 | **Title = Animated text for main line** 39 | 40 | **Sub font size = Sub text font size** 41 | 42 | **Sub Title = Animated text for sub text line** 43 | 44 | **Horizontal alignment of text = Left Right or Center** 45 | 46 | **Vertical alignment of text = Top Bottom or Center** 47 | 48 | **Crop style you can check demo videos** 49 | 50 | **Click on Add Row** to add blocks like first is photo and second is video then photo or ... 51 | 52 | **Click on Submit HD Video** to generate frames and merge them in video in 1080,720,360,240 resolution 53 | 54 | # Demo Videos 55 | 56 | Video = Type || Alignment Horizontal = Left || Alignment Vertical = Top || Crop = Full 57 | 58 | https://user-images.githubusercontent.com/35697452/144758975-e5889178-a94d-4251-a88d-ea842378e59e.mp4 59 | 60 | Video = Type || Alignment Horizontal = Right || Alignment Vertical = Bottom || Crop = Full 61 | 62 | https://user-images.githubusercontent.com/35697452/144758981-95b17aad-44c2-4d9f-81a9-806392ef45c7.mp4 63 | 64 | Video = Type || Alignment Horizontal = Center || Alignment Vertical = Center || Crop = Full 65 | 66 | https://user-images.githubusercontent.com/35697452/144759017-28af9cf8-67ec-4ffb-b0e0-992885fc607f.mp4 67 | 68 | Video = Type || Alignment Horizontal = Left || Alignment Vertical = Top || Crop = Fitoframe 69 | 70 | https://user-images.githubusercontent.com/35697452/144759039-3b727d45-6fbb-4ded-a9ce-de1f129177da.mp4 71 | 72 | Video = Type || Alignment Horizontal = Left || Alignment Vertical = Top || Crop = Left 73 | 74 | https://user-images.githubusercontent.com/35697452/144759070-eaed6e25-4f8d-4b82-92bb-c58c2e61bae9.mp4 75 | 76 | Photo = Type || Alignment Horizontal = Left || Alignment Vertical = Top || Crop = Full 77 | 78 | https://user-images.githubusercontent.com/35697452/144759162-d7b1d94e-1c75-4c5b-9126-3756bf8382ea.mp4 79 | 80 | Photo = Type || Alignment Horizontal = Right || Alignment Vertical = Bottom || Crop = Full 81 | 82 | https://user-images.githubusercontent.com/35697452/144759177-bdbac2ef-16c6-43de-ac40-6632fb7be7d7.mp4 83 | 84 | Photo = Type || Alignment Horizontal = Center || Alignment Vertical = Center || Crop = Full 85 | 86 | https://user-images.githubusercontent.com/35697452/144759184-6b4241ac-5817-4bea-ac19-0a066db46740.mp4 87 | 88 | 89 | 90 | # Todo : 91 | 92 | ### More animation theme. 93 | 94 | ### Optimization & cleaning of code. 95 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const utils = require('./utils.js'); 2 | const Config= require('./config.js'); 3 | const AnimBulletin = require('./AnimationBulletin.js'); 4 | const fs = require('fs').promises; 5 | let path = require('path'); 6 | const express=require('express') 7 | let app =express(); 8 | let amqp = require('amqplib/callback_api'); 9 | app.use(express.json()); 10 | app.use(function(req, res, next) { 11 | res.header("Access-Control-Allow-Origin", "*"); // update to match the domain you will make the request from 12 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 13 | next(); 14 | }); 15 | app.use('/assets',express.static(__dirname + path.sep+'assets')); 16 | let preview_status = []; 17 | let animBullet =new AnimBulletin("Bulletin"); 18 | let dynamicJson='\'{"name":"Project Name","uploadedMedia":[{"type":"photo","thumbnail":"http://192.168.1.107:82/assets/Image/id/print.jpg","url":"http://192.168.1.107:82/assets/Image/id/print.jpg"},{"type":"video","thumbnail":"http://192.168.1.107:82/assets/Footage/id/o.jpg","url":"http://192.168.1.107:82/assets/Footage/id/720p-sample1.mp4"},{"type":"photo","thumbnail":"http://192.168.1.107:82/assets/Image/id/o.jpg","url":"http://192.168.1.107:82/assets/Image/id/o.jpg"},{"type":"video","thumbnail":"http://192.168.1.107:82/assets/Footage/id/360p-sample1.jpg","url":"http://192.168.1.107:82/assets/Footage/id/270p-sample1.mp4"}],"global":{"backgroundMusic":{"source":"http://192.168.1.107:82/assets/Audio/audio.mpeg","volume":0.5,"loop":true,"trimAudio":{"trim":false,"value":{"start":0,"end":34}}},"filter":"none","aspectRatio":"landscape","style":"hiRise","font":"Roboto","watermark":{"source":"xxx","position":"top-right","size":"medium","transparency":true}},"blocks":[]}\';'; 19 | let server = require('http').Server(app); 20 | let io = require('socket.io')(server); 21 | server.listen(Config.port); 22 | 23 | let modifyIndex =()=>{ 24 | let assetsTemplateIndex = __dirname + path.sep+'assets'+path.sep+'template_index'; 25 | let assetsIndex = __dirname + path.sep+'assets'+path.sep+'index.html'; 26 | fs.readFile(assetsTemplateIndex, 'utf8').then((data)=>{ 27 | var result = data.replace(/192.168.1.107:82/g, Config.socket_ip); 28 | 29 | fs.writeFile(assetsIndex, result, 'utf8'); 30 | }); 31 | 32 | } 33 | let storeData = function (data, path) { 34 | fs.writeFile(path,JSON.stringify(data)).catch(function(){console.error(err)}); 35 | } 36 | let writeFileData = function(is_preview,id,id_string){ 37 | return new Promise(function(resolve,reject){ 38 | console.log(Config.output_directory+'id',id,id_string); 39 | fs.writeFile(Config.output_directory+'id',id.toString()).then(()=> 40 | resolve({isPreview:is_preview,error:null, result:{status : "succeed",id:id_string}})) 41 | .catch(function(err){ 42 | console.log(err); 43 | resolve({isPreview:is_preview,error:'error', result:{status : "error",id:id_string}}); 44 | }); 45 | }) 46 | } 47 | let writeFolderId = function(is_preview,id) { 48 | return new Promise(function(resolve,reject){ 49 | id=parseInt(id)+1; 50 | let id_string=id.toLocaleString('en-US', { minimumIntegerDigits: 10, useGrouping: false }); 51 | let directory=Config.output_directory+id_string; 52 | utils.checkFileExists(directory).then(function(isExist){ 53 | if(isExist){ 54 | utils.deleteFolderRecursive(directory); 55 | fs.mkdir(directory).then(function(){ 56 | fs.mkdir(directory+path.sep+"data"+path.sep); 57 | writeFileData(is_preview,id,id_string).then(function(val){ 58 | resolve(val); 59 | }); 60 | }); 61 | }else{ 62 | fs.mkdir(directory).then(function(){ 63 | fs.mkdir(directory+path.sep+"data"+path.sep); 64 | writeFileData(is_preview,id,id_string).then(function(val){ 65 | resolve(val); 66 | }); 67 | }).catch(function(err){ 68 | console.log(err); 69 | }); 70 | } 71 | }); 72 | }); 73 | }; 74 | modifyIndex(); 75 | app.get('/:id/:file', function (req, res) { 76 | let id = req.params.id 77 | let file = req.params.file 78 | let fileDownload = __dirname + path.sep+'download' + path.sep+id+ path.sep+file; 79 | res.download(fileDownload); 80 | 81 | 82 | }); 83 | app.get('/', function (req, res) { 84 | let jsonString='{"name":"Project Name","uploadedMedia":[{"type":"image","thumbnail":"http://localhost:82/assets/Image/id/print.jpg","url":"http://localhost:82/assets/Image/id/print.jpg"},{"type":"video","thumbnail":"http://localhost:82/assets/Footage/id/o.jpg","url":"http://localhost:82/assets/Footage/id/720p-sample1.mp4"},{"type":"image","thumbnail":"http://localhost:82/assets/Image/id/o.jpg","url":"http://localhost:82/assets/Image/id/o.jpg"},{"type":"video","thumbnail":"http://localhost:82/assets/Footage/id/360p-sample1.jpg","url":"http://localhost:82/assets/Footage/id/270p-sample1.mp4"}],"global":{"backgroundMusic":{"source":"http://localhost:82/assets/audio/audio.mpeg","volume":0.5,"loop":true,"trimAudio":{"trim":false,"value":{"start":0,"end":34}}},"filter":"none","aspectRatio":"landscape","style":"hiRise","font":"Roboto","watermark":{"source":"xxx","position":"top-right","size":"medium","transparency":true}},"blocks":[{"id":0,"type":"image","timing":3,"voiceover":{"present":false,"source":"","volume":1},"text":{"title":{"content":"Title text","fontSize":50,"color":"#ffffff"},"subTitle":{"content":"subtitle text","fontSize":20,"color":"#ffffff"},"legibility":false,"legibilityColor":"#000","accent":"#F8AF00","align":{"vertical":"center","horizontal":"center"}},"background":{"media":"http://localhost:82/assets/Image/id/print.jpg","scale":1,"position":{"x":0,"y":0},"rotate":0,"crop":"Fullscreen","color":"#ccc"}},{"id":1,"type":"video","timing":10,"trim":{"start":0,"end":10},"voiceover":{"present":false,"source":"","volume":1},"text":{"title":{"content":"Title text","fontSize":50,"color":"#ffffff"},"subTitle":{"content":"subtitle text","fontSize":20,"color":"#ffffff"},"legibility":false,"legibilityColor":"#000","accent":"#F8AF00","align":{"vertical":"center","horizontal":"center"}},"background":{"media":"http://localhost:82/assets/Footage/id/720p-sample1.mp4","sound":false,"volume":1,"scale":1,"position":{"x":0,"y":0},"rotate":0,"crop":"Fullscreen","color":"#ccc"}},{"id":2,"type":"image","timing":3,"voiceover":{"present":false,"source":"","volume":1},"text":{"title":{"content":"Title text","fontSize":50,"color":"#ffffff"},"subTitle":{"content":"subtitle text","fontSize":20,"color":"#ffffff"},"legibility":false,"legibilityColor":"#000","accent":"#F8AF00","align":{"vertical":"center","horizontal":"center"}},"background":{"media":"http://localhost:82/assets/Image/id/o.jpg","scale":1,"position":{"x":0,"y":0},"rotate":0,"crop":"Fullscreen","color":"#ccc"}},{"id":3,"type":"video","timing":10,"trim":{"start":0,"end":10},"voiceover":{"present":false,"source":"","volume":1},"text":{"title":{"content":"Title text","fontSize":50,"color":"#ffffff"},"subTitle":{"content":"subtitle text","fontSize":20,"color":"#ffffff"},"legibility":false,"legibilityColor":"#000","accent":"#F8AF00","align":{"vertical":"center","horizontal":"center"}},"background":{"media":"http://localhost:82/assets/Footage/id/270p-sample1.mp4","sound":false,"volume":1,"scale":1,"position":{"x":0,"y":0},"rotate":0,"crop":"Fullscreen","color":"#ccc"}}]}'; 85 | res.send( 86 | "
" 87 | +"
")}) 90 | app.post(/^\/(upload|preview)\_json$/, function (req, res) { 91 | let path=req.path.substring(1) 92 | if(path=="upload_json"){ 93 | uploadJson(req.body,res,false) 94 | }else{ 95 | uploadJson(req.body,res,true,false) 96 | } 97 | }); 98 | 99 | let uploadJson = async function(json,res,isPreview=false,isTesting=false){ 100 | console.log(isPreview,"PREVIEW"); 101 | if(Config.connection!=null){ 102 | processJson(json,res,isPreview,isTesting); 103 | }else{ 104 | amqp.connect('amqp://localhost', function(error0, connection) { 105 | if (error0) { 106 | throw(error0); 107 | } 108 | connection.createChannel(function(error1, channel) { 109 | Config.ch=channel 110 | if (error1) { 111 | throw(error1); 112 | } 113 | processJson(json,res,isPreview,isTesting); 114 | }) 115 | }); 116 | } 117 | } 118 | 119 | let processJson = async function (json,res,is_preview=false,isTesting=false){ 120 | let id="0"; 121 | let pathUID=Config.output_directory+"id"; 122 | let fileExistPromise = utils.checkFileExists(pathUID); 123 | fileExistPromise.then(function(value){ 124 | let idNumberPromise = fs.readFile(pathUID); 125 | idNumberPromise.catch(function(err){ 126 | }).then(function(idNumber){ 127 | writeFolderId(is_preview,idNumber.toString().trim()).then(function(response){ 128 | if(response.err){ 129 | console.log("Already Exists"); 130 | let js={id:"none",socket_url:Config.socket_ip}; 131 | res.send(js); 132 | }else{ 133 | console.log("Saved"); 134 | id=response.result.id 135 | let js={id:response.result.id,socket_url:Config.socket_ip} 136 | res.send(js) 137 | storeData(json,path.join(__dirname, 'download')+ path.sep+id+ path.sep+"data"+path.sep+"data.json") 138 | preview_status[id] = response.isPreview; 139 | dataUploaded() 140 | } 141 | }).catch(function(obj){ 142 | console.log(obj); 143 | }); 144 | }); 145 | }) 146 | .catch(function(value){ 147 | writeFolderId(is_preview,id.toString().trim()).then(function(value){ 148 | if(value.err){ 149 | console.log("Already Exists") 150 | let js={id:"none",socket_url:Config.socket_ip} 151 | res.send(js) 152 | }else{ 153 | console.log("Saved") 154 | id=value.result.id 155 | let js={id:value.result.id,socket_url:Config.socket_ip} 156 | res.send(js) 157 | storeData(json,path.join(__dirname, 'download')+ path.sep+id+path.sep+"data"+path.sep+"data.json"); 158 | preview_status[id] = value.isPreview; 159 | dataUploaded(); 160 | } 161 | }).catch(function(obj){ 162 | console.log(obj); 163 | }); 164 | }); 165 | } 166 | 167 | let dataUploaded = function(){ 168 | io.use(function(socket, next){ 169 | let id = socket.handshake.query.id 170 | let isPreview=preview_status[id]; 171 | if(typeof(socket)==="undefined"){ 172 | console.log("Undefined") 173 | }else{ 174 | if(typeof(Config.users[id])==="undefined"){ 175 | let obj={} 176 | obj.blockList=[] 177 | obj.socket = socket; 178 | Config.users[id]=(obj) 179 | if(isPreview){ 180 | animBullet.run(id,true); 181 | }else{ 182 | animBullet.run(id,false); 183 | } 184 | } 185 | } 186 | 187 | 188 | io.on('connection', function (socket) { 189 | if(!Config.users[id]){ 190 | if(isPreview){ 191 | Config.users[id].socket.emit('status', {'status':'started', 192 | 'is_preview':'true' 193 | ,video_url:{url:'none'} }); 194 | }else{ 195 | Config.users[id].socket.emit('status', {'status':'started', 196 | videos_progress:{'360p':0,'480p':0,'720p':0,'1080p':0} 197 | ,videos_url:{'360p':'none','480p':'none','720p':'none','1080p':'none'} }); 198 | } 199 | console.log("Connected"); 200 | } 201 | }); 202 | next(); 203 | }); 204 | } 205 | 206 | io.on('disconnect', function () { 207 | Config.users[current.id].socket.removeAllListeners(); 208 | Config.users[current.id].socket.disconnect() 209 | Config.users.splice(current.id,1) 210 | preview_status.splice(current.id,1) 211 | }); -------------------------------------------------------------------------------- /assets/Audio/audio.mpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/assets/Audio/audio.mpeg -------------------------------------------------------------------------------- /assets/Font/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/assets/Font/Roboto-Bold.ttf -------------------------------------------------------------------------------- /assets/Font/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/assets/Font/Roboto-Light.ttf -------------------------------------------------------------------------------- /assets/Footage/id/720p-sample1.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/assets/Footage/id/720p-sample1.mp4 -------------------------------------------------------------------------------- /assets/Image/id/block_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/assets/Image/id/block_1.jpg -------------------------------------------------------------------------------- /assets/Image/id/block_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/assets/Image/id/block_3.jpg -------------------------------------------------------------------------------- /assets/Image/id/o.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubhamdevhouse/Animated-VideoMaker/b89cc33c9cd1503cf576b0b0bb88bd8f3f29914c/assets/Image/id/o.jpg -------------------------------------------------------------------------------- /assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 232 |
233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 |
Source URLTypeTimingTitleSubtitleAlignment HorizontalAlignment VerticalCropStyle
252 |
253 |
254 | 255 |
256 |
257 | 258 |
259 |
260 | 261 |

262 |
263 |
264 |
265 |
266 | 267 | 268 |
269 |
270 |
271 | 272 | 273 | 274 |
275 |
276 |
277 |
278 |
279 |
280 | 281 | 282 |
283 |
284 | 285 |
286 | 287 | 288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 | 297 | 298 | 299 |
300 | 301 |
302 |
303 | 304 | 305 | 306 |
307 |

308 |
309 |
310 | 311 | 312 | 313 |
314 |
315 |
316 |
317 | 318 | 319 |
320 |
321 |
322 |
323 | 324 |
325 |
326 | 327 |
328 |
329 |
330 |
331 |
332 | 333 |
334 |
335 |
-------------------------------------------------------------------------------- /assets/template_index: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 232 |
233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 |
Source URLTypeTimingTitleSubtitleAlignment HorizontalAlignment VerticalCropStyle
252 |
253 |
254 | 255 |
256 |
257 | 258 |
259 |
260 | 261 |

262 |
263 |
264 |
265 |
266 | 267 | 268 |
269 |
270 |
271 | 272 | 273 | 274 |
275 |
276 |
277 |
278 |
279 |
280 | 281 | 282 |
283 |
284 | 285 |
286 | 287 | 288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 | 297 | 298 | 299 |
300 | 301 |
302 |
303 | 304 | 305 | 306 |
307 |

308 |
309 |
310 | 311 | 312 | 313 |
314 |
315 |
316 |
317 | 318 | 319 |
320 |
321 |
322 |
323 | 324 |
325 |
326 | 327 |
328 |
329 |
330 |
331 |
332 | 333 |
334 |
335 |
-------------------------------------------------------------------------------- /classes/Text.js: -------------------------------------------------------------------------------- 1 | 2 | const fs = require('fs'); 3 | class Text { 4 | 5 | constructor(metricFile, fontSize = 50, defaultFontsize = 500) { 6 | this.fontSize = fontSize; 7 | this.defaultFontSize = defaultFontsize; 8 | this.text = ""; 9 | this.lines = []; 10 | let self = this; 11 | fs.readFile(metricFile, { encoding: 'utf-8' }, function (err, data) { 12 | if (!err) { 13 | self.fontMetrics = JSON.parse(data); 14 | } else { 15 | console.log(err); 16 | } 17 | }); 18 | } 19 | getMaxWidth = () => { 20 | return this.maxWidth; 21 | } 22 | setMaxWidth = (value) => { 23 | this.maxWidth = value; 24 | } 25 | getDefaultFontSize = () => { 26 | return this.defaultFontsize; 27 | } 28 | setDefaultFontSize = (value) => { 29 | this.defaultFontsize = value; 30 | } 31 | getFontSize = () => { 32 | return this.fontSize; 33 | } 34 | setFontSize = (value) => { 35 | this.fontSize = value; 36 | } 37 | getText = () => { 38 | return this.text; 39 | } 40 | 41 | setText = (value) => { 42 | this.text = value; 43 | } 44 | 45 | getMetricData = (word) => { 46 | let width = 0; 47 | let ascent = 0; 48 | let descent = 0; 49 | 50 | for (let i = 0; i < word.length; i++) { 51 | let charMetric = this.fontMetrics[word[i]]; 52 | width += Math.round((charMetric.width / this.getDefaultFontSize()) * this.getFontSize()); 53 | let optimizedAscent = Math.round((charMetric.ascent / this.getDefaultFontSize()) * this.getFontSize()); 54 | let optimizedDescent = Math.round((charMetric.descent / this.getDefaultFontSize()) * this.getFontSize()); 55 | if (optimizedAscent > ascent) { 56 | ascent = optimizedAscent; 57 | } 58 | if (optimizedDescent > descent) { 59 | descent = optimizedDescent; 60 | } 61 | 62 | 63 | } 64 | let metricObject = { width, ascent, descent }; 65 | return metricObject; 66 | } 67 | validateWord = (splitted, word, index) => { 68 | let wordWidth = 0; 69 | if (index >= splitted.length) { return; } 70 | for (let i = 0; i < word.length; i++) { 71 | let charWidth = Math.round((this.fontMetrics[word[i]].width / this.getDefaultFontSize()) * this.getFontSize()); 72 | if (wordWidth + charWidth >= this.getMaxWidth()) { 73 | let tempWord = word.substr(0, i); 74 | let restWord = word.substr(i); 75 | splitted.splice(index + 1, 0, restWord); 76 | splitted[index] = tempWord; 77 | break; 78 | } else { wordWidth += charWidth; } 79 | } 80 | this.validateWord(splitted, splitted[index + 1], index + 1); 81 | 82 | } 83 | 84 | getLine = (splitted, text, textWidth, index, oldMetricObj) => { 85 | let metricObj = this.getMetricData(splitted[index]); 86 | 87 | let wordWidth = metricObj.width; 88 | console.log(metricObj, "dataMetric"); 89 | if (textWidth + wordWidth > this.getMaxWidth()) { 90 | 91 | let textSplit = text.split(" "); 92 | textSplit.pop(); 93 | 94 | let textString = textSplit.join(" "); 95 | let widthWithSpace = textWidth + (textSplit.length * ((this.fontMetrics[" "].width / this.getDefaultFontSize()) * this.getFontSize())); 96 | console.log({ width: widthWithSpace, text: textString, ascent: oldMetricObj.ascent, descent: oldMetricObj.descent }, "NewLine"); 97 | 98 | this.lines.push({ width: widthWithSpace, text: textString, ascent: oldMetricObj.ascent, descent: oldMetricObj.descent }); 99 | return this.getLine(splitted, splitted[index], 0, index, metricObj); 100 | 101 | } else { 102 | if (index + 1 >= splitted.length) { 103 | 104 | let widthWithSpace = (wordWidth + textWidth) + ((text.split(" ").length - 1) * ((this.fontMetrics[" "].width / this.getDefaultFontSize()) * this.getFontSize())); 105 | console.log(wordWidth, textWidth, text, this.fontMetrics[" "].width); 106 | console.log({ width: widthWithSpace, text, ascent: metricObj.ascent, descent: metricObj.descent }, "NewLine"); 107 | this.lines.push({ width: widthWithSpace, text, ascent: metricObj.ascent, descent: metricObj.descent }); 108 | console.log(this.lines); 109 | return this.lines; 110 | } 111 | 112 | if (oldMetricObj.width > metricObj.width) 113 | metricObj.width = oldMetricObj.width 114 | 115 | if (oldMetricObj.ascent > metricObj.ascent) 116 | metricObj.ascent = oldMetricObj.ascent 117 | 118 | if (oldMetricObj.descent > metricObj.descent) 119 | metricObj.descent = oldMetricObj.descent 120 | 121 | return this.getLine(splitted, text + " " + splitted[index + 1], textWidth + wordWidth, index + 1, metricObj); 122 | } 123 | } 124 | 125 | generateText = (text, width, fontSize, defaultFontSize = 500) => { 126 | this.lines = []; 127 | this.setFontSize(fontSize); 128 | this.setMaxWidth(width); 129 | this.setDefaultFontSize(defaultFontSize); 130 | let splittedText = text.split(" "); 131 | this.validateWord(splittedText, splittedText[0], 0); 132 | return this.getLine(splittedText, splittedText[0], 0,0,{ width:0, ascent:0, descent:0 }); 133 | } 134 | 135 | 136 | 137 | 138 | } 139 | module.exports = Text; -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | class Config{ 3 | static ffmpeg_path = "E:\\ffmpeg\\bin\\ffmpeg"; 4 | static convert_path = "C:\\Program Files\\ImageMagick-7.1.0-Q16\\magick"; 5 | static magick_path = "C:\\Program Files\\ImageMagick-7.1.0-Q16\\magick"; 6 | static output_directory = path.join(__dirname, 'download')+path.sep; 7 | static roboto_bold = "E:\\animoto_reference\\Animated-VideoMaker\\assets\\Font\\Roboto-Bold.ttf"; 8 | static roboto_light = "E:\\animoto_reference\\Animated-VideoMaker\\assets\\Font\\Roboto-Light.ttf"; 9 | static roboto_bold_metric = "E:\\animoto_reference\\Animated-VideoMaker\\fontcode\\robotobold.json"; 10 | static roboto_light_metric = "E:\\animoto_reference\\Animated-VideoMaker\\fontcode\\robotolight.json"; 11 | static audio = "F:\\assets\\Audio\\audio.mpeg"; 12 | static socket_ip="192.168.1.103:82"; 13 | static users=[]; 14 | static connecton=null; 15 | static ch=null; 16 | static extVideos=[".avi",".mov",".mp4"]; 17 | static extImages=[".png",".jpg",".jpeg"]; 18 | static hdWidth = 1920; 19 | static hdHeight = 1080; 20 | static previewWidth = 426; 21 | static previewHeight = 240; 22 | static port = 82; 23 | } 24 | module.exports=Config; -------------------------------------------------------------------------------- /download/id: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /ffmpeg_wrapper.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const stream_1 = require("stream"); 4 | /** 5 | * convert HH:MM:SS.mss to milliseconds 6 | */ 7 | function humanTime2msec(timeString) { 8 | const [h, m, s] = timeString.split(':').map(Number); 9 | return Math.round(h * 36e5 + m * 6e4 + s * 1e3); 10 | } 11 | /** 12 | * 13 | * @param data 14 | * @param duration video duration (milliseconds) 15 | */ 16 | function parseProgress(data, duration,index) { 17 | if (data.startsWith('frame=')) { 18 | const evt = {}; 19 | const info = data 20 | .replace(/=\s+/g, '=') 21 | .trim() 22 | .split(/\s+/g); 23 | info.forEach(kv => { 24 | const [k, v] = kv.split('='); 25 | switch (k) { 26 | case 'frame': 27 | case 'fps': 28 | evt[k] = +v; 29 | break; 30 | case 'bitrate': 31 | case 'speed': 32 | evt[k] = Number.parseFloat(v); 33 | break; 34 | case 'Lsize': 35 | case 'size': 36 | evt['size'] = Number.parseInt(v) * 1024; 37 | break; 38 | case 'total_size': 39 | evt['size'] = +v; 40 | break; 41 | case 'out_time': 42 | case 'time': 43 | evt['time'] = v; 44 | // eslint-disable-next-line @typescript-eslint/camelcase 45 | evt.time_ms = humanTime2msec(evt.time); 46 | break; 47 | default: 48 | if (v) { 49 | evt[k] = v; 50 | } 51 | break; 52 | } 53 | }); 54 | evt.index=index 55 | if (duration) { 56 | evt.percentage = +((100 * evt.time_ms) / duration).toFixed(2); 57 | evt.remaining = Math.floor((duration - evt.time_ms) * evt.speed); 58 | } 59 | return evt; 60 | } 61 | return; 62 | } 63 | exports.parseProgress = parseProgress; 64 | /** 65 | * Extract progress status from FFMPEG stderr. 66 | * @public 67 | */ 68 | class FFMpegProgress extends stream_1.Transform { 69 | /** 70 | * Creates an instance of FFMpegProgress. 71 | * @param duration - video duration (milliseconds) 72 | * If parameter is omitted - will attempt to auto-detect media duration 73 | */ 74 | constructor(duration = 0,index=0) { 75 | super({ 76 | readableObjectMode: true, 77 | writableObjectMode: true 78 | }); 79 | this.duration = duration; 80 | this.index=index 81 | /** 82 | * last ffmpeg stderr message 83 | * @beta 84 | */ 85 | this.exitMessage = ''; 86 | } 87 | _transform(chunk, encoding, done) { 88 | const str = chunk.toString(); 89 | const evt = parseProgress(str, this.duration,this.index); 90 | if (evt) { 91 | this.push(evt); 92 | } 93 | else { 94 | if (!this.duration && !evt) { 95 | const re = /(^|Duration: )(\d\d:\d\d:\d\d\.\d\d)/; 96 | const match = re.exec(str); 97 | if (match && match[2]) { 98 | this.duration = humanTime2msec(match[2]); 99 | } 100 | } 101 | this.exitMessage = str.split('\n').splice(-2)[0]; 102 | } 103 | done(); 104 | } 105 | } 106 | exports.FFMpeg_Wrapper = FFMpegProgress; 107 | -------------------------------------------------------------------------------- /fontcode/generate.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const process = require( 'process' ); 3 | const argv = key => { 4 | if ( process.argv.includes( `--${ key }` ) ) return true; 5 | const value = process.argv.find( element => element.startsWith( `--${ key }=` ) ); 6 | if ( !value ) return null; 7 | return value.replace( `--${ key }=` , '' ); 8 | } 9 | if(argv('font')==null){ 10 | console.error("No font file found!"); 11 | process.exit(1); 12 | } 13 | if(argv('output')==null){ 14 | console.error("No output file name found!"); 15 | process.exit(1); 16 | } 17 | 18 | const { createCanvas, registerFont } = require('canvas'); 19 | //'../assets/Font/Roboto-Bold.ttf' 20 | registerFont(argv('font'), { family: 'Font' }) 21 | let fontString = "~!@#$%^&*()-_+={}][|\`,./?;:'\"<>1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ "; 22 | let fontData = {}; 23 | const canvas = createCanvas(100, 100) 24 | const ctx = canvas.getContext('2d') 25 | ctx.font = '500px Font'; 26 | 27 | for(let i=0;i{ 37 | console.error(err); 38 | }); -------------------------------------------------------------------------------- /fontcode/metric.json: -------------------------------------------------------------------------------- 1 | {"0":{"baseLine":0,"width":11,"ascent":14,"descent":0},"1":{"baseLine":0,"width":11,"ascent":14,"descent":0},"2":{"baseLine":0,"width":11,"ascent":14,"descent":0},"3":{"baseLine":0,"width":11,"ascent":14,"descent":0},"4":{"baseLine":0,"width":11,"ascent":14,"descent":0},"5":{"baseLine":0,"width":11,"ascent":14,"descent":0},"6":{"baseLine":0,"width":11,"ascent":14,"descent":0},"7":{"baseLine":0,"width":11,"ascent":14,"descent":0},"8":{"baseLine":0,"width":11,"ascent":14,"descent":0},"9":{"baseLine":0,"width":11,"ascent":14,"descent":0},"~":{"baseLine":0,"width":13,"ascent":8,"descent":-4},"!":{"baseLine":0,"width":5,"ascent":14,"descent":0},"@":{"baseLine":0,"width":18,"ascent":14,"descent":4},"#":{"baseLine":0,"width":12,"ascent":14,"descent":0},"$":{"baseLine":0,"width":11,"ascent":16,"descent":2},"%":{"baseLine":0,"width":15,"ascent":14,"descent":0},"^":{"baseLine":0,"width":9,"ascent":14,"descent":-7},"&":{"baseLine":0,"width":13,"ascent":14,"descent":0},"*":{"baseLine":0,"width":9,"ascent":14,"descent":-6},"(":{"baseLine":0,"width":7,"ascent":16,"descent":4},")":{"baseLine":0,"width":7,"ascent":16,"descent":4},"-":{"baseLine":0,"width":8,"ascent":7,"descent":-5},"_":{"baseLine":0,"width":9,"ascent":0,"descent":2},"+":{"baseLine":0,"width":11,"ascent":12,"descent":-2},"=":{"baseLine":0,"width":11,"ascent":9,"descent":-3},"{":{"baseLine":0,"width":7,"ascent":16,"descent":4},"}":{"baseLine":0,"width":7,"ascent":16,"descent":4},"]":{"baseLine":0,"width":6,"ascent":17,"descent":3},"[":{"baseLine":0,"width":6,"ascent":17,"descent":3},"|":{"baseLine":0,"width":5,"ascent":14,"descent":3},"`":{"baseLine":0,"width":7,"ascent":15,"descent":-12},",":{"baseLine":0,"width":5,"ascent":3,"descent":3},".":{"baseLine":0,"width":6,"ascent":3,"descent":0},"/":{"baseLine":0,"width":7,"ascent":14,"descent":1},"?":{"baseLine":0,"width":10,"ascent":14,"descent":0},";":{"baseLine":0,"width":5,"ascent":11,"descent":3},":":{"baseLine":0,"width":6,"ascent":11,"descent":0},"'":{"baseLine":0,"width":3,"ascent":15,"descent":-10},"\"":{"baseLine":0,"width":6,"ascent":15,"descent":-10},"<":{"baseLine":0,"width":10,"ascent":11,"descent":-2},">":{"baseLine":0,"width":10,"ascent":11,"descent":-2},"a":{"baseLine":0,"width":11,"ascent":11,"descent":0},"b":{"baseLine":0,"width":11,"ascent":15,"descent":0},"c":{"baseLine":0,"width":10,"ascent":11,"descent":0},"d":{"baseLine":0,"width":11,"ascent":15,"descent":0},"e":{"baseLine":0,"width":11,"ascent":11,"descent":0},"f":{"baseLine":0,"width":7,"ascent":15,"descent":0},"g":{"baseLine":0,"width":11,"ascent":11,"descent":4},"h":{"baseLine":0,"width":11,"ascent":15,"descent":0},"i":{"baseLine":0,"width":5,"ascent":15,"descent":0},"j":{"baseLine":0,"width":5,"ascent":15,"descent":4},"k":{"baseLine":0,"width":11,"ascent":15,"descent":0},"l":{"baseLine":0,"width":5,"ascent":15,"descent":0},"m":{"baseLine":0,"width":17,"ascent":11,"descent":0},"n":{"baseLine":0,"width":11,"ascent":11,"descent":0},"o":{"baseLine":0,"width":11,"ascent":11,"descent":0},"p":{"baseLine":0,"width":11,"ascent":11,"descent":4},"q":{"baseLine":0,"width":11,"ascent":11,"descent":4},"r":{"baseLine":0,"width":7,"ascent":11,"descent":0},"s":{"baseLine":0,"width":10,"ascent":11,"descent":0},"t":{"baseLine":0,"width":7,"ascent":14,"descent":0},"u":{"baseLine":0,"width":11,"ascent":11,"descent":0},"v":{"baseLine":0,"width":10,"ascent":11,"descent":0},"w":{"baseLine":0,"width":15,"ascent":11,"descent":0},"x":{"baseLine":0,"width":10,"ascent":11,"descent":0},"y":{"baseLine":0,"width":10,"ascent":11,"descent":4},"z":{"baseLine":0,"width":10,"ascent":11,"descent":0},"A":{"baseLine":0,"width":13,"ascent":14,"descent":0},"B":{"baseLine":0,"width":13,"ascent":14,"descent":0},"C":{"baseLine":0,"width":13,"ascent":14,"descent":0},"D":{"baseLine":0,"width":13,"ascent":14,"descent":0},"E":{"baseLine":0,"width":11,"ascent":14,"descent":0},"F":{"baseLine":0,"width":11,"ascent":14,"descent":0},"G":{"baseLine":0,"width":14,"ascent":14,"descent":0},"H":{"baseLine":0,"width":14,"ascent":14,"descent":0},"I":{"baseLine":0,"width":6,"ascent":14,"descent":0},"J":{"baseLine":0,"width":11,"ascent":14,"descent":0},"K":{"baseLine":0,"width":13,"ascent":14,"descent":0},"L":{"baseLine":0,"width":11,"ascent":14,"descent":0},"M":{"baseLine":0,"width":18,"ascent":14,"descent":0},"N":{"baseLine":0,"width":14,"ascent":14,"descent":0},"O":{"baseLine":0,"width":14,"ascent":14,"descent":0},"P":{"baseLine":0,"width":13,"ascent":14,"descent":0},"Q":{"baseLine":0,"width":14,"ascent":14,"descent":2},"R":{"baseLine":0,"width":13,"ascent":14,"descent":0},"S":{"baseLine":0,"width":12,"ascent":14,"descent":0},"T":{"baseLine":0,"width":12,"ascent":14,"descent":0},"U":{"baseLine":0,"width":13,"ascent":14,"descent":0},"V":{"baseLine":0,"width":13,"ascent":14,"descent":0},"W":{"baseLine":0,"width":17,"ascent":14,"descent":0},"X":{"baseLine":0,"width":13,"ascent":14,"descent":0},"Y":{"baseLine":0,"width":12,"ascent":14,"descent":0},"Z":{"baseLine":0,"width":12,"ascent":14,"descent":0}," ":{"baseLine":0,"width":5,"ascent":0,"descent":1}} -------------------------------------------------------------------------------- /fontcode/robotobold.json: -------------------------------------------------------------------------------- 1 | {"0":{"baseLine":-11,"width":287,"ascent":360,"descent":5},"1":{"baseLine":-11,"width":287,"ascent":356,"descent":0},"2":{"baseLine":-11,"width":287,"ascent":360,"descent":0},"3":{"baseLine":-11,"width":287,"ascent":360,"descent":5},"4":{"baseLine":-11,"width":287,"ascent":355,"descent":0},"5":{"baseLine":-11,"width":287,"ascent":355,"descent":5},"6":{"baseLine":-11,"width":287,"ascent":359,"descent":5},"7":{"baseLine":-11,"width":287,"ascent":355,"descent":0},"8":{"baseLine":-11,"width":287,"ascent":360,"descent":5},"9":{"baseLine":-11,"width":287,"ascent":360,"descent":3},"~":{"baseLine":-11,"width":324,"ascent":202,"descent":-93},"!":{"baseLine":-11,"width":136,"ascent":355,"descent":4},"@":{"baseLine":-11,"width":448,"ascent":346,"descent":110},"#":{"baseLine":-11,"width":298,"ascent":355,"descent":0},"$":{"baseLine":-11,"width":287,"ascent":412,"descent":53},"%":{"baseLine":-11,"width":369,"ascent":361,"descent":5},"^":{"baseLine":-11,"width":219,"ascent":355,"descent":-178},"&":{"baseLine":-11,"width":328,"ascent":360,"descent":5},"*":{"baseLine":-11,"width":227,"ascent":355,"descent":-139},"(":{"baseLine":-11,"width":176,"ascent":395,"descent":111},")":{"baseLine":-11,"width":176,"ascent":395,"descent":111},"-":{"baseLine":-11,"width":194,"ascent":181,"descent":-124},"_":{"baseLine":-11,"width":223,"ascent":0,"descent":55},"+":{"baseLine":-11,"width":273,"ascent":294,"descent":-35},"=":{"baseLine":-11,"width":286,"ascent":240,"descent":-77},"{":{"baseLine":-11,"width":165,"ascent":390,"descent":88},"}":{"baseLine":-11,"width":165,"ascent":390,"descent":88},"]":{"baseLine":-11,"width":139,"ascent":414,"descent":83},"[":{"baseLine":-11,"width":139,"ascent":414,"descent":83},"|":{"baseLine":-11,"width":126,"ascent":355,"descent":66},"`":{"baseLine":-11,"width":165,"ascent":375,"descent":-299},",":{"baseLine":-11,"width":122,"ascent":60,"descent":89},".":{"baseLine":-11,"width":145,"ascent":72,"descent":3},"/":{"baseLine":-11,"width":187,"ascent":355,"descent":31},"?":{"baseLine":-11,"width":249,"ascent":360,"descent":3},";":{"baseLine":-11,"width":131,"ascent":272,"descent":89},":":{"baseLine":-11,"width":141,"ascent":272,"descent":3},"'":{"baseLine":-11,"width":81,"ascent":375,"descent":-240},"\"":{"baseLine":-11,"width":160,"ascent":375,"descent":-241},"<":{"baseLine":-11,"width":254,"ascent":269,"descent":-33},">":{"baseLine":-11,"width":258,"ascent":269,"descent":-33},"a":{"baseLine":-11,"width":268,"ascent":269,"descent":5},"b":{"baseLine":-11,"width":281,"ascent":375,"descent":5},"c":{"baseLine":-11,"width":261,"ascent":269,"descent":5},"d":{"baseLine":-11,"width":282,"ascent":375,"descent":5},"e":{"baseLine":-11,"width":270,"ascent":269,"descent":5},"f":{"baseLine":-11,"width":179,"ascent":380,"descent":0},"g":{"baseLine":-11,"width":285,"ascent":269,"descent":104},"h":{"baseLine":-11,"width":280,"ascent":375,"descent":0},"i":{"baseLine":-11,"width":133,"ascent":370,"descent":0},"j":{"baseLine":-11,"width":130,"ascent":370,"descent":107},"k":{"baseLine":-11,"width":267,"ascent":375,"descent":0},"l":{"baseLine":-11,"width":133,"ascent":375,"descent":0},"m":{"baseLine":-11,"width":433,"ascent":269,"descent":0},"n":{"baseLine":-11,"width":280,"ascent":269,"descent":0},"o":{"baseLine":-11,"width":283,"ascent":269,"descent":5},"p":{"baseLine":-11,"width":281,"ascent":269,"descent":102},"q":{"baseLine":-11,"width":282,"ascent":269,"descent":102},"r":{"baseLine":-11,"width":182,"ascent":269,"descent":0},"s":{"baseLine":-11,"width":257,"ascent":269,"descent":5},"t":{"baseLine":-11,"width":169,"ascent":329,"descent":5},"u":{"baseLine":-11,"width":280,"ascent":264,"descent":5},"v":{"baseLine":-11,"width":253,"ascent":264,"descent":0},"w":{"baseLine":-11,"width":367,"ascent":264,"descent":0},"x":{"baseLine":-11,"width":254,"ascent":264,"descent":0},"y":{"baseLine":-11,"width":251,"ascent":264,"descent":107},"z":{"baseLine":-11,"width":254,"ascent":264,"descent":0},"A":{"baseLine":-11,"width":336,"ascent":355,"descent":0},"B":{"baseLine":-11,"width":319,"ascent":355,"descent":0},"C":{"baseLine":-11,"width":327,"ascent":360,"descent":5},"D":{"baseLine":-11,"width":325,"ascent":355,"descent":0},"E":{"baseLine":-11,"width":281,"ascent":355,"descent":0},"F":{"baseLine":-11,"width":274,"ascent":355,"descent":0},"G":{"baseLine":-11,"width":341,"ascent":360,"descent":5},"H":{"baseLine":-11,"width":353,"ascent":355,"descent":0},"I":{"baseLine":-11,"width":146,"ascent":355,"descent":0},"J":{"baseLine":-11,"width":279,"ascent":355,"descent":5},"K":{"baseLine":-11,"width":317,"ascent":355,"descent":0},"L":{"baseLine":-11,"width":271,"ascent":355,"descent":0},"M":{"baseLine":-11,"width":438,"ascent":355,"descent":0},"N":{"baseLine":-11,"width":353,"ascent":355,"descent":0},"O":{"baseLine":-11,"width":345,"ascent":360,"descent":5},"P":{"baseLine":-11,"width":323,"ascent":355,"descent":0},"Q":{"baseLine":-11,"width":345,"ascent":360,"descent":64},"R":{"baseLine":-11,"width":319,"ascent":355,"descent":0},"S":{"baseLine":-11,"width":307,"ascent":360,"descent":5},"T":{"baseLine":-11,"width":309,"ascent":355,"descent":0},"U":{"baseLine":-11,"width":329,"ascent":355,"descent":5},"V":{"baseLine":-11,"width":327,"ascent":355,"descent":0},"W":{"baseLine":-11,"width":437,"ascent":355,"descent":0},"X":{"baseLine":-11,"width":318,"ascent":355,"descent":0},"Y":{"baseLine":-11,"width":309,"ascent":355,"descent":0},"Z":{"baseLine":-11,"width":303,"ascent":355,"descent":0}," ":{"baseLine":-11,"width":125,"ascent":0,"descent":1}} -------------------------------------------------------------------------------- /fontcode/robotolight.json: -------------------------------------------------------------------------------- 1 | {"0":{"baseLine":-11,"width":287,"ascent":360,"descent":5},"1":{"baseLine":-11,"width":287,"ascent":356,"descent":0},"2":{"baseLine":-11,"width":287,"ascent":360,"descent":0},"3":{"baseLine":-11,"width":287,"ascent":360,"descent":5},"4":{"baseLine":-11,"width":287,"ascent":355,"descent":0},"5":{"baseLine":-11,"width":287,"ascent":355,"descent":5},"6":{"baseLine":-11,"width":287,"ascent":359,"descent":5},"7":{"baseLine":-11,"width":287,"ascent":355,"descent":0},"8":{"baseLine":-11,"width":287,"ascent":360,"descent":5},"9":{"baseLine":-11,"width":287,"ascent":360,"descent":3},"~":{"baseLine":-11,"width":324,"ascent":202,"descent":-93},"!":{"baseLine":-11,"width":136,"ascent":355,"descent":4},"@":{"baseLine":-11,"width":448,"ascent":346,"descent":110},"#":{"baseLine":-11,"width":298,"ascent":355,"descent":0},"$":{"baseLine":-11,"width":287,"ascent":412,"descent":53},"%":{"baseLine":-11,"width":369,"ascent":361,"descent":5},"^":{"baseLine":-11,"width":219,"ascent":355,"descent":-178},"&":{"baseLine":-11,"width":328,"ascent":360,"descent":5},"*":{"baseLine":-11,"width":227,"ascent":355,"descent":-139},"(":{"baseLine":-11,"width":176,"ascent":395,"descent":111},")":{"baseLine":-11,"width":176,"ascent":395,"descent":111},"-":{"baseLine":-11,"width":194,"ascent":181,"descent":-124},"_":{"baseLine":-11,"width":223,"ascent":0,"descent":55},"+":{"baseLine":-11,"width":273,"ascent":294,"descent":-35},"=":{"baseLine":-11,"width":286,"ascent":240,"descent":-77},"{":{"baseLine":-11,"width":165,"ascent":390,"descent":88},"}":{"baseLine":-11,"width":165,"ascent":390,"descent":88},"]":{"baseLine":-11,"width":139,"ascent":414,"descent":83},"[":{"baseLine":-11,"width":139,"ascent":414,"descent":83},"|":{"baseLine":-11,"width":126,"ascent":355,"descent":66},"`":{"baseLine":-11,"width":165,"ascent":375,"descent":-299},",":{"baseLine":-11,"width":122,"ascent":60,"descent":89},".":{"baseLine":-11,"width":145,"ascent":72,"descent":3},"/":{"baseLine":-11,"width":187,"ascent":355,"descent":31},"?":{"baseLine":-11,"width":249,"ascent":360,"descent":3},";":{"baseLine":-11,"width":131,"ascent":272,"descent":89},":":{"baseLine":-11,"width":141,"ascent":272,"descent":3},"'":{"baseLine":-11,"width":81,"ascent":375,"descent":-240},"\"":{"baseLine":-11,"width":160,"ascent":375,"descent":-241},"<":{"baseLine":-11,"width":254,"ascent":269,"descent":-33},">":{"baseLine":-11,"width":258,"ascent":269,"descent":-33},"a":{"baseLine":-11,"width":268,"ascent":269,"descent":5},"b":{"baseLine":-11,"width":281,"ascent":375,"descent":5},"c":{"baseLine":-11,"width":261,"ascent":269,"descent":5},"d":{"baseLine":-11,"width":282,"ascent":375,"descent":5},"e":{"baseLine":-11,"width":270,"ascent":269,"descent":5},"f":{"baseLine":-11,"width":179,"ascent":380,"descent":0},"g":{"baseLine":-11,"width":285,"ascent":269,"descent":104},"h":{"baseLine":-11,"width":280,"ascent":375,"descent":0},"i":{"baseLine":-11,"width":133,"ascent":370,"descent":0},"j":{"baseLine":-11,"width":130,"ascent":370,"descent":107},"k":{"baseLine":-11,"width":267,"ascent":375,"descent":0},"l":{"baseLine":-11,"width":133,"ascent":375,"descent":0},"m":{"baseLine":-11,"width":433,"ascent":269,"descent":0},"n":{"baseLine":-11,"width":280,"ascent":269,"descent":0},"o":{"baseLine":-11,"width":283,"ascent":269,"descent":5},"p":{"baseLine":-11,"width":281,"ascent":269,"descent":102},"q":{"baseLine":-11,"width":282,"ascent":269,"descent":102},"r":{"baseLine":-11,"width":182,"ascent":269,"descent":0},"s":{"baseLine":-11,"width":257,"ascent":269,"descent":5},"t":{"baseLine":-11,"width":169,"ascent":329,"descent":5},"u":{"baseLine":-11,"width":280,"ascent":264,"descent":5},"v":{"baseLine":-11,"width":253,"ascent":264,"descent":0},"w":{"baseLine":-11,"width":367,"ascent":264,"descent":0},"x":{"baseLine":-11,"width":254,"ascent":264,"descent":0},"y":{"baseLine":-11,"width":251,"ascent":264,"descent":107},"z":{"baseLine":-11,"width":254,"ascent":264,"descent":0},"A":{"baseLine":-11,"width":336,"ascent":355,"descent":0},"B":{"baseLine":-11,"width":319,"ascent":355,"descent":0},"C":{"baseLine":-11,"width":327,"ascent":360,"descent":5},"D":{"baseLine":-11,"width":325,"ascent":355,"descent":0},"E":{"baseLine":-11,"width":281,"ascent":355,"descent":0},"F":{"baseLine":-11,"width":274,"ascent":355,"descent":0},"G":{"baseLine":-11,"width":341,"ascent":360,"descent":5},"H":{"baseLine":-11,"width":353,"ascent":355,"descent":0},"I":{"baseLine":-11,"width":146,"ascent":355,"descent":0},"J":{"baseLine":-11,"width":279,"ascent":355,"descent":5},"K":{"baseLine":-11,"width":317,"ascent":355,"descent":0},"L":{"baseLine":-11,"width":271,"ascent":355,"descent":0},"M":{"baseLine":-11,"width":438,"ascent":355,"descent":0},"N":{"baseLine":-11,"width":353,"ascent":355,"descent":0},"O":{"baseLine":-11,"width":345,"ascent":360,"descent":5},"P":{"baseLine":-11,"width":323,"ascent":355,"descent":0},"Q":{"baseLine":-11,"width":345,"ascent":360,"descent":64},"R":{"baseLine":-11,"width":319,"ascent":355,"descent":0},"S":{"baseLine":-11,"width":307,"ascent":360,"descent":5},"T":{"baseLine":-11,"width":309,"ascent":355,"descent":0},"U":{"baseLine":-11,"width":329,"ascent":355,"descent":5},"V":{"baseLine":-11,"width":327,"ascent":355,"descent":0},"W":{"baseLine":-11,"width":437,"ascent":355,"descent":0},"X":{"baseLine":-11,"width":318,"ascent":355,"descent":0},"Y":{"baseLine":-11,"width":309,"ascent":355,"descent":0},"Z":{"baseLine":-11,"width":303,"ascent":355,"descent":0}," ":{"baseLine":-11,"width":125,"ascent":0,"descent":1}} -------------------------------------------------------------------------------- /multi_worker.js: -------------------------------------------------------------------------------- 1 | const worker=require("./worker.js") 2 | worker(); 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "animoto_clone", 3 | "version": "1.0.0", 4 | "main": "app.js", 5 | "scripts": { 6 | "start": "nodemon --max_old_space_size=4096 app.js", 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "worker": "nodemon --max_old_space_size=2094 multi_worker.js" 9 | }, 10 | "nodemonConfig": { 11 | "ignore": [ 12 | "download/*" 13 | ] 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "ISC", 18 | "dependencies": { 19 | "@mixmaxhq/promise-pool": "^2.0.0", 20 | "amqplib": "^0.5.5", 21 | "canvas": "^2.9.1", 22 | "detect-kerning": "^2.1.2", 23 | "dotenv": "^8.2.0", 24 | "express": "^4.17.1", 25 | "fontkit": "^1.8.0", 26 | "gearmanode": "^0.9.2", 27 | "get-video-dimensions": "^1.0.0", 28 | "image-size": "^0.8.3", 29 | "moment": "^2.24.0", 30 | "moment-duration-format": "^2.3.2", 31 | "rimraf": "^3.0.2", 32 | "socket.io": "^2.3.0", 33 | "winston": "^0.7.1", 34 | "yargs": "^15.0.2" 35 | }, 36 | "devDependencies": { 37 | "font-metrics": "^0.4.3" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /utils.js: -------------------------------------------------------------------------------- 1 | const config = require('./config.js') 2 | 3 | const http = require('http'); 4 | const https = require('https'); 5 | const fs = require('fs') 6 | const getDimensions = require('get-video-dimensions'); 7 | const url = require("url"); 8 | const Path = require('path'); 9 | const Stream = require('stream').Transform 10 | class Utils { 11 | static block = { title: "", subtitle: "", type: "", url: "", width: 0, height: 0 } 12 | static tgmStruct = 13 | { 14 | currentGM: 0.0, i: 0, tgmPre: 0.0, 15 | tgmValuePre: 0.0, 16 | isRun: false, 17 | tgm: 0.0, 18 | tgmValue: 0.0, 19 | _tgm: 0.0, 20 | _tgmValue: 0.0, 21 | 22 | }; 23 | 24 | static getVideoSize = async function (file) { 25 | const dimensions = await getDimensions(file); 26 | return dimensions; 27 | 28 | } 29 | static generateRandomID = function () { 30 | // Math.random should be unique because of its seeding algorithm. 31 | // Convert it to base 36 (numbers + letters), and grab the first 9 characters 32 | // after the decimal. 33 | return '_' + Math.random().toString(36).substr(2, 9); 34 | }; 35 | static generateUuid = function () { 36 | return Math.random().toString() + 37 | Math.random().toString() + 38 | Math.random().toString(); 39 | } 40 | 41 | static runProcessWithProgress = function (argv, callback) { 42 | return new Promise((resolve, reject) => { 43 | var spawn = require('child_process').spawn 44 | var prc = spawn(config.ffmpeg_path, argv); 45 | 46 | 47 | 48 | prc.on('error', function () { 49 | console.log("Failed to start child."); 50 | }); 51 | var data = ""; 52 | prc.stdout.setEncoding('utf8'); 53 | prc.stdout.on('data', function (datae) { 54 | var str = datae.toString() 55 | var lines = str.split(/(\r?\n)/g) 56 | data += lines.join(""); 57 | 58 | }); 59 | prc.stderr.on('data', function (datae) { 60 | 61 | var lines = datae.toString(); data += lines; 62 | callback(lines, data); 63 | 64 | }); 65 | 66 | prc.stdout.on('end', function () { 67 | 68 | resolve(data) 69 | }); 70 | prc.on('exit', function () { 71 | 72 | }) 73 | prc.on('close', function (code) { 74 | reject(code); 75 | 76 | }); 77 | 78 | }) 79 | } 80 | 81 | static runProcess = function (name, argv) { 82 | 83 | return new Promise((resolve, reject) => { 84 | var spawn = require('child_process').spawn 85 | var prc = "" 86 | 87 | if (name == "ffmpeg") { 88 | prc = spawn(config.ffmpeg_path, argv); 89 | 90 | 91 | } else if (name == "convert") { 92 | console.log(argv.join(' ')); 93 | prc = spawn(config.convert_path, argv); 94 | } else if (name == "magick") { 95 | prc = spawn(config.magick_path, argv); 96 | } 97 | var data = ""; 98 | try { 99 | prc.stdout.setEncoding('utf8'); 100 | } catch (e) { 101 | throw (e) 102 | 103 | } 104 | prc.stdout.on('data', function (datae) { 105 | var str = datae.toString() 106 | var lines = str.split(/(\r?\n)/g) 107 | data += lines.join(""); 108 | 109 | }); 110 | prc.stderr.on('data', function (datae) { 111 | //Here is where the error output goes 112 | 113 | var lines = datae.toString(); 114 | data += lines; 115 | 116 | }); 117 | 118 | prc.stdout.on('end', function () { 119 | 120 | }); 121 | prc.on('exit', function () { 122 | resolve(data) 123 | }) 124 | prc.on('close', function (code) { 125 | // resolve(data) 126 | reject(code) 127 | 128 | }); 129 | 130 | }) 131 | } 132 | 133 | static deleteFolderRecursive = function (path) { 134 | if (fs.existsSync(path)) { 135 | fs.readdirSync(path).forEach((file, index) => { 136 | const curPath = Path.join(path, file); 137 | if (fs.lstatSync(curPath).isDirectory()) { // recurse 138 | Utils.deleteFolderRecursive(curPath); 139 | } else { // delete file 140 | fs.unlinkSync(curPath); 141 | } 142 | }); 143 | fs.rmdirSync(path); 144 | } 145 | }; 146 | static hexToRgb(hex) { 147 | // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") 148 | var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; 149 | hex = hex.replace(shorthandRegex, function (m, r, g, b) { 150 | return r + r + g + g + b + b; 151 | }); 152 | 153 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 154 | return result ? { 155 | r: parseInt(result[1], 16), 156 | g: parseInt(result[2], 16), 157 | b: parseInt(result[3], 16) 158 | } : null; 159 | } 160 | static async readFile(path) { 161 | return new Promise((resolve, reject) => { 162 | fs.readFile(path, 'utf8', function (err, data) { 163 | if (err) { 164 | reject(err); 165 | } 166 | resolve(data); 167 | }); 168 | }); 169 | } 170 | 171 | // function returns a Promise 172 | static getPromise(urlLink, fileName) { 173 | return new Promise((resolve, reject) => { 174 | var urlVal = new URL(urlLink); 175 | var parsed = url.parse(urlLink); 176 | var client = http; 177 | client = (urlVal.protocol == "https:") ? https : client; 178 | 179 | const request = client.get(urlLink, function (response) { 180 | 181 | var data = new Stream(); 182 | 183 | response.on('data', function (chunk) { 184 | data.push(chunk); 185 | }); 186 | 187 | response.on('end', function () { 188 | resolve("success"); 189 | 190 | fs.writeFileSync(fileName, data.read()); 191 | }); 192 | response.on('error', (error) => { 193 | console.log("errorcode") 194 | reject(error); 195 | }); 196 | }); 197 | }); 198 | } 199 | 200 | static async makeSynchronousRequest(url, file) { 201 | try { 202 | let http_promise = Utils.getPromise(url, file); 203 | await http_promise; 204 | 205 | } 206 | catch (error) { 207 | // Promise rejected 208 | console.log(error); 209 | } 210 | } 211 | static componentToHex(c) { 212 | var hex = c.toString(16); 213 | return hex.length == 1 ? "0" + hex : hex; 214 | } 215 | static rgbToHex(r, g, b) { 216 | return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); 217 | } 218 | static checkFileExists(file) { 219 | return fs.promises.access(file, fs.constants.F_OK) 220 | .then(() => (true)) 221 | .catch(() => (false)) 222 | } 223 | //Get data in between functions from index start & end 224 | static getDataInBetweenInt(text,iFrom,iTo){ 225 | let result = text.substr(iFrom, iTo ); 226 | return result; 227 | } 228 | //Get data in between 229 | static getDataInBetween(text, startText,endText){ 230 | let iFrom = this.getDataStartPoint(text,startText); 231 | let iTo = this.getDataEndPoint(text,endText); 232 | let result = this.getDataInBetweenInt(text,iFrom, iTo - iFrom ); 233 | return result; 234 | 235 | } 236 | //Get index position 237 | static getDataEndPoint(text,endText,isLast = true,startIndex = 0){ 238 | if(isLast){ 239 | return text.lastIndexOf(endText); 240 | }else{ 241 | return text.indexOf(endText,startIndex); 242 | } 243 | } 244 | //Get index position with length 245 | static getDataStartPoint(text,startText){ 246 | return text.indexOf(startText) + startText.length; 247 | } 248 | 249 | //module.exports = { runProcess,block,deleteFolderRecursive ,runProcessWithProgress,readFile,hexToRgb,rgbToHex,makeSynchronousRequest,getVideoSize,checkFileExists,generateUuid} 250 | } 251 | module.exports=Utils; -------------------------------------------------------------------------------- /worker.js: -------------------------------------------------------------------------------- 1 | const { Worker } = require('worker_threads'); 2 | let amqp = require('amqplib/callback_api'); 3 | let totalLimit = 0; 4 | const processFrames = function (date, id, commands, windex, wind, limit, channel, msg, isWorkDone, currentIndex) { 5 | if (!isWorkDone) { 6 | for (let ie = currentIndex; ie < limit; ie++) { 7 | runAgain = false; 8 | if (ie >= commands.length) { return; } 9 | new Promise((resolve, reject) => { 10 | const port = new Worker(('./workerChild.js'), { 11 | workerData: { name: commands[ie].name, cmd: commands[ie].cmd } 12 | }); 13 | port.on('message', (data) => { 14 | if (data != null && typeof (data) !== 'undefined' && data.toString().includes("error/convert.c")) { 15 | channel.sendToQueue(msg.properties.replyTo, 16 | Buffer.from(JSON.stringify({ status: 'error', id: id, message: "Incorrect data" })), { 17 | correlationId: msg.properties.correlationId 18 | }); 19 | channel.ack(msg); 20 | isWorkDone = true; 21 | } 22 | }); 23 | port.on('error', reject); 24 | port.on('exit', (code) => { 25 | console.log(wind, windex, currentIndex, limit); 26 | currentIndex++; 27 | if (wind == windex - 2) { 28 | if (currentIndex * (wind + 1) >= limit * (wind + 1)) { 29 | wind++; 30 | date = new Date(); 31 | processFrames(date, id, commands, windex, wind, commands.length, channel, msg, isWorkDone, currentIndex); 32 | } 33 | } else if (wind < windex - 2) { 34 | if (currentIndex * (wind + 1) >= limit * (wind + 1)) { 35 | limit += totalLimit; 36 | wind++; 37 | date = new Date(); 38 | processFrames(date, id, commands, windex, wind, limit, channel, msg, isWorkDone, currentIndex); 39 | } 40 | } 41 | if (currentIndex >= commands.length) { 42 | channel.sendToQueue(msg.properties.replyTo, 43 | Buffer.from(JSON.stringify({ status: 'success', id: id })), { 44 | correlationId: msg.properties.correlationId 45 | }); 46 | channel.ack(msg); 47 | isWorkDone = true; 48 | return; 49 | } 50 | if (code !== 0) 51 | reject(new Error(`Worker stopped with exit code ${code}`)); 52 | }); 53 | }); 54 | } 55 | } 56 | } 57 | function worker() { 58 | currentIndex = 0; 59 | amqp.connect('amqp://localhost', function (error, connection) { 60 | console.log(error); 61 | connection.createChannel(function (error, channel) { 62 | let queue = 'render_cmd_dev'; 63 | channel.assertQueue(queue, { 64 | durable: false 65 | }); 66 | channel.prefetch(1); 67 | console.log(" [*] Waiting for messages in %s. To exit press CTRL+C", queue); 68 | channel.consume(queue, function reply(msg) { 69 | let content = JSON.parse(msg.content.toString()); 70 | 71 | if(typeof(content.commands)!=='undefined'){ 72 | console.log(content); 73 | totalLimit = content.tLimit; 74 | let commands = content.commands; 75 | let id = content.id; 76 | let date = content.date; 77 | let isWorkDone = false; 78 | let windex = content.commands.length < totalLimit ? 1 : parseInt(content.commands.length / totalLimit) 79 | if (windex == 1) { 80 | channel.ack(msg); 81 | } else { 82 | console.log("RUN", windex, date, id, windex, 0, totalLimit) 83 | processFrames(date, id, commands, windex, 0, totalLimit, channel, msg, isWorkDone, currentIndex); 84 | } 85 | } else { 86 | channel.ack(msg); 87 | } 88 | }); 89 | 90 | 91 | }); 92 | }); 93 | } 94 | module.exports = worker -------------------------------------------------------------------------------- /workerChild.js: -------------------------------------------------------------------------------- 1 | const utils=require('./utils.js') 2 | const {parentPort,workerData}=require('worker_threads'); 3 | utils.runProcess(workerData.name,workerData.cmd).then((data)=>{ 4 | if(typeof(workerData.j)!=='undefined'){ 5 | parentPort.postMessage({ j:workerData.j,id:workerData.id,index:workerData.index,fileName: workerData.name,file_name:workerData.file_name,cmd:workerData.cmd, status: 'Done' }) 6 | }else{ 7 | parentPort.postMessage({ id:workerData.id,index:workerData.index,fileName: workerData.name,file_name:workerData.file_name,cmd:workerData.cmd, status: 'Done' }) 8 | } 9 | }) 10 | 11 | 12 | --------------------------------------------------------------------------------