├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── stale.yml ├── .gitignore ├── FUNDING.yml ├── LICENSE ├── README.md ├── app.py ├── docs ├── App.html ├── BrowserWindow.html ├── Builder.html ├── Cleaner.html ├── Dispatcher.html ├── Footer.html ├── MainPage.LoadingScreen.html ├── Navigation.html ├── Notice.html ├── Packager.html ├── Pages.MainPage.html ├── Pages.SettingsPage.html ├── Requests.html ├── Services.html ├── Settings.html ├── Starter.html ├── Themes.html ├── Titlebar.html ├── global.html ├── index.html ├── main.js.html ├── scripts │ ├── custom.js │ ├── linenumber.js │ ├── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js │ ├── search.js │ └── utils.min.js ├── scripts_build.js.html ├── scripts_clean.js.html ├── scripts_dispatch.js.html ├── scripts_package.js.html ├── scripts_start.js.html ├── src_components_App.js.html ├── src_components_dialog_Notice.js.html ├── src_components_footer_Footer.js.html ├── src_components_navigation_Navigation.js.html ├── src_components_pages_main_InputField.js.html ├── src_components_pages_main_LoadingScreen.js.html ├── src_components_pages_main_MainPage.js.html ├── src_components_pages_settings_LanguageSettings.js.html ├── src_components_pages_settings_SettingsPage.js.html ├── src_components_pages_settings_util_supportedLanguages.js.html ├── src_components_titlebar_Favicon.js.html ├── src_components_titlebar_Titlebar.js.html ├── src_components_titlebar_TitlebarButtons.js.html ├── src_theme_palettes.js.html ├── src_utils_requests.js.html ├── src_utils_services.js.html ├── src_utils_settings.js.html └── styles │ ├── custom.css │ ├── daybrush.css │ ├── jsdoc.css │ └── prettify.css ├── jsconfig.json ├── jsdoc.json ├── main.js ├── package.json ├── preload.js ├── public ├── favicon.ico ├── index.html ├── manifest.json └── robots.txt ├── renderer.js ├── requirements.txt ├── resources ├── __init__.py ├── ffmpeg │ ├── LICENSE │ ├── README.txt │ ├── ffmpeg.exe │ ├── ffprobe.exe │ └── presets │ │ ├── libvpx-1080p.ffpreset │ │ ├── libvpx-1080p50_60.ffpreset │ │ ├── libvpx-360p.ffpreset │ │ ├── libvpx-720p.ffpreset │ │ └── libvpx-720p50_60.ffpreset ├── mkvtoolnix │ ├── LICENSE │ ├── README.md │ ├── mkvmerge.exe │ └── source.zip └── modules │ ├── filewalker.py │ └── mkvtoolnix.py ├── scripts ├── build.js ├── clean.js ├── dispatch.js ├── package.js └── start.js ├── src ├── components │ ├── App.js │ ├── App.module.scss │ ├── dialog │ │ └── Notice.js │ ├── footer │ │ ├── Footer.js │ │ └── assets │ │ │ └── styles │ │ │ └── Footer.module.scss │ ├── navigation │ │ ├── Navigation.js │ │ └── assets │ │ │ ├── icons │ │ │ ├── FoldersIcon.js │ │ │ ├── SettingsIcon.js │ │ │ └── ThemeIcon.js │ │ │ └── styles │ │ │ └── Navigation.module.scss │ ├── pages │ │ ├── main │ │ │ ├── InputField.js │ │ │ ├── LoadingScreen.js │ │ │ ├── MainPage.js │ │ │ └── assets │ │ │ │ ├── icons │ │ │ │ └── Spinner.js │ │ │ │ └── styles │ │ │ │ ├── InputField.module.scss │ │ │ │ ├── LoadingScreen.module.scss │ │ │ │ └── MainPage.module.scss │ │ └── settings │ │ │ ├── LanguageSettings.js │ │ │ ├── SettingsPage.js │ │ │ ├── assets │ │ │ └── styles │ │ │ │ └── SettingsPage.module.scss │ │ │ └── util │ │ │ └── supportedLanguages.js │ └── titlebar │ │ ├── Favicon.js │ │ ├── Titlebar.js │ │ ├── TitlebarButtons.js │ │ └── scss │ │ ├── Titlebar.module.scss │ │ └── TitlebarButtons.module.scss ├── index.js ├── index.scss ├── logo.svg ├── serviceWorker.js ├── tests │ ├── App.test.js │ └── setupTests.js ├── theme │ ├── overrides.scss │ ├── palettes.js │ └── variables.scss └── utils │ ├── requests.js │ ├── services.js │ └── settings.js ├── utilities ├── dmg │ └── images │ │ ├── background.png │ │ └── icon.icns ├── jsdoc │ ├── LICENSE.md │ ├── README.md │ ├── fixtures │ │ ├── base │ │ │ ├── chains.js │ │ │ └── index.js │ │ ├── documents │ │ │ ├── binder.js │ │ │ ├── collector.js │ │ │ ├── model.js │ │ │ ├── probe.js │ │ │ └── schema.js │ │ ├── fixtures.conf.json │ │ ├── mixins │ │ │ ├── bussable.js │ │ │ └── signalable.js │ │ ├── strings │ │ │ └── format.js │ │ ├── tutorials │ │ │ ├── Brush Teeth.md │ │ │ ├── Drive Car.md │ │ │ └── Fence Test.md │ │ └── utils │ │ │ └── logger.js │ ├── package.json │ ├── publish.js │ ├── static │ │ ├── scripts │ │ │ ├── custom.js │ │ │ ├── linenumber.js │ │ │ ├── prettify │ │ │ │ ├── Apache-License-2.0.txt │ │ │ │ ├── lang-css.js │ │ │ │ └── prettify.js │ │ │ ├── search.js │ │ │ └── utils.min.js │ │ └── styles │ │ │ ├── custom.css │ │ │ ├── daybrush.css │ │ │ ├── jsdoc.css │ │ │ └── prettify.css │ └── tmpl │ │ ├── augments.tmpl │ │ ├── container.tmpl │ │ ├── details.tmpl │ │ ├── example.tmpl │ │ ├── examples.tmpl │ │ ├── exceptions.tmpl │ │ ├── layout.tmpl │ │ ├── mainpage.tmpl │ │ ├── members.tmpl │ │ ├── method.tmpl │ │ ├── params.tmpl │ │ ├── properties.tmpl │ │ ├── returns.tmpl │ │ ├── source.tmpl │ │ ├── tutorial.tmpl │ │ └── type.tmpl ├── loaders │ ├── react │ │ ├── assets │ │ │ ├── logo.svg │ │ │ └── style.css │ │ └── index.html │ └── redux │ │ ├── assets │ │ ├── logo.svg │ │ └── style.css │ │ └── index.html └── msi │ └── images │ ├── background.png │ ├── banner.png │ └── icon.ico └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/react", 5 | [ 6 | "minify", { 7 | "builtIns": false 8 | } 9 | ] 10 | ], 11 | "plugins": [ 12 | "@babel/plugin-proposal-async-generator-functions", 13 | "@babel/plugin-proposal-class-properties", 14 | "@babel/plugin-proposal-object-rest-spread", 15 | "@babel/plugin-transform-arrow-functions", 16 | "@babel/plugin-transform-async-to-generator", 17 | "@babel/plugin-transform-classes", 18 | "@babel/plugin-transform-computed-properties", 19 | "@babel/plugin-transform-destructuring", 20 | "@babel/plugin-transform-for-of", 21 | "@babel/plugin-transform-parameters", 22 | "@babel/plugin-transform-shorthand-properties", 23 | "@babel/plugin-transform-spread", 24 | "@babel/plugin-transform-sticky-regex", 25 | "@babel/plugin-transform-template-literals" 26 | ] 27 | } -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | node_modules/ 4 | stories/ 5 | .snapshots/ 6 | *.min.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es6: true, 5 | mocha: true 6 | }, 7 | extends: ['plugin:react/recommended', 'airbnb'], 8 | globals: { 9 | Atomics: 'readonly', 10 | SharedArrayBuffer: 'readonly' 11 | }, 12 | parser: 'babel-eslint', 13 | parserOptions: { 14 | ecmaFeatures: { 15 | jsx: true 16 | }, 17 | ecmaVersion: 12, 18 | sourceType: 'module' 19 | }, 20 | plugins: ['react'], 21 | rules: { 22 | 'array-bracket-spacing': [0], 23 | 'arrow-body-style': [0], 24 | 'arrow-parens': ['warn'], 25 | 'brace-style': [0], 26 | 'comma-dangle': ['warn', 'never'], 27 | 'consistent-return': [0], 28 | 'eol-last': [0], 29 | 'func-names': ['warn', 'always', { 30 | generators: 'as-needed' 31 | }], 32 | 'global-require': ['warn'], 33 | 'implicit-arrow-linebreak': [0], 34 | 'import/no-dynamic-require': ['warn'], 35 | 'import/no-extraneous-dependencies': [0], 36 | 'import/order': ['warn'], 37 | 'import/prefer-default-export': [0], 38 | 'indent': ['warn', 2, { 39 | SwitchCase: 1 40 | }], 41 | 'jsx-a11y/anchor-is-valid': ['warn'], 42 | 'jsx-a11y/click-events-have-key-events': [0], 43 | 'jsx-a11y/interactive-supports-focus': [0], 44 | 'jsx-a11y/label-has-associated-control': [0], 45 | 'jsx-a11y/no-noninteractive-element-interactions': [0], 46 | 'keyword-spacing': ['warn'], 47 | 'linebreak-style': [0], 48 | 'max-len': ['warn'], 49 | 'no-console': ['warn', { 50 | allow: ['warn', 'error'] 51 | }], 52 | 'no-nested-ternary': [0], 53 | 'no-param-reassign': [0], 54 | 'no-mixed-spaces-and-tabs': ['warn'], 55 | 'no-multi-spaces': ['warn'], 56 | 'no-multiple-empty-lines': [0], 57 | 'no-restricted-syntax': [0], 58 | 'no-tabs': ['warn'], 59 | 'no-trailing-spaces': ['warn'], 60 | 'no-unneeded-ternary': ['warn'], 61 | 'no-underscore-dangle': ['warn'], 62 | 'no-unused-expressions': [0], 63 | 'no-unused-vars': ['warn'], 64 | 'no-use-before-define': ['error', { 65 | 'functions': false 66 | }], 67 | 'object-curly-newline': [0], 68 | 'object-curly-spacing': ['warn'], 69 | 'object-shorthand': ['warn', 'always'], 70 | 'one-var': ['warn', { 71 | 'initialized': 'never' 72 | }], 73 | 'one-var-declaration-per-line': ['warn', 'initializations'], 74 | 'operator-linebreak': ['warn'], 75 | 'padded-blocks': [0], 76 | 'prefer-arrow-callback': ['warn'], 77 | 'prefer-const': ['warn'], 78 | 'prefer-destructuring': [ 79 | 'warn', 80 | { 81 | array: true, 82 | object: true 83 | }, 84 | { 85 | enforceForRenamedProperties: false 86 | } 87 | ], 88 | 'prefer-template': ['warn'], 89 | 'quotes': ['warn'], 90 | 'quote-props': ['warn', 'consistent'], 91 | 'rest-spread-spacing': ['warn', 'never'], 92 | 'semi': ['warn'], 93 | 'spaced-comment': ['warn'], 94 | 'space-before-function-paren': ['warn'], 95 | 'react/destructuring-assignment': [0], 96 | 'react/forbid-prop-types': [0], 97 | 'react/jsx-closing-bracket-location': ['warn'], 98 | 'react/jsx-curly-newline': ['warn'], 99 | 'react/jsx-curly-spacing': ['warn', 'always'], 100 | 'react/jsx-filename-extension': [0], 101 | 'react/jsx-fragments': [0], 102 | 'react/jsx-indent': ['warn', 2], 103 | 'react/jsx-equals-spacing': ['warn'], 104 | 'react/jsx-one-expression-per-line': ['warn'], 105 | 'react/jsx-props-no-spreading': [0], 106 | 'react/jsx-tag-spacing': ['warn'], 107 | 'react/jsx-wrap-multilines': ['warn'], 108 | 'react/no-access-state-in-setstate': [0], 109 | 'react/no-array-index-key': [0], 110 | 'react/no-unused-state': ['warn'], 111 | 'react/prop-types': ['warn'], 112 | 'react/prefer-stateless-function': ['warn'], 113 | 'react/require-default-props': ['warn'], 114 | 'react/sort-comp': [0], 115 | 'react/state-in-constructor': ['warn', 'never'] 116 | }, 117 | settings: { 118 | 'import/resolver': { 119 | node: { 120 | paths: ['./', 'src'] 121 | } 122 | } 123 | } 124 | }; -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.exe filter=lfs diff=lfs merge=lfs -text 2 | resources/ffmpeg/ffprobe.exe filter=lfs diff=lfs merge=lfs -text 3 | resources/ffmpeg/ffmerge.exe filter=lfs diff=lfs merge=lfs -text 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: "bug \U0001F99F" 6 | assignees: iPzard 7 | 8 | --- 9 | 10 | **🦟 Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Steps to Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement ✨ 6 | assignees: iPzard 7 | 8 | --- 9 | 10 | **✨ Describe the feature** 11 | A clear and concise description of the feature you want. 12 | 13 | **Additional context** 14 | Add any other context or screenshots about the feature request here. 15 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 30 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - preserved 💾 9 | - security 10 | # Label to use when marking an issue as stale 11 | staleLabel: wontfix 12 | # Comment to post when marking an issue as stale. Set to `false` to disable 13 | markComment: > 14 | This issue has been automatically marked as stale because it has not had 15 | recent activity. It will be closed if no further activity occurs. Thank you 16 | for your contributions. 17 | # Comment to post when closing a stale issue. Set to `false` to disable 18 | closeComment: This issue has been closed due to inactivity. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | #cache 4 | app.pyc 5 | app.spec 6 | app.debug.spec 7 | __pycache__ 8 | 9 | # debug 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # dependencies 15 | /node_modules 16 | /.pnp 17 | .pnp.js 18 | 19 | # testing 20 | /coverage 21 | 22 | # production 23 | /build 24 | /dist 25 | app/ 26 | 27 | # resources 28 | resources/app/ 29 | resources/app.debug/ 30 | *.pyo 31 | 32 | # misc 33 | .DS_Store 34 | .env.local 35 | .env.development.local 36 | .env.test.local 37 | .env.production.local 38 | -------------------------------------------------------------------------------- /FUNDING.yml: -------------------------------------------------------------------------------- 1 | # repo: your_github_handle/.github 2 | # filename: FUNDING.YML 3 | 4 | github: iPzard -------------------------------------------------------------------------------- /docs/App.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | App - Documentation 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 32 | 33 |
34 | 35 |

App

36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | 45 |
46 | 47 |

48 | App 49 |

50 | 51 | 52 |
53 | 54 |
55 |
56 | 57 | 58 | 59 |
60 | 61 | 62 |
Source:
63 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 | 99 | 100 | 101 | 102 | 103 |
    104 |
  • Controls global state and page navigation
  • 105 |
106 | 107 | 108 | 109 | 110 |
111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 |
130 | 131 |
132 | 133 | 134 | 135 | 136 | 137 | 147 | 148 |
149 | 150 |
151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /docs/scripts/custom.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iPzard/mkvtoolnix-batch-tool/33821381e38cf89a0702cd8276f86ccf0dd3189f/docs/scripts/custom.js -------------------------------------------------------------------------------- /docs/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/scripts/search.js: -------------------------------------------------------------------------------- 1 | 2 | (function () { 3 | var nav = document.querySelector("nav"); 4 | var searchBar = nav.querySelector(".search"); 5 | var input = searchBar.querySelector("input"); 6 | // var submit = searchBar.querySelector("button"); 7 | var groups = Array.prototype.slice.call(document.querySelectorAll("nav>ul .parent")).map(function (group) { 8 | var items = Array.prototype.slice.call(group.querySelectorAll("a")); 9 | var strings = items.map(function (a) { 10 | return a.innerText.toLowerCase(); 11 | }); 12 | 13 | return {el: group, items: items, strings, strings}; 14 | }); 15 | input.addEventListener("keyup", function (e) { 16 | var value = input.value.toLowerCase(); 17 | 18 | if (value) { 19 | utils.addClass(nav, "searching"); 20 | } else { 21 | utils.removeClass(nav, "searching"); 22 | return; 23 | } 24 | groups.forEach(function (group) { 25 | var isSearch = false; 26 | var items = group.items; 27 | 28 | group.strings.forEach(function (v, i) { 29 | var item = items[i]; 30 | if (utils.hasClass(item.parentNode, "parent")) { 31 | item = item.parentNode; 32 | } 33 | if (v.indexOf(value) > -1) { 34 | utils.addClass(item, "targeting"); 35 | isSearch = true; 36 | } else { 37 | utils.removeClass(item, "targeting"); 38 | } 39 | }); 40 | if (isSearch) { 41 | utils.addClass(group.el, "module-targeting"); 42 | } else { 43 | utils.removeClass(group.el, "module-targeting"); 44 | } 45 | }); 46 | }); 47 | })(); -------------------------------------------------------------------------------- /docs/scripts/utils.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 Daybrush 3 | @name: @daybrush/utils 4 | license: MIT 5 | author: Daybrush 6 | repository: https://github.com/daybrush/utils 7 | @version 0.4.0 8 | */ 9 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.utils=t()}(this,function(){"use strict";var u="rgb",c="rgba",f="hsl",l="hsla",e=[u,c,f,l],t="function",n="object",r="string",i="undefined",a=typeof window!==i,o=["webkit","ms","moz","o"],s=function(e){if(typeof document===i)return"";var t=(document.body||document.documentElement).style,n=o.length;if(typeof t[e]!==i)return e;for(var r=0;r 2 | 3 | 4 | 5 | scripts/clean.js - Documentation 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 32 | 33 |
34 | 35 |

scripts/clean.js

36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 |
45 |
const {
 46 |   existsSync,
 47 |   readdirSync,
 48 |   rmdirSync,
 49 |   statSync,
 50 |   unlinkSync
 51 | } = require('fs');
 52 | 
 53 | /**
 54 |  * @namespace Cleaner
 55 |  * @description - Cleans project by removing the following files and folders:
 56 |  * docs, node_modules, yarn.lock, and package-lock.json.
 57 |  */
 58 | class Cleaner {
 59 | 
 60 |   removePath = (pathToRemove) => {
 61 |     if (existsSync(pathToRemove)) {
 62 |       // eslint-disable-next-line no-console
 63 |       console.log(`Removing: ${pathToRemove}`);
 64 |       if (statSync(pathToRemove).isFile()) unlinkSync(pathToRemove);
 65 | 
 66 |       else {
 67 |         const files = readdirSync(pathToRemove);
 68 | 
 69 |         files.forEach((file) => {
 70 |           const filePath = `${pathToRemove}/${file}`;
 71 | 
 72 |           if (statSync(filePath).isDirectory()) this.removePath(filePath);
 73 |           else unlinkSync(filePath);
 74 |         });
 75 |         rmdirSync(pathToRemove);
 76 |       }
 77 |     }
 78 |   };
 79 | }
 80 | 
 81 | module.exports.Cleaner = Cleaner;
 82 | 
83 |
84 |
85 | 86 | 87 | 88 | 89 | 90 | 100 | 101 |
102 | 103 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /docs/styles/custom.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iPzard/mkvtoolnix-batch-tool/33821381e38cf89a0702cd8276f86ccf0dd3189f/docs/styles/custom.css -------------------------------------------------------------------------------- /docs/styles/daybrush.css: -------------------------------------------------------------------------------- 1 | .readme table { 2 | border-spacing: 0; 3 | border-collapse: collapse; 4 | } 5 | .readme * { 6 | box-sizing: border-box; 7 | } 8 | .readme table th, .readme table td { 9 | padding: 6px 13px; 10 | border: 1px solid #ddd; 11 | } 12 | 13 | nav>ul>li:after { 14 | content: ""; 15 | position: absolute; 16 | right: 10px; 17 | top: 0; 18 | bottom: 0; 19 | width: 0; 20 | height: 0; 21 | margin: auto 0px; 22 | border-top: 7px solid #ccc; 23 | border-left: 6px solid transparent; 24 | border-right: 6px solid transparent; 25 | } 26 | nav li h4, nav li ul { 27 | display: none; 28 | } 29 | 30 | .name.typescript { 31 | background: #374E79; 32 | font-size: 14px; 33 | } 34 | .name.typescript .signature { 35 | color: #21de60; 36 | } 37 | .ts-params.typescript table .last { 38 | display: none; 39 | } 40 | table.params th, table.params tr td , table.params tr td.type{ 41 | word-break: break-word; 42 | white-space: normal; 43 | } 44 | 45 | nav .search { 46 | position: relative; 47 | margin: 0px 10px; 48 | border: 3px solid #333; 49 | height: 43px; 50 | } 51 | nav .search .input-area { 52 | position: absolute; 53 | left: 0; 54 | top: 0; 55 | right: 35px; 56 | height: 35px; 57 | } 58 | nav .search input { 59 | position: relative; 60 | width: 100%; 61 | height: 100%; 62 | border: 0; 63 | padding: 0; 64 | text-indent: 10px; 65 | font-weight: bold; 66 | font-size: 14px; 67 | outline: none; 68 | } 69 | nav .search button { 70 | position: absolute; 71 | top: 0; 72 | right: 0px; 73 | width: 35px; 74 | height: 35px; 75 | border: 0; 76 | padding: 0; 77 | outline: none; 78 | cursor: pointer; 79 | } 80 | nav .search button:before { 81 | position: absolute; 82 | content: ""; 83 | width: 18px; 84 | height: 18px; 85 | top: 7px; 86 | left: 7px; 87 | border: 3px solid #333; 88 | border-radius: 50%; 89 | box-sizing: border-box; 90 | } 91 | nav .search button:after { 92 | position: absolute; 93 | content: ""; 94 | width: 3px; 95 | height: 11px; 96 | top: 21px; 97 | left: 18px; 98 | background: #333; 99 | transform-origin: 50% 0%; 100 | -ms-transform-origin: 50% 0%; 101 | -webkit-transform-origin: 50% 0%; 102 | transform: rotate(-45deg); 103 | -ms-transform: rotate(-45deg); 104 | -webkit-transform: rotate(-45deg); 105 | } 106 | 107 | nav.searching li:after { 108 | display: none!important; 109 | } 110 | nav.searching li h4, nav.searching li ul { 111 | display: block!important; 112 | } 113 | 114 | nav.searching .parent { 115 | display: none; 116 | } 117 | nav.searching .parent ul li a { 118 | display: none; 119 | } 120 | 121 | nav.searching .parent.module-targeting { 122 | display: block; 123 | } 124 | nav.searching .parent.module-targeting ul li a { 125 | display: none; 126 | } 127 | nav.searching .parent.module-targeting ul li a.targeting { 128 | display: block; 129 | } 130 | nav.searching .parent.targeting ul li a { 131 | display: block; 132 | } 133 | 134 | nav>h2.custom>a { 135 | margin:12px 10px; 136 | } -------------------------------------------------------------------------------- /docs/styles/prettify.css: -------------------------------------------------------------------------------- 1 | .pln { 2 | color: #ddd; 3 | } 4 | 5 | /* string content */ 6 | .str { 7 | color: #61ce3c; 8 | } 9 | 10 | /* a keyword */ 11 | .kwd { 12 | color: #fbde2d; 13 | } 14 | 15 | /* a comment */ 16 | .com { 17 | color: #aeaeae; 18 | } 19 | 20 | /* a type name */ 21 | .typ { 22 | color: #8da6ce; 23 | } 24 | 25 | /* a literal value */ 26 | .lit { 27 | color: #fbde2d; 28 | } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #ddd; 33 | } 34 | 35 | /* lisp open bracket */ 36 | .opn { 37 | color: #000000; 38 | } 39 | 40 | /* lisp close bracket */ 41 | .clo { 42 | color: #000000; 43 | } 44 | 45 | /* a markup tag name */ 46 | .tag { 47 | color: #8da6ce; 48 | } 49 | 50 | /* a markup attribute name */ 51 | .atn { 52 | color: #fbde2d; 53 | } 54 | 55 | /* a markup attribute value */ 56 | .atv { 57 | color: #ddd; 58 | } 59 | 60 | /* a declaration */ 61 | .dec { 62 | color: #EF5050; 63 | } 64 | 65 | /* a variable name */ 66 | .var { 67 | color: #c82829; 68 | } 69 | 70 | /* a function name */ 71 | .fun { 72 | color: #4271ae; 73 | } 74 | 75 | /* Specify class=linenums on a pre to get line numbering */ 76 | ol.linenums { 77 | margin-top: 0; 78 | margin-bottom: 0; 79 | } 80 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "src" 4 | }, 5 | "include": ["src"] 6 | } -------------------------------------------------------------------------------- /jsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": { 3 | "include": ["main.js", "scripts", "src"], 4 | "includePattern": ".js$", 5 | "excludePattern": "(node_modules/|docs)" 6 | }, 7 | "plugins": ["plugins/markdown"], 8 | "templates": { 9 | "cleverLinks": true, 10 | "monospaceLinks": true 11 | }, 12 | "opts": { 13 | "recurse": true, 14 | "destination": "docs", 15 | "template": "utilities/jsdoc", 16 | "readme": "readme.md" 17 | } 18 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Daniel Wade", 3 | "browserslist": { 4 | "production": [ 5 | ">0.2%", 6 | "not dead", 7 | "not op_mini all" 8 | ], 9 | "development": [ 10 | "last 1 chrome version", 11 | "last 1 firefox version", 12 | "last 1 safari version" 13 | ] 14 | }, 15 | "build": { 16 | "extraResources": [ 17 | "./resources/app", 18 | "./resources/app.debug", 19 | "./resources/mkvtoolnix", 20 | "./resources/modules", 21 | "./resources/__init__.py" 22 | ] 23 | }, 24 | "dependencies": { 25 | "axios": "0.21.1", 26 | "electron-is-dev": "1.2.0", 27 | "get-port": "5.1.1", 28 | "socket.io-client": "2.3.1" 29 | }, 30 | "description": "MKVToolNix batch processing tool", 31 | "devDependencies": { 32 | "@fluentui/react": "7.160.1", 33 | "@testing-library/jest-dom": "4.2.4", 34 | "@testing-library/react": "9.3.2", 35 | "@testing-library/user-event": "7.1.2", 36 | "babel-eslint": "10.1.0", 37 | "cross-env": "7.0.3", 38 | "electron": "10.1.3", 39 | "electron-installer-dmg": "3.0.0", 40 | "electron-packager": "15.0.0", 41 | "electron-wix-msi": "5.0.0", 42 | "eslint-config-airbnb": "18.2.1", 43 | "eslint-plugin-import": "2.23.4", 44 | "eslint-plugin-jsx-a11y": "6.4.1", 45 | "eslint-plugin-react": "7.24.0", 46 | "eslint-plugin-standard": "5.0.0", 47 | "exe-icon-extractor": "1.0.8", 48 | "jsdoc": "3.6.5", 49 | "prop-types": "15.7.2", 50 | "react": "16.13.1", 51 | "react-dom": "16.13.1", 52 | "react-scripts": "3.4.1", 53 | "sass": "1.26.5" 54 | }, 55 | "eslintConfig": { 56 | "extends": "react-app" 57 | }, 58 | "homepage": "./", 59 | "license": "MIT", 60 | "main": "main.js", 61 | "name": "mkvtoolnix-batch-tool", 62 | "private": true, 63 | "productName": "MKVToolNix Batch Tool", 64 | "scripts": { 65 | "build": "node ./scripts/dispatch build all", 66 | "build:all": "node ./scripts/dispatch build all", 67 | "build:react": "node ./scripts/dispatch build react", 68 | "build:python": "node ./scripts/dispatch build python", 69 | "build:docs": "jsdoc -c jsdoc.json", 70 | "build:package:mac": "node ./scripts/dispatch package mac", 71 | "build:package:windows": "node ./scripts/dispatch package windows", 72 | "clean": "node ./scripts/dispatch clean", 73 | "eject": "react-scripts eject", 74 | "start": "node ./scripts/dispatch start", 75 | "start:electron": "electron .", 76 | "start:react": "react-scripts start", 77 | "test": "react-scripts test" 78 | }, 79 | "version": "2.5.4" 80 | } 81 | -------------------------------------------------------------------------------- /preload.js: -------------------------------------------------------------------------------- 1 | // All of the Node.js APIs are available in the preload process. 2 | // It has the same sandbox as a Chrome extension. 3 | window.addEventListener('DOMContentLoaded', () => { 4 | 5 | process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true; 6 | 7 | const replaceText = (selector, text) => { 8 | const element = document.getElementById(selector); 9 | if (element) element.innerText = text; 10 | } 11 | 12 | for (const type of ['chrome', 'node', 'electron']) { 13 | replaceText(`${type}-version`, process.versions[type]); 14 | } 15 | }); -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iPzard/mkvtoolnix-batch-tool/33821381e38cf89a0702cd8276f86ccf0dd3189f/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 17 | 18 | 27 | MKVToolNix Batch Tool 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "MKVToolNix Batch tool", 3 | "name": "MKVToolNix Batch tool", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#bf7e45", 14 | "background_color": "#252525" 15 | } 16 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /renderer.js: -------------------------------------------------------------------------------- 1 | // This file is required by the index.html file and will 2 | // be executed in the renderer process for that window. 3 | // No Node.js APIs are available in this process because 4 | // `nodeIntegration` is turned off. Use `preload.js` to 5 | // selectively enable features needed in the rendering 6 | // process. 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | chardet==4.0.0 2 | ffmpeg-python==0.2.0 3 | Flask==2.0.1 4 | Flask-Cors==3.0.10 5 | Flask-SocketIO==3.1.2 6 | python-socketio==2.1.2 7 | jsonify==0.5 8 | langdetect==1.16.0 9 | pyinstaller==4.3 10 | python-engineio==3.1.0 11 | -------------------------------------------------------------------------------- /resources/__init__.py: -------------------------------------------------------------------------------- 1 | from .modules import filewalker 2 | from .modules import mkvtoolnix -------------------------------------------------------------------------------- /resources/ffmpeg/README.txt: -------------------------------------------------------------------------------- 1 | FFmpeg 64-bit static Windows build from www.gyan.dev 2 | 3 | Version: 2021-05-16-git-f53414a038-full_build-www.gyan.dev 4 | 5 | License: GPL v3 6 | 7 | Source Code: https://github.com/FFmpeg/FFmpeg/commit/f53414a038 8 | 9 | git-full build configuration: 10 | 11 | --enable-gpl 12 | --enable-version3 13 | --enable-static 14 | --disable-w32threads 15 | --disable-autodetect 16 | --enable-fontconfig 17 | --enable-iconv 18 | --enable-gnutls 19 | --enable-libxml2 20 | --enable-gmp 21 | --enable-lzma 22 | --enable-libsnappy 23 | --enable-zlib 24 | --enable-librist 25 | --enable-libsrt 26 | --enable-libssh 27 | --enable-libzmq 28 | --enable-avisynth 29 | --enable-libbluray 30 | --enable-libcaca 31 | --enable-sdl2 32 | --enable-libdav1d 33 | --enable-libzvbi 34 | --enable-librav1e 35 | --enable-libsvtav1 36 | --enable-libwebp 37 | --enable-libx264 38 | --enable-libx265 39 | --enable-libxvid 40 | --enable-libaom 41 | --enable-libopenjpeg 42 | --enable-libvpx 43 | --enable-libass 44 | --enable-frei0r 45 | --enable-libfreetype 46 | --enable-libfribidi 47 | --enable-libvidstab 48 | --enable-libvmaf 49 | --enable-libzimg 50 | --enable-amf 51 | --enable-cuda-llvm 52 | --enable-cuvid 53 | --enable-ffnvcodec 54 | --enable-nvdec 55 | --enable-nvenc 56 | --enable-d3d11va 57 | --enable-dxva2 58 | --enable-libmfx 59 | --enable-libglslang 60 | --enable-vulkan 61 | --enable-opencl 62 | --enable-libcdio 63 | --enable-libgme 64 | --enable-libmodplug 65 | --enable-libopenmpt 66 | --enable-libopencore-amrwb 67 | --enable-libmp3lame 68 | --enable-libshine 69 | --enable-libtheora 70 | --enable-libtwolame 71 | --enable-libvo-amrwbenc 72 | --enable-libilbc 73 | --enable-libgsm 74 | --enable-libopencore-amrnb 75 | --enable-libopus 76 | --enable-libspeex 77 | --enable-libvorbis 78 | --enable-ladspa 79 | --enable-libbs2b 80 | --enable-libflite 81 | --enable-libmysofa 82 | --enable-librubberband 83 | --enable-libsoxr 84 | --enable-chromaprint 85 | 86 | -------------------------------------------------------------------------------- /resources/ffmpeg/ffmpeg.exe: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:3e5420a8efef8cf92c65961e646893d6b6c370f11c1d172b0b3535ee1ceb53fb 3 | size 112782336 4 | -------------------------------------------------------------------------------- /resources/ffmpeg/ffprobe.exe: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:8cd5a20b7e150380e29417e9d39ad221a6804d68245db38d8ebd7013edbfda83 3 | size 112684544 4 | -------------------------------------------------------------------------------- /resources/ffmpeg/presets/libvpx-1080p.ffpreset: -------------------------------------------------------------------------------- 1 | vcodec=libvpx 2 | 3 | g=120 4 | lag-in-frames=16 5 | deadline=good 6 | cpu-used=0 7 | vprofile=1 8 | qmax=51 9 | qmin=11 10 | slices=4 11 | b=2M 12 | 13 | #ignored unless using -pass 2 14 | maxrate=24M 15 | minrate=100k 16 | auto-alt-ref=1 17 | arnr-maxframes=7 18 | arnr-strength=5 19 | arnr-type=centered 20 | -------------------------------------------------------------------------------- /resources/ffmpeg/presets/libvpx-1080p50_60.ffpreset: -------------------------------------------------------------------------------- 1 | vcodec=libvpx 2 | 3 | g=120 4 | lag-in-frames=25 5 | deadline=good 6 | cpu-used=0 7 | vprofile=1 8 | qmax=51 9 | qmin=11 10 | slices=4 11 | b=2M 12 | 13 | #ignored unless using -pass 2 14 | maxrate=24M 15 | minrate=100k 16 | auto-alt-ref=1 17 | arnr-maxframes=7 18 | arnr-strength=5 19 | arnr-type=centered 20 | -------------------------------------------------------------------------------- /resources/ffmpeg/presets/libvpx-360p.ffpreset: -------------------------------------------------------------------------------- 1 | vcodec=libvpx 2 | 3 | g=120 4 | lag-in-frames=16 5 | deadline=good 6 | cpu-used=0 7 | vprofile=0 8 | qmax=63 9 | qmin=0 10 | b=768k 11 | 12 | #ignored unless using -pass 2 13 | maxrate=1.5M 14 | minrate=40k 15 | auto-alt-ref=1 16 | arnr-maxframes=7 17 | arnr-strength=5 18 | arnr-type=centered 19 | -------------------------------------------------------------------------------- /resources/ffmpeg/presets/libvpx-720p.ffpreset: -------------------------------------------------------------------------------- 1 | vcodec=libvpx 2 | 3 | g=120 4 | lag-in-frames=16 5 | deadline=good 6 | cpu-used=0 7 | vprofile=0 8 | qmax=51 9 | qmin=11 10 | slices=4 11 | b=2M 12 | 13 | #ignored unless using -pass 2 14 | maxrate=24M 15 | minrate=100k 16 | auto-alt-ref=1 17 | arnr-maxframes=7 18 | arnr-strength=5 19 | arnr-type=centered 20 | -------------------------------------------------------------------------------- /resources/ffmpeg/presets/libvpx-720p50_60.ffpreset: -------------------------------------------------------------------------------- 1 | vcodec=libvpx 2 | 3 | g=120 4 | lag-in-frames=25 5 | deadline=good 6 | cpu-used=0 7 | vprofile=0 8 | qmax=51 9 | qmin=11 10 | slices=4 11 | b=2M 12 | 13 | #ignored unless using -pass 2 14 | maxrate=24M 15 | minrate=100k 16 | auto-alt-ref=1 17 | arnr-maxframes=7 18 | arnr-strength=5 19 | arnr-type=centered 20 | -------------------------------------------------------------------------------- /resources/mkvtoolnix/mkvmerge.exe: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:850373a68c1189a9345a2312b02acfdd574265f1bcc43d31ac855f6e35255c0f 3 | size 17450504 4 | -------------------------------------------------------------------------------- /resources/mkvtoolnix/source.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iPzard/mkvtoolnix-batch-tool/33821381e38cf89a0702cd8276f86ccf0dd3189f/resources/mkvtoolnix/source.zip -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | const { spawnSync } = require('child_process'); 2 | 3 | const spawnOptions = { detached: false, shell: true, stdio: 'inherit' }; 4 | 5 | /** 6 | * @namespace Builder 7 | * @description - Builds React & Python builds of project so Electron can be used. 8 | */ 9 | 10 | class Builder { 11 | 12 | /** 13 | * @description - Creates React and Python production builds. 14 | * @memberof Builder 15 | */ 16 | buildAll = () => { 17 | const { buildPython, buildReact } = this; 18 | 19 | buildPython(); 20 | buildReact(); 21 | } 22 | 23 | /** 24 | * @description - Creates production build of Python back end. 25 | * @memberof Builder 26 | */ 27 | buildPython = () => { 28 | // eslint-disable-next-line no-console 29 | console.log('Creating Python distribution files...'); 30 | 31 | const app = 'app.py'; 32 | const icon = './public/favicon.ico'; 33 | 34 | // PyInstaller default options 35 | const pyInstallerOptions = [ 36 | '--noconfirm', // Don't confirm overwrite 37 | '--distpath=./resources', // Output path 38 | `--icon=${icon}`, // Icon to use for app 39 | '--collect-datas=langdetect' // modules 40 | ]; 41 | 42 | // Options for app file with hidden console 43 | const productionOptions = [ 44 | ...pyInstallerOptions, 45 | '--noconsole' // Hides console output 46 | ]; 47 | 48 | // Options for app file with console shown 49 | const debugOptions = [ 50 | ...pyInstallerOptions, 51 | '--name=app.debug' // Custom name for debug app 52 | ]; 53 | 54 | // Create production and debug versions of app 55 | spawnSync('pyinstaller', [...productionOptions, app], spawnOptions); 56 | spawnSync('pyinstaller', [...debugOptions, app], spawnOptions); 57 | } 58 | 59 | /** 60 | * @description - Creates production build of React front end. 61 | * @memberof Builder 62 | */ 63 | buildReact = () => { 64 | // eslint-disable-next-line no-console 65 | console.log('Creating React distribution files...'); 66 | 67 | // Set the GENERATE_SOURCEMAP environment variable to false 68 | process.env.GENERATE_SOURCEMAP = 'false'; 69 | 70 | spawnSync('react-scripts build', spawnOptions); 71 | } 72 | } 73 | 74 | module.exports.Builder = Builder; 75 | -------------------------------------------------------------------------------- /scripts/clean.js: -------------------------------------------------------------------------------- 1 | const { 2 | existsSync, 3 | readdirSync, 4 | rmdirSync, 5 | statSync, 6 | unlinkSync 7 | } = require('fs'); 8 | 9 | /** 10 | * @namespace Cleaner 11 | * @description - Cleans project by removing the following files and folders: 12 | * docs, node_modules, yarn.lock, and package-lock.json. 13 | */ 14 | class Cleaner { 15 | 16 | removePath = (pathToRemove) => { 17 | if (existsSync(pathToRemove)) { 18 | // eslint-disable-next-line no-console 19 | console.log(`Removing: ${pathToRemove}`); 20 | if (statSync(pathToRemove).isFile()) unlinkSync(pathToRemove); 21 | 22 | else { 23 | const files = readdirSync(pathToRemove); 24 | 25 | files.forEach((file) => { 26 | const filePath = `${pathToRemove}/${file}`; 27 | 28 | if (statSync(filePath).isDirectory()) this.removePath(filePath); 29 | else unlinkSync(filePath); 30 | }); 31 | rmdirSync(pathToRemove); 32 | } 33 | } 34 | }; 35 | } 36 | 37 | module.exports.Cleaner = Cleaner; 38 | -------------------------------------------------------------------------------- /scripts/dispatch.js: -------------------------------------------------------------------------------- 1 | const [ , , script, command ] = process.argv; 2 | const { Builder } = require('./build'); 3 | const { Cleaner } = require('./clean'); 4 | const { Packager } = require('./package'); 5 | const { Starter } = require('./start'); 6 | 7 | 8 | 9 | /** 10 | * @namespace Dispatcher 11 | * @description - Dispatches script commands to various scripts. 12 | * @argument script - Script manager to use (e.g., build or package). 13 | * @argument command - Command argument describing exact script to run. 14 | */ 15 | 16 | switch (script) { 17 | case 'build': 18 | return buildApp(); 19 | 20 | case 'clean': 21 | return cleanProject(); 22 | 23 | case 'package': 24 | return packageApp(); 25 | 26 | case 'start': 27 | return startDeveloperMode(); 28 | 29 | // no default 30 | } 31 | 32 | /** 33 | * @description - Builds various production builds (e.g., Python, React). 34 | * @memberof Dispatcher 35 | */ 36 | function buildApp() { 37 | const builder = new Builder(); 38 | 39 | switch (command) { 40 | case 'react': 41 | return builder.buildReact(); 42 | 43 | case 'python': 44 | return builder.buildPython(); 45 | 46 | case 'all': 47 | return builder.buildAll(); 48 | 49 | // no default 50 | } 51 | } 52 | 53 | /** 54 | * @description - Cleans project by removing various files and folders. 55 | * @memberof Dispatcher 56 | */ 57 | function cleanProject() { 58 | const cleaner = new Cleaner(); 59 | const getPath = (...path) => path.join(__dirname, '..', ...path); 60 | 61 | // Files to remove during cleaning 62 | [ 63 | // Cache 64 | getPath('app.pyc'), 65 | getPath('app.spec'), 66 | getPath('app.debug.spec'), 67 | getPath('__pycache__'), 68 | 69 | // Debug 70 | getPath('npm-debug.log'), 71 | getPath('yarn-debug.log'), 72 | getPath('yarn-error.log'), 73 | 74 | // Dependencies 75 | getPath('.pnp'), 76 | getPath('.pnp.js'), 77 | getPath('node_modules'), 78 | getPath('package-lock.json'), 79 | getPath('yarn.lock'), 80 | 81 | // Testing 82 | getPath('coverage'), 83 | 84 | // Production 85 | getPath('build'), 86 | getPath('dist'), 87 | getPath('docs'), 88 | 89 | // Misc 90 | getPath('.DS_Store') 91 | ] 92 | // Iterate and remove process 93 | .forEach(cleaner.removePath); 94 | // eslint-disable-next-line no-console 95 | console.log('Project is clean.'); 96 | } 97 | 98 | /** 99 | * @description - Builds various installers (e.g., DMG, MSI). 100 | * @memberof Dispatcher 101 | */ 102 | function packageApp() { 103 | const packager = new Packager(); 104 | 105 | switch (command) { 106 | case 'windows': 107 | return packager.packageWindows(); 108 | 109 | case 'mac': 110 | return packager.packageMacOS(); 111 | 112 | // no default 113 | } 114 | } 115 | 116 | /** 117 | * @description - Starts developer mode of app. 118 | * Including; React, Electron, and Python/Flask. 119 | * @memberof Dispatcher 120 | */ 121 | function startDeveloperMode() { 122 | const start = new Starter(); 123 | start.developerMode(); 124 | } 125 | -------------------------------------------------------------------------------- /scripts/package.js: -------------------------------------------------------------------------------- 1 | const { spawnSync } = require('child_process'); 2 | const { Builder } = require('./build'); 3 | 4 | const builder = new Builder(); 5 | const spawnOptions = { detached: false, shell: true, stdio: 'inherit' }; 6 | 7 | // Define input and output directories 8 | const path = (directory) => { 9 | return require('path').resolve(__dirname, directory); 10 | }; 11 | 12 | /** 13 | * @namespace Packager 14 | * @description - Packages app for various operating systems. 15 | */ 16 | class Packager { 17 | 18 | /** 19 | * @description - Creates DMG installer for macOS. 20 | * @memberof Packager 21 | */ 22 | packageMacOS = () => { 23 | 24 | // Build Python & React distribution files 25 | builder.buildAll(); 26 | 27 | const options = { 28 | build: [ 29 | 'app', 30 | '--asar', 31 | '--extra-resource=./resources/app', 32 | '--extra-resource=./resources/app.debug', 33 | '--icon ./public/favicon.ico', 34 | '--darwin', 35 | '--out', 36 | './dist/mac', 37 | '--overwrite' 38 | ].join(' '), 39 | 40 | package: [ 41 | path('../dist/mac/app-darwin-x64/app.app'), 42 | 'Example', 43 | `--out=${path('../dist/mac/setup')}`, 44 | `--icon=${path('../utilities/dmg/images/icon.icns')}`, 45 | // `--background=${path('../utilities/dmg/images/background.png')}`, 46 | '--title="Example App"', 47 | '--overwrite' 48 | ].join(' '), 49 | 50 | spawn: spawnOptions 51 | }; 52 | 53 | spawnSync(`electron-packager . ${options.build}`, options.spawn); 54 | spawnSync(`electron-installer-dmg ${options.package}`, options.spawn); 55 | }; 56 | 57 | 58 | /** 59 | * @description - Creates MSI installer for Windows. 60 | * @memberof Packager 61 | */ 62 | packageWindows = () => { 63 | // eslint-disable-next-line no-console 64 | console.log('Building windows package...'); 65 | 66 | // Build Python & React distribution files 67 | builder.buildAll(); 68 | 69 | const options = { 70 | app: [ 71 | 'app', 72 | '--asar', 73 | '--extra-resource=./resources/app', 74 | '--extra-resource=./resources/app.debug', 75 | '--extra-resource=./resources/mkvtoolnix/mkvmerge.exe', 76 | '--extra-resource=./resources/ffmpeg/ffmpeg.exe', 77 | '--extra-resource=./resources/ffmpeg/ffprobe.exe', 78 | '--extra-resource=./resources/modules', 79 | '--extra-resource=./resources/__init__.py', 80 | '--icon ./public/favicon.ico', 81 | '--win32', 82 | '--out', 83 | './dist/windows', 84 | '--overwrite', 85 | '--debug' 86 | ].join(' '), 87 | 88 | spawn: spawnOptions 89 | }; 90 | 91 | spawnSync(`electron-packager . ${options.app}`, options.spawn); 92 | 93 | const { MSICreator } = require('electron-wix-msi'); 94 | 95 | const msiCreator = new MSICreator({ 96 | appDirectory: path('../dist/windows/app-win32-x64'), 97 | appIconPath: path('../utilities/msi/images/icon.ico'), 98 | outputDirectory: path('../dist/windows/setup'), 99 | description: 'MKVToolNix batch processing tool', 100 | exe: 'app', 101 | manufacturer: 'MKVToolNix Batch Tool', 102 | name: 'MKVToolNix Batch Tool', 103 | ui: { 104 | chooseDirectory: true, 105 | images: { 106 | background: path('../utilities/msi/images/background.png'), 107 | banner: path('../utilities/msi/images/banner.png') 108 | } 109 | }, 110 | version: '2.5.4' 111 | }); 112 | 113 | // Customized MSI template 114 | msiCreator.wixTemplate = msiCreator.wixTemplate 115 | .replace(/ \(Machine - MSI\)/gi, '') 116 | .replace(/ \(Machine\)/gi, ''); 117 | 118 | // Create .wxs template and compile MSI 119 | msiCreator.create().then(() => msiCreator.compile()); 120 | }; 121 | 122 | } 123 | 124 | module.exports.Packager = Packager; 125 | -------------------------------------------------------------------------------- /scripts/start.js: -------------------------------------------------------------------------------- 1 | const { spawn, spawnSync } = require('child_process'); 2 | const getPort = require('get-port'); 3 | const { get } = require('axios'); 4 | 5 | /** 6 | * @namespace Starter 7 | * @description - Scripts to start Electron, React, and Python. 8 | */ 9 | class Starter { 10 | 11 | /** 12 | * @description - Starts developer mode. 13 | * @memberof Starter 14 | */ 15 | developerMode = async () => { 16 | 17 | // Child spawn options for console 18 | const spawnOptions = { 19 | hideLogs: { detached: false, shell: true, stdio: 'pipe' }, 20 | showLogs: { detached: false, shell: true, stdio: 'inherit' } 21 | }; 22 | 23 | /** 24 | * Method to get first port in range of 3001-3999, 25 | * Remains unused here so will be the same as the 26 | * port used in main.js 27 | */ 28 | const port = await getPort({ 29 | port: getPort.makeRange(3001, 3999) 30 | }); 31 | 32 | // Kill anything that might using required React port 33 | spawnSync('npx kill-port 3000', spawnOptions.hideLogs); 34 | 35 | // Start & identify React & Electron processes 36 | spawn('cross-env BROWSER=none react-scripts start', spawnOptions.showLogs); 37 | spawn('electron .', spawnOptions.showLogs); 38 | 39 | // Kill processes on exit 40 | const exitOnEvent = (event) => { 41 | process.once(event, () => { 42 | try { 43 | 44 | // These errors are expected since the connection is closing 45 | const expectedErrors = ['ECONNRESET', 'ECONNREFUSED']; 46 | 47 | // Send command to Flask server to quit and close 48 | get(`http://localhost:${port}/quit`) 49 | // eslint-disable-next-line no-console 50 | .catch((error) => !expectedErrors.includes(error.code) && console.log(error)); 51 | 52 | } catch (error) { 53 | 54 | // This errors is expected since the process is closing 55 | if (error.code !== 'ESRCH') console.error(error); 56 | } 57 | }); 58 | }; 59 | 60 | const exitEvents = ['exit', 'SIGINT', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'SIGTERM']; 61 | exitEvents.forEach(exitOnEvent); 62 | }; 63 | 64 | } 65 | 66 | module.exports = { Starter }; 67 | -------------------------------------------------------------------------------- /src/components/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component, Fragment } from 'react'; 2 | import { darkTheme, lightTheme, togglePalette } from 'theme/palettes'; 3 | 4 | import MainPage from 'components/pages/main/MainPage'; 5 | import Navigation from 'components/navigation/Navigation'; 6 | import SettingsPage from 'components/pages/settings/SettingsPage'; 7 | import Titlebar from 'components/titlebar/Titlebar'; 8 | import { loadTheme } from 'office-ui-fabric-react'; 9 | import { settings } from 'utils/settings'; 10 | 11 | import styles from 'components/App.module.scss'; 12 | 13 | /** 14 | * @namespace App 15 | * @description - Controls global state and page navigation 16 | */ 17 | class App extends Component { 18 | state = { 19 | input: '', 20 | output: '', 21 | page: 'main', 22 | settings: {} 23 | }; 24 | 25 | // Initialize settings on load 26 | componentDidMount() { 27 | loadTheme({ palette: darkTheme }); // default theme 28 | const settingDefaults = settings.getSettings(); 29 | 30 | // Always default debug mode to false 31 | settingDefaults.isDebugMode = false; 32 | settings.setItem('isDebugMode', false); 33 | 34 | this.setState({ 35 | output: settings.getItem('outputDir') || '', 36 | settings: settingDefaults 37 | }); 38 | } 39 | 40 | componentDidUpdate(_prevProps, prevState) { 41 | const { 42 | state: { 43 | settings: { theme } 44 | } 45 | } = this; 46 | const { 47 | settings: { theme: prevTheme } 48 | } = prevState; 49 | 50 | if (theme !== prevTheme) { 51 | togglePalette(theme); 52 | 53 | if (theme === 'light') loadTheme({ palette: lightTheme }); 54 | else loadTheme({ palette: darkTheme }); 55 | } 56 | } 57 | 58 | // Method to set global app state 59 | setAppState = (state, callback) => this.setState(state, callback); 60 | 61 | // Method to update settings (including state) 62 | updateSetting = (item, value, callback) => { 63 | settings.setItem(item, value); 64 | this.setState({ settings: settings.getSettings() }, callback); 65 | }; 66 | 67 | // Method to update multiple settings (including state) 68 | updateMultipleSettings = (newSettings, callback) => { 69 | const currentSettings = settings.getSettings(); 70 | const updatedSettings = { ...currentSettings, ...newSettings }; 71 | 72 | settings.saveSettings(updatedSettings); 73 | this.setState({ settings: updatedSettings }, callback); 74 | }; 75 | 76 | render() { 77 | const { 78 | setAppState, 79 | state: { input, output, page, settings: stateSettings, theme }, 80 | updateMultipleSettings, 81 | updateSetting 82 | } = this; 83 | 84 | const componentProps = { 85 | appState: { input, output, theme }, 86 | setAppState, 87 | settings: stateSettings, 88 | updateMultipleSettings, 89 | updateSetting 90 | }; 91 | 92 | return ( 93 | 94 | 95 |
96 | 97 | 98 |
99 |
100 | ); 101 | } 102 | } 103 | 104 | /** 105 | * @description - Page navigation controller. 106 | * @property {Component} page - Component to render. 107 | */ 108 | function PageController(props) { 109 | const { page, ...componentProps } = props; 110 | 111 | switch (page) { 112 | case 'settings': 113 | return ; 114 | 115 | case 'main': 116 | default: 117 | return ; 118 | } 119 | } 120 | 121 | export default App; 122 | -------------------------------------------------------------------------------- /src/components/App.module.scss: -------------------------------------------------------------------------------- 1 | .main { 2 | display: grid; 3 | grid-template-columns: 1fr 8fr; 4 | height: 330px; 5 | } -------------------------------------------------------------------------------- /src/components/dialog/Notice.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from 'react'; 2 | import { 3 | Dialog, 4 | DialogFooter, 5 | DialogType 6 | } from 'office-ui-fabric-react/lib/Dialog'; 7 | 8 | import { PrimaryButton } from 'office-ui-fabric-react/lib/Button'; 9 | import { useId } from '@uifabric/react-hooks'; 10 | 11 | import PropTypes from 'prop-types'; 12 | 13 | /** 14 | * @namespace Notice 15 | * @description - Generic notice component to display messages to the end user. 16 | * 17 | * @property {boolean} hideDialog - Boolean to determine if the dialog should be shown. 18 | * @property {string} messageText - Text to show as the main message. 19 | * @property {string} messageTitle - Text to show as the title of the notice. 20 | * @property {function} setHideDialog - Function used to set the `hideDialog` boolean. 21 | * @tutorial - https://developer.microsoft.com/en-us/fluentui#/controls/web/dialog 22 | */ 23 | 24 | const Notice = (props) => { 25 | const { hideDialog, messageText, messageTitle, setHideDialog } = props; 26 | 27 | const dialogContentProps = { 28 | type: DialogType.normal, 29 | title: messageTitle, 30 | closeButtonAriaLabel: 'Close', 31 | subText: messageText 32 | }; 33 | 34 | // Ensure unique IDs 35 | const labelId = useId('dialogLabel'); 36 | const subTextId = useId('subTextLabel'); 37 | 38 | const modalProps = useMemo( 39 | () => ({ 40 | titleAriaId: labelId, 41 | subtitleAriaId: subTextId, 42 | isBlocking: false, 43 | styles: { main: { maxWidth: 450 } } 44 | }), 45 | [labelId, subTextId] 46 | ); 47 | 48 | const toggleHideDialog = () => setHideDialog(!hideDialog); 49 | 50 | return ( 51 | 61 | ); 62 | }; 63 | 64 | Notice.propTypes = { 65 | hideDialog: PropTypes.bool.isRequired, 66 | messageText: PropTypes.string.isRequired, 67 | setHideDialog: PropTypes.func.isRequired, 68 | messageTitle: PropTypes.string.isRequired 69 | }; 70 | 71 | export default Notice; 72 | -------------------------------------------------------------------------------- /src/components/footer/Footer.js: -------------------------------------------------------------------------------- 1 | import { PrimaryButton } from 'office-ui-fabric-react'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | import styles from 'components/footer/assets/styles/Footer.module.scss'; 5 | 6 | /** 7 | * @namespace Footer 8 | * @property {string|null} [buttonClassName=null] - Optional class name for button. 9 | * @property {function} buttonOnClick - On click handler for button. 10 | * @property {string|null} [buttonIcon=null] - Footer button icon. 11 | * @property {string} buttonText - Footer button text. 12 | * @property {string} buttonTitle - Title for button element. 13 | * @property {boolean} [disabled=false] - Boolean determining if button is disabled. 14 | */ 15 | const Footer = (props) => { 16 | const { 17 | buttonClassName = null, 18 | buttonOnClick, 19 | buttonIcon = null, 20 | buttonText, 21 | buttonTitle, 22 | disabled = false 23 | } = props; 24 | 25 | const className = buttonClassName 26 | ? `${styles['continue-button']} ${styles[buttonClassName]}` 27 | : styles['continue-button']; 28 | 29 | return ( 30 |
31 | 39 |
40 | ); 41 | }; 42 | 43 | Footer.propTypes = { 44 | buttonClassName: PropTypes.string, 45 | buttonOnClick: PropTypes.func.isRequired, 46 | buttonIcon: PropTypes.string, 47 | buttonText: PropTypes.string.isRequired, 48 | disabled: PropTypes.bool 49 | }; 50 | 51 | Footer.defaultProps = { 52 | buttonClassName: null, 53 | buttonIcon: null, 54 | disabled: false 55 | }; 56 | 57 | export default Footer; 58 | -------------------------------------------------------------------------------- /src/components/footer/assets/styles/Footer.module.scss: -------------------------------------------------------------------------------- 1 | @import 'theme/variables.scss'; 2 | 3 | .footer { 4 | display: flex; 5 | flex-direction: row-reverse; 6 | justify-content: flex-start; 7 | align-items: center; 8 | width: 100%; 9 | margin-top: 15px; 10 | } 11 | 12 | .continue-button { 13 | width: 117px; 14 | height: 30px; 15 | margin: 25px 15px; 16 | &[disabled] { 17 | cursor: not-allowed; 18 | pointer-events: auto; 19 | opacity: .75; 20 | 21 | &:hover { 22 | &::before { 23 | content: "You must first select a source and output folder"; 24 | position: fixed; 25 | left: 180px; 26 | padding-top: 6px; 27 | color: var(--primary); 28 | } 29 | } 30 | } 31 | } 32 | 33 | .reset-button { 34 | margin: 49px 0 0; 35 | } 36 | 37 | .tooltip { 38 | margin-top: 10px; 39 | } -------------------------------------------------------------------------------- /src/components/navigation/Navigation.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | 3 | import FoldersIcon from 'components/navigation/assets/icons/FoldersIcon'; 4 | import PropTypes from 'prop-types'; 5 | import SettingsIcon from 'components/navigation/assets/icons/SettingsIcon'; 6 | import ThemeIcon from 'components/navigation/assets/icons/ThemeIcon'; 7 | import styles from 'components/navigation/assets/styles/Navigation.module.scss'; 8 | 9 | /** 10 | * @namespace Navigation 11 | * @description - Settings page of the app where settings are updated. 12 | * 13 | * @property {object} appState - Global app state. 14 | * @property {function} setAppState - Function to set global app state. 15 | * @property {object} settings - User defined, persistent settings. 16 | * @property {function} updateMultipleSettings - Function to update multiple user defined settings at once. 17 | * @property {function} updateSetting - Function to update a single setting at a time. 18 | */ 19 | const Navigation = (props) => { 20 | const [active, setActive] = useState('folders'); 21 | 22 | const setFoldersActive = () => { 23 | props.setAppState({ page: 'home' }, setActive('folders')); 24 | }; 25 | 26 | const setSettingsActive = () => { 27 | props.setAppState({ page: 'settings' }, setActive('settings')); 28 | }; 29 | 30 | const setClassName = (type) => 31 | active === type ? `${styles.active} ${styles.svg}` : styles.svg; 32 | 33 | const toggleAppTheme = () => { 34 | const { 35 | settings: { theme } 36 | } = props; 37 | const otherTheme = theme === 'dark' ? 'light' : 'dark'; 38 | 39 | props.updateSetting('theme', otherTheme); 40 | }; 41 | 42 | return ( 43 | 68 | ); 69 | }; 70 | 71 | Navigation.propTypes = { 72 | appState: PropTypes.object.isRequired, 73 | setAppState: PropTypes.func.isRequired, 74 | settings: PropTypes.object.isRequired, 75 | updateMultipleSettings: PropTypes.func, 76 | updateSetting: PropTypes.func 77 | }; 78 | 79 | export default Navigation; 80 | -------------------------------------------------------------------------------- /src/components/navigation/assets/icons/FoldersIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const FoldersIcon = (props) => { 4 | return ( 5 | 6 | ); 7 | }; 8 | 9 | export default FoldersIcon; -------------------------------------------------------------------------------- /src/components/navigation/assets/icons/SettingsIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const SettingsIcon = (props) => { 4 | return ( 5 | 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SettingsIcon; -------------------------------------------------------------------------------- /src/components/navigation/assets/icons/ThemeIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const ThemeIcon = (props) => { 4 | return ( 5 | 6 | ); 7 | }; 8 | 9 | export default ThemeIcon; -------------------------------------------------------------------------------- /src/components/navigation/assets/styles/Navigation.module.scss: -------------------------------------------------------------------------------- 1 | @import 'theme/variables.scss'; 2 | 3 | .aside { 4 | display: flex; 5 | flex-direction: column; 6 | border-right: var(--border); 7 | margin-top: -8px; 8 | width: 80px; 9 | } 10 | 11 | .svg { 12 | display: flex; 13 | align-items: center; 14 | justify-content: center; 15 | height: 80px; 16 | 17 | svg { 18 | color: var(--white); 19 | width: 40px; 20 | } 21 | 22 | &:hover { 23 | cursor: pointer; 24 | 25 | &:not(.active) { 26 | background-color: var(--hover-state); 27 | } 28 | } 29 | 30 | &.active{ 31 | background-color: var(--active-state); 32 | } 33 | } 34 | 35 | .theme { 36 | svg { 37 | width: 40px; 38 | color: var(--primary); 39 | transform: scale(-1, 1); 40 | position: fixed; 41 | bottom: 25px; 42 | left: 20px; 43 | cursor: pointer; 44 | } 45 | } -------------------------------------------------------------------------------- /src/components/pages/main/InputField.js: -------------------------------------------------------------------------------- 1 | import { DefaultButton } from 'office-ui-fabric-react'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | import { TextField } from 'office-ui-fabric-react/lib/TextField'; 5 | import styles from 'components/pages/main/assets/styles/InputField.module.scss'; 6 | 7 | /** 8 | * @description - Input section component 9 | * @property {boolean} disabled - Determines whether input field is disabled or not. 10 | * @property {string} label - Input label. 11 | * @property {string} placeholder - Input placeholder. 12 | * @property {function} setValue - Function set input value. 13 | * @property {string} type - Type of input field (e.g., input or output directory). 14 | * @property {string} value - Current value of input field. 15 | * 16 | * @memberof Home 17 | */ 18 | 19 | const InputField = (props) => { 20 | const { disabled, label, placeholder, setValue, value } = props; 21 | 22 | const onDrop = (event) => { 23 | const path = event.dataTransfer.files[0].path; 24 | setValue(path); 25 | }; 26 | 27 | return ( 28 |
29 | 40 | 41 | 48 |
49 | ); 50 | }; 51 | 52 | InputField.propTypes = { 53 | disabled: PropTypes.bool, 54 | label: PropTypes.string.isRequired, 55 | placeholder: PropTypes.string.isRequired, 56 | setValue: PropTypes.func.isRequired, 57 | value: PropTypes.string.isRequired 58 | }; 59 | 60 | export default InputField; 61 | -------------------------------------------------------------------------------- /src/components/pages/main/LoadingScreen.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { Label } from 'office-ui-fabric-react/lib/Label'; 4 | import Spinner from 'components/pages/main/assets/icons/Spinner'; 5 | import { socket } from 'utils/requests'; 6 | import styles from 'components/pages/main/assets/styles/LoadingScreen.module.scss'; 7 | 8 | /** 9 | * @description - Loading screen for when data is processing 10 | * @memberof MainPage 11 | */ 12 | class LoadingScreen extends Component { 13 | state = { 14 | batchSize: 0, 15 | currentCount: 0 16 | }; 17 | 18 | setBatchSize = (batchSize) => { 19 | this.setState({ batchSize }); 20 | }; 21 | 22 | processDirectory = () => { 23 | this.setState({ currentCount: this.state.currentCount + 1 }); 24 | }; 25 | 26 | componentDidMount() { 27 | // Configure socket communication 28 | socket.on('batch_size', this.setBatchSize); 29 | socket.on('processing_subdirectory', this.processDirectory); 30 | } 31 | 32 | componentWillUnmount() { 33 | // Disconnect socket on unmount 34 | socket.off('batch_size', this.setBatchSize); 35 | socket.off('processing_subdirectory', this.processDirectory); 36 | } 37 | 38 | render() { 39 | const { 40 | state: { batchSize, currentCount } 41 | } = this; 42 | 43 | return ( 44 |
45 | 46 | 49 |
50 | ); 51 | } 52 | } 53 | 54 | export default LoadingScreen; 55 | -------------------------------------------------------------------------------- /src/components/pages/main/assets/icons/Spinner.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Spinner = (props) => { 4 | return ( 5 | 10 | 11 | 16 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 56 | 57 | 58 | 59 | 60 | 61 | ); 62 | }; 63 | 64 | export default Spinner; 65 | -------------------------------------------------------------------------------- /src/components/pages/main/assets/styles/InputField.module.scss: -------------------------------------------------------------------------------- 1 | .browse-button { 2 | margin-top: 29px; 3 | margin-left: 4px; 4 | } 5 | 6 | .input-block { 7 | display: flex; 8 | margin: 15px 15px 0; 9 | } 10 | 11 | .input-field { 12 | width: 100%; 13 | max-width: 800px; 14 | } -------------------------------------------------------------------------------- /src/components/pages/main/assets/styles/LoadingScreen.module.scss: -------------------------------------------------------------------------------- 1 | .label { 2 | color: var(--white-constant); 3 | } 4 | 5 | .spinner { 6 | position: fixed; 7 | top: 32px; 8 | right: 0; 9 | bottom: 0; 10 | left: 0; 11 | display: flex; 12 | justify-content: center; 13 | align-items: center; 14 | flex-direction: column; 15 | background: var(--loading-background-color); 16 | z-index: 1; 17 | cursor: not-allowed; 18 | 19 | * { 20 | cursor: not-allowed; 21 | } 22 | } 23 | 24 | .spinner-icon { 25 | height: 100px; 26 | width: 100px; 27 | margin-top: -16px; 28 | } -------------------------------------------------------------------------------- /src/components/pages/main/assets/styles/MainPage.module.scss: -------------------------------------------------------------------------------- 1 | @import 'theme/variables.scss'; 2 | 3 | .home { 4 | padding: 0 15px; 5 | } 6 | 7 | .checkbox { 8 | margin: 12px 20px; 9 | width: fit-content; 10 | } 11 | 12 | .mode-settings { 13 | display: flex; 14 | flex-direction: column; 15 | margin: 23px 12px -33px; 16 | 17 | button:first-child { 18 | margin-right: 7px; 19 | } 20 | } 21 | 22 | :global(.ms-Callout.ms-Dropdown-callout) { 23 | height: 110px !important; 24 | } 25 | -------------------------------------------------------------------------------- /src/components/pages/settings/LanguageSettings.js: -------------------------------------------------------------------------------- 1 | import { Dropdown, DropdownMenuItemType } from 'office-ui-fabric-react/lib/Dropdown'; 2 | import React, { useEffect, useMemo, useState } from 'react'; 3 | 4 | import { Icon } from 'office-ui-fabric-react/lib/Icon'; 5 | import { Label } from 'office-ui-fabric-react/lib/Label'; 6 | import PropTypes from 'prop-types'; 7 | import { Stack } from 'office-ui-fabric-react/lib/Stack'; 8 | import { get } from 'utils/requests'; 9 | 10 | const onRenderLabel = (props) => ( 11 | 12 | 17 | 22 | 23 | ); 24 | 25 | /** 26 | * @description - Language setting dropdown for settings page 27 | * @property {object} language - Selected language object with `key` and `text` keys. 28 | * @property {function} setLanguageSetting - Callback handler to return language data to the parent. 29 | * 30 | * @memberof SettingsPage 31 | */ 32 | const LanguageSettings = (props) => { 33 | const { 34 | language: { text, key }, 35 | setLanguageSetting 36 | } = props; 37 | 38 | // Primary languages to select from 39 | const primaryLanguageOptions = useMemo(() => ([ 40 | { key: 'unset', text: 'None' }, 41 | { key: 'chi', text: 'Chinese' }, 42 | { key: 'dut', text: 'Dutch' }, 43 | { key: 'eng', text: 'English' }, 44 | { key: 'spa', text: 'Spanish' }, 45 | { key: 'fre', text: 'French' }, 46 | { key: 'ger', text: 'German' }, 47 | { key: 'ita', text: 'Italian' }, 48 | { key: 'jpn', text: 'Japanese' }, 49 | { key: 'por', text: 'Portuguese' }, 50 | { key: 'rus', text: 'Russian' }, 51 | { key: 'swe', text: 'Swedish' } 52 | ]), []); 53 | 54 | const [languageOptions, setLanguageOptions] = useState(primaryLanguageOptions); 55 | 56 | // Additional supported languages (from MKVToolNix) 57 | useEffect(() => { 58 | 59 | // Create hashmap of existing keys for reference 60 | const existingKeys = primaryLanguageOptions.reduce((acc, languageOption) => { 61 | acc[languageOption.key] = true; 62 | return acc; 63 | }, {}); 64 | 65 | get('supported_languages', (languages) => { 66 | const additionalLanguageOptions = [ 67 | { 68 | key: 'additional-languages', 69 | text: 'Full Language List', 70 | itemType: DropdownMenuItemType.Header 71 | }, 72 | 73 | // Don't include existing (primary) languages 74 | ...Object.values(languages).filter((option) => { 75 | return !(option.key in existingKeys); 76 | }) 77 | ]; 78 | 79 | // Combine primary and additional language options 80 | setLanguageOptions([ 81 | ...primaryLanguageOptions, 82 | ...additionalLanguageOptions 83 | ]); 84 | }); 85 | }, [primaryLanguageOptions]); 86 | 87 | const onKeyDown = (event) => { 88 | const option = languageOptions.find((language) => { 89 | return language.key[0] === event.key; 90 | }); 91 | 92 | if (option) { 93 | setLanguageSetting(event, option); 94 | } 95 | }; 96 | 97 | return ( 98 | 108 | ); 109 | }; 110 | 111 | LanguageSettings.propTypes = { 112 | language: PropTypes.object.isRequired, 113 | setLanguageSetting: PropTypes.func.isRequired 114 | }; 115 | 116 | 117 | export default LanguageSettings; 118 | -------------------------------------------------------------------------------- /src/components/pages/settings/SettingsPage.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox'; 3 | import LanguageSettings from 'components/pages/settings/LanguageSettings'; 4 | import Notice from 'components/dialog/Notice'; 5 | import PropTypes from 'prop-types'; 6 | import styles from 'components/pages/settings/assets/styles/SettingsPage.module.scss'; 7 | import { app } from 'utils/services'; 8 | 9 | /** 10 | * @namespace SettingsPage 11 | * @description - Settings page of the app where settings are updated. 12 | * 13 | * @property {object} appState - Global app state. 14 | * @property {function} setAppState - Function to set global app state (unused). 15 | * @property {object} settings - User defined, persistent settings. 16 | * @property {function} updateMultipleSettings - Function to update multiple user defined settings at once. 17 | * @property {function} updateSetting - Function to update a single setting at a time. 18 | * 19 | * @memberof Pages 20 | */ 21 | class SettingsPage extends Component { 22 | state = { 23 | isDebugMode: true, 24 | isRememberOutputDir: false, 25 | isRemoveAds: false, 26 | isRemoveExistingSubtitles: false, 27 | isRemoveOld: false, 28 | language: { key: 'unset', text: 'None' }, 29 | noticeData: { 30 | hideDialog: true, 31 | messageText: 'Manually closing the console may cause the application to misbehave. If this happens, restart the application.', 32 | messageTitle: 'Notice' 33 | } 34 | }; 35 | 36 | // Keep component up-to-date w/latest props 37 | static getDerivedStateFromProps(nextProps) { 38 | return { 39 | isDebugMode: nextProps.settings.isDebugMode, 40 | isRememberOutputDir: nextProps.settings.isRememberOutputDir, 41 | isRemoveAds: nextProps.settings.isRemoveAds, 42 | isRemoveExistingSubtitles: nextProps.settings.isRemoveExistingSubtitles, 43 | isRemoveOld: nextProps.settings.isRemoveOld, 44 | language: nextProps.settings.language 45 | }; 46 | } 47 | 48 | setHideDialog = (hideDialog) => { 49 | this.setState({ noticeData: { ...this.state.noticeData, hideDialog } }); 50 | } 51 | 52 | // Method to toggle "subtitle language" setting 53 | setLanguageSetting = (event, language) => { 54 | this.props.updateSetting('language', language); 55 | }; 56 | 57 | // Generic method to toggle or update a setting 58 | toggleSetting = (option) => { 59 | this.props.updateSetting(option, !this.props.settings[option]); 60 | }; 61 | 62 | // Method to update the remember output directory and related settings 63 | updateRememberOutputDir = () => { 64 | const { isRememberOutputDir, isSameAsSource } = this.props.settings; 65 | const outputIfNotSameAsSource = !isSameAsSource && this.props.appState.output; 66 | 67 | if (isRememberOutputDir) { 68 | this.props.updateMultipleSettings({ 69 | isRememberOutputDir: false, 70 | outputDir: null 71 | }); 72 | } else { 73 | this.props.updateMultipleSettings({ 74 | isRememberOutputDir: true, 75 | outputDir: outputIfNotSameAsSource || null 76 | }); 77 | } 78 | }; 79 | 80 | toggleDetached = () => { 81 | this.toggleSetting('isDebugMode'); 82 | 83 | /** 84 | * Spamming checkbox would otherwise cause 85 | * issues w/async calls from socket.io 86 | */ 87 | const debounceOption = (fn) => { 88 | const timeoutId = 'enable-dev-console-timeout'; 89 | let timeout = this.props.settings[timeoutId]; 90 | 91 | return () => { 92 | if (timeout) { 93 | clearTimeout(Number(timeout)); 94 | this.props.updateSetting(timeoutId, 0); 95 | } 96 | timeout = setTimeout(fn, app.reconnectionDelay); 97 | this.props.updateSetting(timeoutId, timeout); 98 | }; 99 | }; 100 | 101 | // Debounced function to restart app 102 | const debouncedRestart = debounceOption(() => { 103 | const { isDebugMode } = this.state; 104 | if (isDebugMode) { 105 | this.setHideDialog(false); 106 | } 107 | 108 | app.restart({ 109 | detached: isDebugMode, 110 | shell: true, 111 | stdio: isDebugMode ? 'inherit' : 'pipe' 112 | }); 113 | }); 114 | 115 | // Invoke debounced restart 116 | debouncedRestart(); 117 | }; 118 | 119 | render() { 120 | const { 121 | setHideDialog, 122 | setLanguageSetting, 123 | state: { 124 | isRememberOutputDir, 125 | isRemoveAds, 126 | isRemoveExistingSubtitles, 127 | isRemoveOld, 128 | language, 129 | isDebugMode, 130 | noticeData 131 | }, 132 | toggleDetached, 133 | toggleSetting, 134 | updateRememberOutputDir 135 | } = this; 136 | 137 | return ( 138 |
139 | 140 | 144 | toggleSetting('isRemoveExistingSubtitles') } 149 | /> 150 | 151 | toggleSetting('isRemoveOld') } 156 | /> 157 | 158 | toggleSetting('isRemoveAds') } 163 | /> 164 | 165 | 171 | 172 | 178 |
179 | ); 180 | } 181 | } 182 | 183 | 184 | SettingsPage.defaultProps = { 185 | updateMultipleSettings: undefined, 186 | updateSetting: undefined 187 | }; 188 | 189 | SettingsPage.propTypes = { 190 | appState: PropTypes.object.isRequired, 191 | settings: PropTypes.shape({ 192 | isSameAsSource: PropTypes.bool.isRequired, 193 | isDebugMode: PropTypes.bool.isRequired, 194 | isRememberOutputDir: PropTypes.bool.isRequired, 195 | isRemoveAds: PropTypes.bool.isRequired, 196 | isRemoveExistingSubtitles: PropTypes.bool.isRequired, 197 | isRemoveOld: PropTypes.bool.isRequired, 198 | language: PropTypes.shape({ 199 | key: PropTypes.string.isRequired, 200 | text: PropTypes.string.isRequired 201 | }).isRequired 202 | }).isRequired, 203 | updateMultipleSettings: PropTypes.func, 204 | updateSetting: PropTypes.func 205 | }; 206 | 207 | export default SettingsPage; 208 | -------------------------------------------------------------------------------- /src/components/pages/settings/assets/styles/SettingsPage.module.scss: -------------------------------------------------------------------------------- 1 | .settings { 2 | padding: 15px 30px; 3 | 4 | .checkbox { 5 | margin: 24px 5px 0; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/components/titlebar/Favicon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | /** 4 | * @description - Favicon for titlebar of app. 5 | * @property {*} props - Optional props drilled down from parent component (e.g., className). 6 | * 7 | * @memberof Titlebar 8 | */ 9 | const Favicon = (props) => { 10 | return ( 11 | 17 | 18 | 23 | 28 | 33 | 34 | 35 | ); 36 | }; 37 | 38 | export default Favicon; 39 | -------------------------------------------------------------------------------- /src/components/titlebar/Titlebar.js: -------------------------------------------------------------------------------- 1 | import { 2 | CloseButton, 3 | MinimizeButton 4 | } from 'components/titlebar/TitlebarButtons'; 5 | 6 | import Favicon from 'components/titlebar/Favicon'; 7 | import React from 'react'; 8 | import { app } from 'utils/services'; 9 | import { initializeIcons } from 'office-ui-fabric-react/lib/Icons'; 10 | import styles from 'components/titlebar/scss/Titlebar.module.scss'; 11 | 12 | initializeIcons(); 13 | 14 | /** 15 | * @namespace Titlebar 16 | * @description Title Component to use as an Electron customized titlebar. 17 | * 18 | * @property {id} electron-window-title-text used in main.js to set opacity on/off focus. 19 | * @property {id} electron-window-title-buttons used in main.js to set opacity on/off focus. 20 | */ 21 | 22 | const Titlebar = () => { 23 | return ( 24 |
25 |
26 | 27 | {document.title} 28 |
29 | 30 |
31 | 32 | 33 |
34 |
35 | ); 36 | }; 37 | 38 | export default Titlebar; 39 | -------------------------------------------------------------------------------- /src/components/titlebar/TitlebarButtons.js: -------------------------------------------------------------------------------- 1 | import { IconButton } from '@fluentui/react/lib/Button'; 2 | import React from 'react'; 3 | import styles from 'components/titlebar/scss/TitlebarButtons.module.scss'; 4 | 5 | /** 6 | * @description Titlebar minimize button. 7 | * @property {*} props - Optional props drilled down from parent component (e.g., className). 8 | * 9 | * @memberof Titlebar 10 | */ 11 | 12 | export const MinimizeButton = (props) => ( 13 | 20 | ); 21 | 22 | /** 23 | * @description Titlebar close button. 24 | * @property {*} props - Optional props drilled down from parent component (e.g., className). 25 | * 26 | * @memberof Titlebar 27 | */ 28 | export const CloseButton = (props) => ( 29 | 36 | ); 37 | -------------------------------------------------------------------------------- /src/components/titlebar/scss/Titlebar.module.scss: -------------------------------------------------------------------------------- 1 | @import 'theme/variables.scss'; 2 | 3 | body section.titlebar { 4 | display: flex; 5 | justify-content: space-between; 6 | align-items: center; 7 | height: 32px; 8 | padding: 0; 9 | position: fixed; 10 | top: 0; 11 | left: 0; 12 | width: 100vw; 13 | max-width: 100vw; 14 | -webkit-user-select: none; 15 | -webkit-app-region: drag; 16 | background-color: var(--primary); 17 | 18 | div { 19 | display: flex; 20 | align-items: center; 21 | 22 | span { 23 | font-size: 14px; 24 | font-weight: bold; 25 | font-family: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif; 26 | color: var(--black); 27 | } 28 | 29 | svg { 30 | color: var(--black); 31 | width: 20px; 32 | padding: 5px 6px 5px 8px; 33 | } 34 | 35 | } 36 | } -------------------------------------------------------------------------------- /src/components/titlebar/scss/TitlebarButtons.module.scss: -------------------------------------------------------------------------------- 1 | @import 'theme/variables.scss'; 2 | 3 | .button { 4 | padding: 0 25px; 5 | -webkit-app-region: no-drag; 6 | color: var(--black); 7 | border-radius: 0; 8 | 9 | &:hover { 10 | background-color: var(--background-color); 11 | color: var(--black); 12 | } 13 | 14 | &:last-child { 15 | &:hover { 16 | background-color: var(--red-exit); 17 | span { 18 | color: var(--white-constant); 19 | } 20 | } 21 | } 22 | 23 | span i { 24 | font-size: 12px; 25 | } 26 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import 'index.scss'; 2 | 3 | import * as serviceWorker from 'serviceWorker'; 4 | 5 | import App from 'components/App'; 6 | import React from 'react'; 7 | import ReactDOM from 'react-dom'; 8 | 9 | ReactDOM.render(, document.getElementById('root')); 10 | 11 | // If you want your app to work offline and load faster, you can change 12 | // unregister() to register() below. Note this comes with some pitfalls. 13 | // Learn more about service workers: https://bit.ly/CRA-PWA 14 | serviceWorker.unregister(); 15 | -------------------------------------------------------------------------------- /src/index.scss: -------------------------------------------------------------------------------- 1 | @import 'theme/variables.scss'; 2 | @import 'theme/overrides.scss'; 3 | 4 | body { 5 | background: var(--black); 6 | margin: 0; 7 | margin-top: 40px; 8 | overflow: hidden; 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | div[role="tooltip"] { 13 | color: var(--black); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' 15 | // [::1] is the IPv6 localhost address. 16 | || window.location.hostname === '[::1]' 17 | // 127.0.0.0/8 are considered localhost for IPv4. 18 | || window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | // eslint-disable-next-line no-console 45 | console.log( 46 | 'This web app is being served cache-first by a service ' 47 | + 'worker. To learn more, visit https://bit.ly/CRA-PWA' 48 | ); 49 | }); 50 | } else { 51 | // Is not localhost. Just register service worker 52 | registerValidSW(swUrl, config); 53 | } 54 | }); 55 | } 56 | } 57 | 58 | function registerValidSW(swUrl, config) { 59 | navigator.serviceWorker 60 | .register(swUrl) 61 | .then((registration) => { 62 | registration.onupdatefound = () => { 63 | const installingWorker = registration.installing; 64 | if (installingWorker == null) { 65 | return; 66 | } 67 | installingWorker.onstatechange = () => { 68 | if (installingWorker.state === 'installed') { 69 | if (navigator.serviceWorker.controller) { 70 | // At this point, the updated precached content has been fetched, 71 | // but the previous service worker will still serve the older 72 | // content until all client tabs are closed. 73 | // eslint-disable-next-line no-console 74 | console.log( 75 | 'New content is available and will be used when all ' 76 | + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 77 | ); 78 | 79 | // Execute callback 80 | if (config && config.onUpdate) { 81 | config.onUpdate(registration); 82 | } 83 | } else { 84 | // At this point, everything has been precached. 85 | // It's the perfect time to display a 86 | // "Content is cached for offline use." message. 87 | // eslint-disable-next-line no-console 88 | console.log('Content is cached for offline use.'); 89 | 90 | // Execute callback 91 | if (config && config.onSuccess) { 92 | config.onSuccess(registration); 93 | } 94 | } 95 | } 96 | }; 97 | }; 98 | }) 99 | .catch((error) => { 100 | console.error('Error during service worker registration:', error); 101 | }); 102 | } 103 | 104 | function checkValidServiceWorker(swUrl, config) { 105 | // Check if the service worker can be found. If it can't reload the page. 106 | fetch(swUrl, { 107 | headers: { 'Service-Worker': 'script' } 108 | }) 109 | .then((response) => { 110 | // Ensure service worker exists, and that we really are getting a JS file. 111 | const contentType = response.headers.get('content-type'); 112 | if ( 113 | response.status === 404 114 | || (contentType != null && contentType.indexOf('javascript') === -1) 115 | ) { 116 | // No service worker found. Probably a different app. Reload the page. 117 | navigator.serviceWorker.ready.then((registration) => { 118 | registration.unregister().then(() => { 119 | window.location.reload(); 120 | }); 121 | }); 122 | } else { 123 | // Service worker found. Proceed as normal. 124 | registerValidSW(swUrl, config); 125 | } 126 | }) 127 | .catch(() => { 128 | // eslint-disable-next-line no-console 129 | console.log( 130 | 'No internet connection found. App is running in offline mode.' 131 | ); 132 | }); 133 | } 134 | 135 | export function unregister() { 136 | if ('serviceWorker' in navigator) { 137 | navigator.serviceWorker.ready.then((registration) => { 138 | registration.unregister(); 139 | }); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/tests/App.test.js: -------------------------------------------------------------------------------- 1 | import App from 'components/App'; 2 | import { Provider } from 'react-redux'; 3 | import React from 'react'; 4 | import { render } from '@testing-library/react'; 5 | import store from 'state/store'; 6 | 7 | test('renders learn react link', () => { 8 | const { getByText } = render( 9 | 10 | 11 | 12 | ); 13 | 14 | expect(getByText(/learn/i)).toBeInTheDocument(); 15 | }); 16 | -------------------------------------------------------------------------------- /src/tests/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom/extend-expect'; 6 | -------------------------------------------------------------------------------- /src/theme/overrides.scss: -------------------------------------------------------------------------------- 1 | /* MS Fluent Overrides */ 2 | 3 | body { 4 | .ms-Callout.ms-Dropdown-callout { 5 | margin-top: 5px; 6 | border: solid 1px; 7 | height: 158px; 8 | overflow-x: auto; 9 | } 10 | 11 | .ms-Callout-main { 12 | 13 | // `!important` to override inline styles 14 | max-height: unset !important; 15 | overflow: hidden !important; 16 | } 17 | 18 | .ms-Dropdown-container i { 19 | color: var(--primary); 20 | 21 | &[data-icon-name="LocaleLanguage"] { 22 | margin-left: 8px; 23 | } 24 | } 25 | 26 | span.ms-layer { 27 | position: absolute; 28 | } 29 | 30 | div.ms-Layer { 31 | top: 32px; 32 | } 33 | 34 | div.ms-Dialog-main { 35 | margin-top: -32px; 36 | } 37 | } -------------------------------------------------------------------------------- /src/theme/palettes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace Themes 3 | * @description - Themes for Microsoft Fluent UI, which is built into the project. 4 | * 5 | * @tutorial - https://www.aka.ms/themedesigner 6 | */ 7 | 8 | export const darkTheme = { 9 | themePrimary: '#bf7e45', 10 | themeLighterAlt: '#080503', 11 | themeLighter: '#1f140b', 12 | themeLight: '#392615', 13 | themeTertiary: '#734c29', 14 | themeSecondary: '#a86f3d', 15 | themeDarkAlt: '#c68954', 16 | themeDark: '#cf996a', 17 | themeDarker: '#dbb18d', 18 | neutralLighterAlt: '#303030', 19 | neutralLighter: '#383838', 20 | neutralLight: '#464646', 21 | neutralQuaternaryAlt: '#4e4e4e', 22 | neutralQuaternary: '#555555', 23 | neutralTertiaryAlt: '#727272', 24 | neutralTertiary: '#f8f8f8', 25 | neutralSecondary: '#f9f9f9', 26 | neutralPrimaryAlt: '#fafafa', 27 | neutralPrimary: '#f5f5f5', 28 | neutralDark: '#fdfdfd', 29 | black: '#fefefe', 30 | white: '#252525', 31 | }; 32 | 33 | export const lightTheme = { 34 | themePrimary: '#0078d4', 35 | themeLighterAlt: '#eff6fc', 36 | themeLighter: '#deecf9', 37 | themeLight: '#c7e0f4', 38 | themeTertiary: '#71afe5', 39 | themeSecondary: '#2b88d8', 40 | themeDarkAlt: '#106ebe', 41 | themeDark: '#005a9e', 42 | themeDarker: '#004578', 43 | neutralLighterAlt: '#faf9f8', 44 | neutralLighter: '#f3f2f1', 45 | neutralLight: '#edebe9', 46 | neutralQuaternaryAlt: '#e1dfdd', 47 | neutralQuaternary: '#d0d0d0', 48 | neutralTertiaryAlt: '#c8c6c4', 49 | neutralTertiary: '#a19f9d', 50 | neutralSecondary: '#605e5c', 51 | neutralPrimaryAlt: '#3b3a39', 52 | neutralPrimary: '#323130', 53 | neutralDark: '#201f1e', 54 | black: '#252525', 55 | white: '#fefefe', 56 | }; 57 | 58 | /** 59 | * @description - Function to toggle theme pallet 60 | */ 61 | export const togglePalette = (theme) => { 62 | const setProperty = (item, value) => { 63 | const root = window.document.documentElement; 64 | root.style.setProperty(item, value); 65 | }; 66 | 67 | const setDark = () => { 68 | setProperty('--active-state', 'rgba(254, 254, 254, .2)'); 69 | setProperty('--background-color', 'rgba(254, 254, 254, .5)'); 70 | setProperty('--black', '#252525'); 71 | setProperty('--border', 'solid 1px rgba(254, 254, 254, .1)'); 72 | setProperty('--hover-state', 'rgba(254, 254, 254, .1)'); 73 | setProperty('--loading-background-color', 'rgba(0, 0, 0, .6)'); 74 | setProperty('--primary', '#bf7e45'); 75 | setProperty('--white', '#fefefe'); 76 | }; 77 | 78 | const setLight = () => { 79 | setProperty('--active-state', 'rgba(37, 37, 37, .2)'); 80 | setProperty('--background-color', 'rgba(37, 37, 37, .5)'); 81 | setProperty('--black', '#fefefe'); 82 | setProperty('--border', 'solid 1px rgba(37, 37, 37, .25)'); 83 | setProperty('--hover-state', 'rgba(37, 37, 37, .1)'); 84 | setProperty('--loading-background-color', 'rgba(0, 0, 0, .75)'); 85 | setProperty('--primary', '#0078d4'); 86 | setProperty('--white', '#252525'); 87 | }; 88 | 89 | if(theme === 'light') setLight(); 90 | else setDark(); 91 | }; -------------------------------------------------------------------------------- /src/theme/variables.scss: -------------------------------------------------------------------------------- 1 | // CSS custom properties which are changed 2 | // when theme is updated. 3 | :root { 4 | --active-state: rgba(254, 254, 254, .2); 5 | --background-color: rgba(254, 254, 254, .5); 6 | --black: #252525; 7 | --border: solid 1px rgba(254, 254, 254, .1); 8 | --hover-state: rgba(254, 254, 254, .1); 9 | --loading-background-color: rgba(0, 0, 0, .6); 10 | --primary: #bf7e45; 11 | --red-exit: #ff0000; 12 | --white: #fefefe; 13 | --white-constant: #fefefe; 14 | } -------------------------------------------------------------------------------- /src/utils/requests.js: -------------------------------------------------------------------------------- 1 | import socketIOClient from 'socket.io-client'; 2 | 3 | // Electron Inter Process Communication and dialog 4 | const { ipcRenderer } = window.require('electron'); 5 | 6 | // Dynamically generated TCP (open) port between 3000-3999 7 | const port = ipcRenderer.sendSync('get-port-number'); 8 | 9 | /** 10 | * @namespace Requests 11 | * @description - Helper functions for network requests (e.g., get, post, put, delete, etc..) 12 | */ 13 | 14 | /** 15 | * @description - Helper GET method for sending requests to and from the Python/Flask services. 16 | * @param {string} url - URL route of the Python/Flask service you want to use. 17 | * @param {function} callback - Callback function which uses the returned data as an argument. 18 | * @param {function} errorCallback - Callback function to use if there's an error. 19 | * @return response data from Python/Flask service. 20 | * @memberof Requests 21 | */ 22 | export const get = (route, callback, errorCallback = console.error) => { 23 | fetch(`http://localhost:${port}/${route}`) 24 | .then((response) => response.json()) 25 | .then(callback) 26 | .catch(errorCallback); 27 | }; 28 | 29 | /** 30 | * @description - Helper POST method for sending requests to and from the Python/Flask services. 31 | * @param {string} body - JSON.stringified request body of data that you want to pass. 32 | * @param {string} route - URL route of the Python/Flask service you want to use. 33 | * @param {function} callback - optional callback function to be invoked if provided. 34 | * @param {function} errorCallback - Callback function to use if there's an error. 35 | * @return response data from Python/Flask service. 36 | * @memberof Requests 37 | */ 38 | export const post = (body, route, callback, errorCallback = console.error) => { 39 | fetch(`http://localhost:${port}/${route}`, { 40 | body, 41 | method: 'POST', 42 | headers: { 'Content-type': 'application/json' } 43 | }) 44 | .then((response) => response.json()) 45 | .then(callback) 46 | .catch(errorCallback); 47 | }; 48 | 49 | /** 50 | * @description - SocketIO client interface configuration. 51 | */ 52 | export const socket = socketIOClient(`http://localhost:${port}/`); 53 | -------------------------------------------------------------------------------- /src/utils/services.js: -------------------------------------------------------------------------------- 1 | import { socket } from 'utils/requests'; 2 | 3 | // Electron Inter Process Communication and dialog 4 | const { ipcRenderer, remote } = window.require('electron'); 5 | const { dialog } = remote; 6 | 7 | /** 8 | * @namespace Services 9 | * @description - Methods from Electron Inter Process Communication. 10 | * @property {function} maximize - Function to maximize the screen size of the program. 11 | * @property {function} minimize - Function to minimize the screen size of the program. 12 | * @property {function} quit - Function to close and exit the program. 13 | * @property {function} unmaximize - Function to contract (unmaximize) the screen size of the program. 14 | * @property {function} restart - Function to restart the app with the given spawn options. 15 | */ 16 | export const app = { 17 | maximize: () => ipcRenderer.send('app-maximize'), 18 | minimize: () => ipcRenderer.send('app-minimize'), 19 | quit: () => ipcRenderer.send('app-quit'), 20 | reconnectionDelay: socket.io.reconnectionDelay(), 21 | restart: (options) => { 22 | socket.once('disconnect', () => { 23 | setTimeout(() => { 24 | ipcRenderer.send('app-restart', options); 25 | setTimeout(() => { 26 | socket.connect(); 27 | }, app.reconnectionDelay); 28 | }, app.reconnectionDelay); 29 | }); 30 | 31 | socket.disconnect(); 32 | }, 33 | unmaximize: () => ipcRenderer.send('app-unmaximize') 34 | }; 35 | 36 | /** 37 | * @description - Function to get a list of files that a user wants to have renamed, this 38 | * also returns the folder path and name the user has selected. 39 | * @return - User selected folder path. 40 | * @memberof Services 41 | */ 42 | export const getDirectory = async (callback) => { 43 | dialog 44 | .showOpenDialog({ properties: ['openDirectory'] }) 45 | .then((response) => { 46 | return response.canceled 47 | ? null 48 | : callback(String.raw`${response.filePaths[0]}`); 49 | }) 50 | .catch(console.error); 51 | }; 52 | -------------------------------------------------------------------------------- /src/utils/settings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace Settings 3 | * @description - Class to manage user settings in localStorage so they persist after 4 | * the application has closed. 5 | */ 6 | class Settings { 7 | // Check if item exists in settings 8 | hasItem = (item) => this.getSettings()[item] !== null; 9 | 10 | // Get a specific item in settings (or `undefined`) 11 | getItem = (item) => this.getSettings()[item]; 12 | 13 | // Get all settings and return as a JavaScript object literal 14 | getSettings = () => { 15 | const settings = window.localStorage.getItem(this.settingsId) 16 | ?? this.loadDefaultSettings(); 17 | 18 | // Parse settings into JSON object 19 | const settingsJSON = JSON.parse(settings); 20 | 21 | // Return object literal of settings 22 | return settingsJSON; 23 | }; 24 | 25 | // Load default settings 26 | loadDefaultSettings = () => { 27 | const settings = JSON.stringify({ 28 | isDebugMode: false, 29 | isExtractSubtitles: false, 30 | isRemoveAds: false, 31 | isRememberOutputDir: false, 32 | isRemoveExistingSubtitles: false, 33 | isRemoveOld: false, 34 | isRemoveSubtitles: false, 35 | isSameAsSource: false, 36 | language: { key: 'eng', text: 'English' }, 37 | outputDir: null, 38 | theme: 'dark' 39 | }); 40 | 41 | window.localStorage.setItem(this.settingsId, settings); 42 | 43 | return settings; 44 | }; 45 | 46 | // Delete an item if it exists, otherwise does nothing 47 | removeItem = (item) => { 48 | const settings = this.getSettings(); 49 | delete settings[item]; 50 | 51 | this.saveSettings(settings); 52 | }; 53 | 54 | // Update settings object with new settings 55 | saveSettings = (settings) => { 56 | window.localStorage.setItem(this.settingsId, JSON.stringify(settings)); 57 | }; 58 | 59 | // Set item in settings 60 | setItem = (item, setting) => 61 | this.saveSettings({ 62 | ...this.getSettings(), 63 | [item]: setting 64 | }); 65 | 66 | // ID used for various instances 67 | settingsId = 'mkvtoolnix-batch-tool-settings'; 68 | } 69 | 70 | // Export instantiated version of settings 71 | export const settings = new Settings(); 72 | -------------------------------------------------------------------------------- /utilities/dmg/images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iPzard/mkvtoolnix-batch-tool/33821381e38cf89a0702cd8276f86ccf0dd3189f/utilities/dmg/images/background.png -------------------------------------------------------------------------------- /utilities/dmg/images/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iPzard/mkvtoolnix-batch-tool/33821381e38cf89a0702cd8276f86ccf0dd3189f/utilities/dmg/images/icon.icns -------------------------------------------------------------------------------- /utilities/jsdoc/LICENSE.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | Docdash is free software, licensed under the Apache License, Version 2.0 (the 4 | "License"). Commercial and non-commercial use are permitted in compliance with 5 | the License. 6 | 7 | Copyright (c) 2016 Clement Moron and the 8 | [contributors to docdash](https://github.com/clenemt/docdash/graphs/contributors). 9 | All rights reserved. 10 | 11 | You may obtain a copy of the License at: 12 | http://www.apache.org/licenses/LICENSE-2.0 13 | 14 | In addition, a copy of the License is included with this distribution. 15 | 16 | As stated in Section 7, "Disclaimer of Warranty," of the License: 17 | 18 | > Licensor provides the Work (and each Contributor provides its Contributions) 19 | > on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 20 | > express or implied, including, without limitation, any warranties or 21 | > conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 22 | > PARTICULAR PURPOSE. You are solely responsible for determining the 23 | > appropriateness of using or redistributing the Work and assume any risks 24 | > associated with Your exercise of permissions under this License. 25 | 26 | The source code for docdash is available at: 27 | https://github.com/clenemt/docdash 28 | 29 | # Third-Party Software 30 | 31 | Docdash includes or depends upon the following third-party software, either in 32 | whole or in part. Each third-party software package is provided under its own 33 | license. 34 | 35 | ## JSDoc 3 36 | 37 | JSDoc 3 is free software, licensed under the Apache License, Version 2.0 (the 38 | "License"). Commercial and non-commercial use are permitted in compliance with 39 | the License. 40 | 41 | Copyright (c) 2011-2016 Michael Mathews and the 42 | [contributors to JSDoc](https://github.com/jsdoc3/jsdoc/graphs/contributors). 43 | All rights reserved. 44 | 45 | You may obtain a copy of the License at: 46 | http://www.apache.org/licenses/LICENSE-2.0 47 | 48 | In addition, a copy of the License is included with this distribution. 49 | 50 | As stated in Section 7, "Disclaimer of Warranty," of the License: 51 | 52 | > Licensor provides the Work (and each Contributor provides its Contributions) 53 | > on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 54 | > express or implied, including, without limitation, any warranties or 55 | > conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 56 | > PARTICULAR PURPOSE. You are solely responsible for determining the 57 | > appropriateness of using or redistributing the Work and assume any risks 58 | > associated with Your exercise of permissions under this License. 59 | 60 | The source code for JSDoc 3 is available at: 61 | https://github.com/jsdoc3/jsdoc 62 | -------------------------------------------------------------------------------- /utilities/jsdoc/README.md: -------------------------------------------------------------------------------- 1 | # daybrush-jsdoc-template 2 | [![npm package](https://img.shields.io/npm/v/daybrush-jsdoc-template.svg)](https://www.npmjs.com/package/daybrush-jsdoc-template) [![license](https://img.shields.io/npm/l/daybrush-jsdoc-template.svg)](LICENSE.md) 3 | 4 | **daybrush-jsdoc-template** is a template based on the [**docdash**](https://github.com/clenemt/docdash) template. 5 | 6 | * [Demo](http://daybrush.github.io/scenejs/release/latest/doc/) 7 | 8 | ## Install 9 | 10 | ```bash 11 | $ npm install daybrush-jsdoc-template 12 | ``` 13 | 14 | ## Usage 15 | Clone repository to your designated `jsdoc` template directory, then: 16 | 17 | ```bash 18 | $ jsdoc entry-file.js -t path/to/daybrush-jsdoc-template 19 | ``` 20 | 21 | ### scene.js 22 | ```bash 23 | $ jsdoc ./outjs ./README.md -d doc -t ./node_modules/daybrush-jsdoc-template 24 | ``` 25 | 26 | ## Usage (npm) 27 | In your projects `package.json` file add a new script: 28 | 29 | ```json 30 | "script": { 31 | "generate-docs": "node_modules/.bin/jsdoc -c jsdoc.json" 32 | } 33 | ``` 34 | 35 | In your `jsdoc.json` file, add a template option. 36 | 37 | ```json 38 | "opts": { 39 | "template": "node_modules/daybrush-jsdoc-template" 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /utilities/jsdoc/fixtures/base/chains.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @fileOverview The chains define the primary composition elements (functions) that determine the order of execution. 4 | * 5 | * @module base/chains 6 | * @requires dcl 7 | */ 8 | var dcl = require( "dcl" ); 9 | /** 10 | * @classDesc Chains define the primary composition elements (functions) that determine the order of execution. 11 | * @exports base/chains 12 | * @constructor 13 | */ 14 | var Chains = dcl( null, {declaredClass : "base/chains"} ); 15 | /** 16 | * The `close` method asks an object to shut itself down in a way that will allow it to be reopened, unlike the 17 | * [end method]{@link base/chains#end} which will call the destroy method which should make the object unusable, but also 18 | * devoid of all resources whereas `close` may still keep some resources open. 19 | * 20 | * | Heading 1 | Heading 2 | Heading 3 | 21 | * |-----------|-----------|-----------------| 22 | * | Bar | Food | This is a table | 23 | * 24 | * This uses the `before` chain which means the last one defined in the first one destroyed 25 | * @memberOf base/chains# 26 | * @name close 27 | * @see base/chains#open 28 | */ 29 | dcl.chainBefore( Chains, "close" ); 30 | /** 31 | * The `end` method will call the destroy method which should make the object unusable and 32 | * devoid of all resources, unlike the 33 | * [close method]{@link base/chains#close} asks an object to shut itself down in a way that will allow it to be reopened. 34 | * 35 | * This uses the `before` chain which means the last one defined in the first one destroyed 36 | * @memberOf base/chains# 37 | * @name end 38 | * 39 | * @example Add *this* to your application.properties. 40 | * {@lang bash} 41 | * foo=bar 42 | * 43 | */ 44 | dcl.chainBefore( Chains, "end" ); 45 | /** 46 | * Destroy is called by the end method and it is here that you should clean up after yourself. The difference between 47 | * `destroy` and [end]{@link base/chains#end} is the `end` is the verb that you raise on an object to ask it to go away 48 | * and `destroy` is where you actually do the work to clean up. Think of this as the counterpart of `constructor` yet 49 | * not called automatically. 50 | * 51 | * This uses the `before` chain which means the last one defined is the first one destroyed 52 | * @private 53 | * @memberOf base/chains# 54 | * @name destroy 55 | */ 56 | dcl.chainBefore( Chains, "destroy" ); 57 | 58 | /** 59 | * If you are using the open/close paradigm for an object that can kind of go dormant on {@link base/chains#close} and can be "reopened" 60 | * again later, here is where the "open" code will go. 61 | * 62 | * This used the `after` chain which means that the first one defined is the first one destroyed. 63 | * 64 | * @memberOf base/chains# 65 | * @name open 66 | * @see base/chains#close 67 | */ 68 | dcl.chainAfter( Chains, "open" ); 69 | 70 | module.exports = Chains; 71 | -------------------------------------------------------------------------------- /utilities/jsdoc/fixtures/base/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @fileOverview This is base definition for all composed classes defined by the system 4 | * @module base 5 | * @requires base/chains 6 | * @requires dcl 7 | */ 8 | 9 | var dcl = require( "dcl" ); 10 | var chains = require( "./chains" ); 11 | 12 | /** 13 | * @classdesc The base of all classes in the system, this is one of the few pure "classes" in core the of the system. It is a 14 | * pretty clean little class whose primary purpose is to surface the composition chains and a basis for storing 15 | * options on mixin and subclass instances. Options are handled at the instance rather than the prototype level 16 | * so that multiple instances don't compete for default values. 17 | * 18 | * @exports base 19 | * @constructor 20 | * @extends base/chains 21 | */ 22 | var Base = dcl( [chains], /** @lends base# */{ 23 | declaredClass : "Base", 24 | /** 25 | * Add an option to a class. If any members of the hash already exist in `this.options`, they will be overwritten. 26 | * @param {hash} options A hash of options you want to set 27 | * @see {base#addDefaultOptions} 28 | */ 29 | addOptions : function ( options ) { 30 | options = options || {}; 31 | if ( this.options ) {options = sys.extend( {}, sys.result( this, 'options' ), options );} 32 | this.options = options; 33 | }, 34 | /** 35 | * Add a default option to a class. The default options are only set if there is not already a 36 | * value for the option. 37 | * @param {hash} options A hash of options you want to set 38 | * @see {base#addOptions} 39 | */ 40 | addDefaultOptions : function ( options ) { 41 | options = options || {}; 42 | if ( this.options ) {options = sys.defaults( {}, sys.result( this, 'options' ), options );} 43 | this.options = options; 44 | }, 45 | 46 | /** 47 | * Call this to close your object and dispose of all maintained resources. You can define this method on your 48 | * own classes without having to call the superclass instance, however it is reccomended that you put 49 | * all disposal code in `destroy()`. You must be disciplined about calling this on your instances. 50 | * @see {base/chains#end} 51 | * @see {base/chains#destroy} 52 | */ 53 | end : function () { 54 | this.destroy() 55 | }, 56 | 57 | /** 58 | * Called when it is time to get rid of all of your instance level references and objects and events. You can 59 | * define this method on your own classes without having to call the superclass instance. It is called by 60 | * `instance.end()` automatically 61 | * @see {base/chains#end} 62 | * @see {base/chains#destroy} 63 | */ 64 | destroy : function () { 65 | 66 | } 67 | 68 | 69 | } ); 70 | 71 | Base.compose = dcl; 72 | Base.mixin = dcl.mix; 73 | module.exports = Base; 74 | -------------------------------------------------------------------------------- /utilities/jsdoc/fixtures/documents/binder.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @fileOverview allows you to bind a change watcher that looks for get and set operations on an arbitrary 4 | * property of an object at at any depth. This allows you to look for changes or intercept values asynchronously or otherwise. 5 | * @module documents/binder 6 | * @requires async 7 | * @requires documents/probe 8 | * @requires lodash 9 | * @requires promise 10 | */ 11 | var Promise = require( 'promise' ); 12 | var async = require( "async" ); 13 | var probe = require( "./probe" ); 14 | var sys = require( "lodash" ); 15 | 16 | /** 17 | * Identifies the properties that the binder expects 18 | * @type {{getter: null, getterAsync: boolean, setter: null, validator: null, validatorAsync: boolean, setterAsync: boolean}} 19 | * @private 20 | */ 21 | var dataBinderOptions = exports.dataBinderOptions = { 22 | getter : null, 23 | getterAsync : false, 24 | setter : null, 25 | validator : null, 26 | validatorAsync : false, 27 | setterAsync : false 28 | }; 29 | 30 | /** 31 | * You can unbind previously bound objects from here. 32 | * 33 | * @param {string} path The path that was bound using {@link module:documents/binder.bind} 34 | * @param {*} record The object that was bound 35 | */ 36 | exports.unbind = function ( path, record ) { 37 | var context = record; 38 | var lastParent = context; 39 | var parts = path.split( probe.delimiter ); 40 | var lastPartName = path; 41 | var lastParentName; 42 | sys.each( parts, function ( part ) { 43 | lastParentName = part; 44 | lastParent = context; 45 | context = context[part]; 46 | lastPartName = part; 47 | if ( sys.isNull( context ) || sys.isUndefined( context ) ) { 48 | context = {}; 49 | } 50 | } ); 51 | 52 | if ( lastParent === context ) { 53 | deleteBindings( record, lastPartName ); 54 | } else { 55 | deleteBindings( lastParent, lastPartName ); 56 | } 57 | 58 | function deleteBindings( mountPoint, mountName ) { 59 | mountPoint[mountName] = mountPoint["__" + mountName + "__"]; 60 | delete mountPoint["__" + mountName + "__"]; 61 | } 62 | }; 63 | 64 | /** 65 | * Bind to a property somewhere in an object. The property is found using dot notation and can be arbitrarily deep. 66 | * @param {string} path The path into the object to locate the property. For instance this could be `"_id"`, `"name.last"`. 67 | * or `"some.really.really.long.path.including.an.array.2.name"` 68 | * @param {object} record Anything you can hang a property off of 69 | * @param {options} options What you wanna do with the doohicky when yoyu bind it. 70 | * @param {function(*):Promise|*=} options.getter This is the method to run when getting the value. When it runs, you will receive 71 | * a single parameter which is the current value as the object understands it. You can return the value directly, just raise an event or 72 | * whatever your little heart demands. However, if you are asynchronous, this will turn your return value into a promise, one of the 73 | * few places this system will embrace promises over node-like error passing and that is mainly because this is a getter so a return value 74 | * is particularly important. * 75 | * @param {*} options.getter.value The current value of the record 76 | * @param {function(err, value)=} options.getter.callback When asynchronous, return you value through this method using node style 77 | * error passing (the promise is handled for you by this method). 78 | * @param {boolean=} options.getterAsync When true (not truthy) the getter is treated asynchronously and returns a promise with your value. 79 | * @param {function(*, *, *)=} options.setter A setter method 80 | * @param {*} options.setter.newVal The new value 81 | * @param {*} options.setter.oldVal The old value 82 | * @param {*} options.setter.record The record hosting the change 83 | * @param {function(*, *, *, function=)=} options.validator If you want a validator to run before settings values, pass this guy in 84 | * @param {*} options.validator.newVal The new value 85 | * @param {*} options.validator.oldVal The old value 86 | * @param {*} options.validator.record The record hosting the change 87 | * @param {function(err)=} options.validator.callback If the validator is asynchronous, then pass your value back here, otherwise pass it back as a return value. 88 | * When you use an asynchronous instance, pass the error in the first value and then the rest of the parameters are yours to play with 89 | * @param {boolean=} options.validatorAsync When true (not truthy) the validator is treated asynchornously and returns a promise with your value. 90 | * @returns {*} 91 | */ 92 | exports.bind = function ( path, record, options ) { 93 | options = sys.extend( {}, dataBinderOptions, options ); 94 | var context = record; 95 | var lastParent = context; 96 | var parts = path.split( probe.delimiter ); 97 | var lastPartName = path; 98 | var lastParentName; 99 | 100 | sys.each( parts, function ( part ) { 101 | lastParentName = part; 102 | lastParent = context; 103 | context = context[part]; 104 | lastPartName = part; 105 | if ( sys.isNull( context ) || sys.isUndefined( context ) ) { 106 | context = {}; 107 | } 108 | } ); 109 | 110 | if ( lastParent === context ) { 111 | setUpBindings( record, lastPartName ); 112 | } else { 113 | setUpBindings( lastParent, lastPartName ); 114 | } 115 | 116 | function setUpBindings( mountPoint, mountName ) { 117 | mountPoint["__" + mountName + "__"] = mountPoint[mountName]; 118 | Object.defineProperty( mountPoint, mountName, { 119 | get : function () { 120 | if ( sys.isFunction( options.getter ) ) { 121 | var promise; 122 | if ( options.getterAsync === true ) { 123 | promise = Promise.denodeify( options.getter ); 124 | } 125 | 126 | if ( promise ) { 127 | return promise( mountPoint["__" + mountName + "__"] ).then( function ( val ) { 128 | mountPoint["__" + mountName + "__"] = val; 129 | } ); 130 | } else { 131 | mountPoint["__" + mountName + "__"] = options.getter( mountPoint["__" + mountName + "__"] ); 132 | return mountPoint["__" + mountName + "__"]; 133 | } 134 | 135 | } else { 136 | return mountPoint["__" + mountName + "__"]; 137 | } 138 | }, 139 | set : function ( val ) { 140 | async.waterfall( [ 141 | function ( done ) { 142 | if ( sys.isFunction( options.validator ) ) { 143 | if ( options.validatorAsync ) { 144 | options.validator( val, mountPoint["__" + mountName + "__"], record, done ); 145 | } else { 146 | var res = options.validator( val, mountPoint["__" + mountName + "__"], record ); 147 | if ( res === true ) { 148 | done(); 149 | } else { 150 | done( res ); 151 | } 152 | } 153 | } else { 154 | done(); 155 | } 156 | }, 157 | function ( done ) { 158 | if ( sys.isFunction( options.setter ) ) { 159 | if ( options.setterAsync === true ) { 160 | options.setter( val, mountPoint["__" + mountName + "__"], record, done ); 161 | } else { 162 | done( null, options.setter( val, mountPoint["__" + mountName + "__"], record ) ); 163 | } 164 | } else { 165 | done( null, val ); 166 | } 167 | } 168 | ], function ( err, newVal ) { 169 | if ( err ) { throw new Error( err ); } 170 | mountPoint["__" + mountName + "__"] = newVal; 171 | } ); 172 | 173 | } 174 | } ); 175 | } 176 | 177 | return context; 178 | }; 179 | -------------------------------------------------------------------------------- /utilities/jsdoc/fixtures/documents/model.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @fileOverview A model is the first level if usable data-bearing entity in the system. It does NOT include any verbs for saving or anything like 4 | * that, it is a pure, in memory data container 5 | * @module documents/model 6 | * @require base 7 | * @require documents/probe 8 | * @require lodash 9 | */ 10 | 11 | var Base = require( "../base" ); 12 | var probe = require( "./probe" ); 13 | var sys = require( "lodash" ); 14 | /** 15 | * A model is the first level if usable data-bearing entity in the system. It does NOT include any verbs for saving or anything like 16 | * that, it is a pure, in memory data container 17 | * @exports documents/model 18 | * @constructor 19 | * @borrows module:documents/probe.get as get 20 | * @borrows module:documents/probe.set as set 21 | * @borrows module:documents/probe.any as any 22 | * @borrows module:documents/probe.all as all 23 | * @borrows module:documents/probe.remove as remove 24 | * @borrows module:documents/probe.seekKey as seekKey 25 | * @borrows module:documents/probe.seek as seek 26 | * @borrows module:documents/probe.findOne as findOne 27 | * @borrows module:documents/probe.findOneKey as findOneKey 28 | * @borrows module:documents/probe.findKeys as findKeys 29 | * @borrows module:documents/probe.find as find 30 | * @borrows module:documents/probe.update as update 31 | * @borrows module:documents/probe.some as some 32 | * @borrows module:documents/probe.every as every 33 | */ 34 | var Model = Base.compose( [Base], /** @lends documents/model# */{ 35 | constructor : function () { 36 | var that = this; 37 | probe.mixin( this ); 38 | 39 | var idField = "_id"; 40 | /** 41 | * The name of the field that uniquely identifies a record. When provided, some operations will take advantage of it 42 | * 43 | * @name _idField 44 | * @memberOf documents/model# 45 | * @type {string} 46 | * @private 47 | */ 48 | Object.defineProperty( this, "_idField", { 49 | get : function () { 50 | return idField; 51 | }, 52 | set : function ( val ) { 53 | idField = val; 54 | }, 55 | configurable : false, 56 | enumerable : true, 57 | writable : true 58 | } ); 59 | 60 | /** 61 | * The value of the primary key if {@link documents/model#_idField} is filled in. It will be null if none found 62 | * 63 | * @name _pkey 64 | * @memberOf documents/model# 65 | * @type {*} 66 | * @private 67 | */ 68 | Object.defineProperty( this, "_pkey", { 69 | get : function () { 70 | var val; 71 | if ( !sys.isEmpty( that._idField ) ) { 72 | val = that[that._idField]; 73 | } 74 | return val; 75 | }, 76 | set : function ( val ) { 77 | if ( !sys.isEmpty( that._idField ) ) { 78 | that[that._idField] = val; 79 | } 80 | }, 81 | configurable : false, 82 | enumerable : true, 83 | writable : true 84 | } ); 85 | 86 | /** 87 | * If {@link documents/model#_idField} is filled in and it's value is empty this will be true. 88 | * @type {boolean} 89 | * @name isNew 90 | * @memberOf documents/model# 91 | */ 92 | Object.defineProperty( this, "isNew", { 93 | get : function () { 94 | return !sys.isEmpty( that._idField ) && !sys.isEmpty( that[that._idField] ) 95 | }, 96 | configurable : false, 97 | enumerable : true, 98 | writable : false 99 | } ); 100 | 101 | /** 102 | * Returns true if this instance is empty 103 | * @type {boolean} 104 | * @name isEmpty 105 | * @memberOf documents/model# 106 | */ 107 | Object.defineProperty( this, "isEmpty", { 108 | get : function () { 109 | return sys.isEmpty( that ); 110 | }, 111 | configurable : false, 112 | enumerable : true, 113 | writable : false 114 | } ); 115 | } 116 | } ); 117 | module.exports = Model; 118 | -------------------------------------------------------------------------------- /utilities/jsdoc/fixtures/fixtures.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": { 3 | "allowUnknownTags": true 4 | }, 5 | "source": { 6 | "include": [ 7 | "fixtures/", 8 | "./README.md" 9 | ] 10 | }, 11 | "plugins": ["plugins/markdown"], 12 | "opts": { 13 | "encoding": "utf8", 14 | "template": "../", 15 | "destination": "../fixtures-doc/", 16 | "recurse": true, 17 | "verbose": true 18 | }, 19 | "markdown": { 20 | "parser": "gfm", 21 | "hardwrap": true 22 | }, 23 | "templates": { 24 | "cleverLinks": false, 25 | "monospaceLinks": false, 26 | "default": { 27 | "outputSourceFiles": true, 28 | "includeDate": false 29 | } 30 | }, 31 | "docdash": { 32 | "static": false, 33 | "sort": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /utilities/jsdoc/fixtures/mixins/bussable.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @fileOverview Provides easy access to the system bus and provides some helper methods for doing so 4 | * @module mixins/bussable 5 | * @requires postal 6 | * @requires lodash 7 | * @requires base 8 | */ 9 | var bus = require( "postal" ); 10 | var Base = require( "../base" ); 11 | var sys = require( "lodash" ); 12 | 13 | /** 14 | * @classDesc Provides easy access to the system bus and provides some helper methods for doing so 15 | * @exports mixins/bussable 16 | * @mixin 17 | */ 18 | var Bussable = Base.compose( [Base], /** @lends mixins/bussable# */{ 19 | declaredClass : "mixins/Bussable", 20 | constructor : function () { 21 | /** 22 | * The list of subscriptions maintained by the mixin 23 | * @type {Array} 24 | * @memberof mixins/bussable# 25 | * @name _subscriptions 26 | * @private 27 | */ 28 | this._subscriptions = {}; 29 | 30 | this.log.trace( "Bussable constructor" ); 31 | }, 32 | 33 | /** 34 | * Subscribe to an event 35 | * @param {string} channel The channel to subscribe to 36 | * @param {string} topic The topic to subscribe to 37 | * @param {callback} callback What to do when you get the event 38 | * @returns {object} The subscription definition 39 | */ 40 | subscribe : function ( channel, topic, callback ) { 41 | this.log.trace( "Bussable subscribe" ); 42 | var sub = bus.subscribe( {channel : channel, topic : topic, callback : callback} ); 43 | this.subscriptions[channel + "." + topic] = sub; 44 | return sub; 45 | }, 46 | 47 | /** 48 | * Subscribe to an event once 49 | * @param {string} channel The channel to subscribe to 50 | * @param {string} topic The topic to subscribe to 51 | * @param {callback} callback What to do when you get the event 52 | * @returns {object} The subscription definition 53 | */ 54 | once : function ( channel, topic, callback ) { 55 | this.log.trace( "Bussable once" ); 56 | var sub = this.subscribe( channel, topic, callback ); 57 | this.subscriptions[channel + "." + topic] = sub; 58 | sub.disposeAfter( 1 ); 59 | return sub; 60 | }, 61 | 62 | /** 63 | * Publish an event on the system bus 64 | * @param {string} channel The channel to publish to 65 | * @param {string} topic The topic to publish to 66 | * @param {object=} options What to pass to the event 67 | */ 68 | publish : function ( channel, topic, options ) { 69 | this.log.trace( "Bussable publish" ); 70 | bus.publish( {channel : channel, topic : topic, data : options} ); 71 | }, 72 | 73 | /** 74 | * Get a subscription definition 75 | * 76 | * @param {string} channel 77 | * @param {string} topic 78 | * @returns {object=} The subscription definition 79 | */ 80 | getSubscription : function ( channel, topic ) { 81 | this.log.trace( "Bussable getSubscription" ); 82 | return this.subscriptions[channel + "." + topic]; 83 | }, 84 | 85 | /** 86 | * Gets rid of all subscriptions for this object. 87 | * @private 88 | */ 89 | destroy : function () { 90 | this.log.trace( "Bussable destroy" ); 91 | 92 | sys.each( this.subscriptions, function ( sub ) { 93 | sub.unsubscribe(); 94 | } ); 95 | } 96 | } ); 97 | 98 | module.exports = Bussable; 99 | -------------------------------------------------------------------------------- /utilities/jsdoc/fixtures/strings/format.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @fileOverview String helper methods 4 | * 5 | * @module strings/format 6 | */ 7 | 8 | /** 9 | * Format a string quickly and easily using .net style format strings 10 | * @param {string} format A string format like "Hello {0}, now take off your {1}!" 11 | * @param {...?} args One argument per `{}` in the string, positionally replaced 12 | * @returns {string} 13 | * 14 | * @example 15 | * var strings = require("papyrus/strings"); 16 | * var s = strings.format("Hello {0}", "Madame Vastra"); 17 | * // s = "Hello Madame Vastra" 18 | * 19 | * @example {@lang xml} 20 | * 21 | * <%= strings.format("Hello {0}", "Madame Vastra") %> 22 | * 23 | */ 24 | module.exports = function ( format ) { 25 | var args = Array.prototype.slice.call( arguments, 1 ); 26 | return format.replace( /{(\d+)}/g, function ( match, number ) { 27 | return typeof args[number] != 'undefined' 28 | ? args[number] 29 | : match 30 | ; 31 | } ); 32 | }; 33 | -------------------------------------------------------------------------------- /utilities/jsdoc/fixtures/tutorials/Brush Teeth.md: -------------------------------------------------------------------------------- 1 | #Lorem ipsum dolor sit amet 2 | 3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra, tellus et fermentum tincidunt, massa ligula dignissim augue, ut aliquam tortor odio in odio. In faucibus metus metus. Curabitur est mi, fermentum lacinia tincidunt vitae, mattis sit amet neque. Quisque diam nisl, accumsan ac porta tincidunt, iaculis facilisis ipsum. Nulla facilisi. Aenean a metus tortor. Pellentesque congue, mauris vitae viverra varius, elit nunc dictum nisl, rhoncus ultrices nulla sapien at leo. Duis ultricies porttitor diam. Nulla facilisi. Nullam elementum, lorem eu imperdiet laoreet, est turpis sollicitudin velit, in porttitor justo dolor vel urna. Mauris in ante magna. Curabitur vitae lacus in magna mollis commodo. 4 | 5 | | Fusce lacinia | mauris ac aliquam | consequat | lacus urna feugiat erat | id viverra mi mi sit amet tortor | 6 | |---------------|-------------------|-------------|-------------------------------|---------------------------------------| 7 | | Etiam ac | 1 | 3 | 4.5 | 6.78910 | 8 | | Pellentesque e| 2 | 2 | 3 | 4 | 9 | 10 | neque lacus, quis posuere orci. Fusce molestie blandit velit, sit amet dictum eros pharetra vitae. In erat urna, condimentum ac feugiat id, rutrum et nisi. Cras ac velit lorem. Nulla facilisi. Maecenas dignissim nulla in turpis tempus sed rhoncus augue dapibus. Nulla feugiat, urna non sagittis laoreet, dolor metus rhoncus justo, sed semper ante lacus eget quam. Sed ac ligula magna. Sed tincidunt pulvinar neque in porta. Nullam quis lacus orci. Pellentesque ornare viverra lacus, id aliquam magna venenatis a. 11 | 12 | Sed id tristique lorem. Ut sodales turpis nec mauris gravida interdum. Cras pellentesque, purus at suscipit euismod, elit nunc cursus nisi, ut venenatis metus sapien id velit. Sed lectus orci, pharetra non pulvinar vel, ullamcorper id lorem. Donec vulputate tincidunt ipsum, ut lacinia tortor sollicitudin id. Nunc nec nibh ut felis venenatis egestas. Proin risus mauris, eleifend eget interdum in, venenatis sed velit. Praesent sodales elit ut odio viverra posuere. Donec sapien lorem, molestie in egestas eget, vulputate sed orci. Aenean elit sapien, pellentesque vitae tempor sit amet, sagittis et ligula. Mauris aliquam sapien sit amet lacus ultrices rutrum. Curabitur nec dolor sed elit varius dignissim a a lacus. Aliquam ac convallis enim. 13 | 14 | Suspendisse orci massa, hendrerit sagittis lacinia consectetur, sagittis vitae purus. Aliquam id eros diam, eget elementum turpis. Nullam tellus magna, mollis in molestie id, venenatis rhoncus est. Proin id diam justo. Nunc tempus gravida justo at lobortis. Nam vitae venenatis nisi. Donec vel odio massa. Quisque interdum metus sit amet est iaculis tincidunt. Donec bibendum blandit purus, id semper orci aliquam quis. Nam tincidunt dolor eu felis ultricies tempor. Nulla non consectetur erat. 15 | 16 | Nunc faucibus lacus eget odio ultricies nec ullamcorper risus pharetra. Nunc nec consequat urna. Curabitur condimentum ante vitae erat tristique vitae gravida quam dapibus. Cras ac justo dui, at faucibus urna. Nunc tristique, velit id feugiat fermentum, dolor enim egestas erat, at vestibulum ante ipsum vel orci. Duis quis ante id justo vehicula eleifend sed et urna. Sed sapien tortor, rutrum id ultrices eu, tincidunt tincidunt mi. Etiam blandit, neque eget interdum dignissim, lacus ante facilisis dolor, non viverra dui lorem vitae nibh. Morbi volutpat augue eget nulla luctus eu aliquam sem facilisis. Pellentesque sollicitudin commodo dolor sit amet vestibulum. Nam dictum posuere quam, in tincidunt erat rutrum eu. 17 | 18 | Etiam nec turpis purus, at lacinia sem. In commodo lacinia euismod. Curabitur tincidunt congue leo, eget iaculis orci volutpat pharetra. Fusce dignissim lacus lacus. Integer consectetur lacus rutrum risus malesuada at consectetur erat rutrum. Sed magna ipsum, fringilla eget auctor non, fringilla nec massa. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum nec tortor id nisi luctus aliquam. Maecenas cursus tincidunt ornare. Nulla a vestibulum odio. Mauris malesuada commodo justo quis mattis. Suspendisse mauris ligula, placerat at egestas in, tincidunt quis nibh. Aliquam ullamcorper elit at augue cursus quis pellentesque purus viverra. 19 | 20 | Nulla ultricies justo ac nisi consectetur posuere. Donec ornare pharetra erat, nec facilisis dui cursus quis. Quisque porttitor porttitor orci, sed facilisis urna facilisis sed. Sed tincidunt adipiscing turpis et hendrerit. Cras posuere orci ut mauris ullamcorper vitae laoreet nisi luctus. In rutrum tristique augue. Nam eleifend dignissim dui. 21 | 22 | Donec viverra egestas tellus non viverra. Aenean est ante, egestas sed scelerisque quis, aliquet sed lacus. Praesent non mauris neque, et adipiscing ante. Vestibulum quis quam vitae ipsum aliquet blandit. Vivamus condimentum euismod orci, in tincidunt justo rutrum faucibus. Phasellus nec lorem arcu. Donec tortor dui, facilisis in rutrum sit amet, pulvinar vitae lacus. Nam sodales sem eu nunc scelerisque vitae ullamcorper dolor facilisis. Duis imperdiet nisi in magna tempor convallis. Fusce at metus augue. Quisque dictum tempus mauris, in mattis ligula dignissim ut. 23 | 24 | Proin sodales, mi at tincidunt ornare, mi dui sagittis velit, sed dictum risus orci eu erat. Sed nunc leo, congue sed rutrum eget, lobortis ac lectus. Etiam non arcu nulla. Vestibulum rutrum dolor pulvinar lorem posuere blandit. Sed quis sapien dui. Nunc sagittis erat commodo quam porta cursus in non erat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin a molestie neque. Aliquam iaculis lacus sed neque hendrerit at dignissim ligula imperdiet. Suspendisse venenatis, lorem at luctus scelerisque, sem purus pellentesque sapien, vitae ornare ipsum quam nec dui. Mauris neque est, interdum nec pulvinar eget, dapibus eleifend tellus. Fusce non lorem tortor. Nullam eget nunc quis felis aliquam consectetur. Aliquam tristique, turpis in feugiat blandit, lectus erat condimentum tortor, non egestas nisl sapien eget nibh. 25 | 26 | Aliquam elit turpis, faucibus et porta et, egestas nec nibh. Sed nisl est, pharetra a eleifend a, pretium ac eros. Sed leo eros, pulvinar vel faucibus dictum, aliquet ut quam. Maecenas et felis non ligula fringilla pretium fringilla sit amet ante. Nam varius imperdiet interdum. Ut non metus mauris, vel volutpat lorem. Nullam sagittis est quis lacus feugiat fringilla. Quisque orci lorem, semper ac accumsan vitae, blandit quis velit. Proin luctus sodales ultrices. Fusce mauris erat, facilisis ut consectetur at, fringilla feugiat orci. Aliquam a nisi a neque interdum suscipit id eget purus. Pellentesque tincidunt justo ut urna posuere non molestie quam auctor. 27 | -------------------------------------------------------------------------------- /utilities/jsdoc/fixtures/tutorials/Drive Car.md: -------------------------------------------------------------------------------- 1 | #Lorem ipsum dolor sit amet 2 | 3 | Curabitur est mi, fermentum lacinia tincidunt vitae, mattis sit amet neque. Quisque diam nisl, accumsan ac porta tincidunt, iaculis facilisis ipsum. Nulla facilisi. Aenean a metus tortor. Pellentesque congue, mauris vitae viverra varius, elit nunc dictum nisl, rhoncus ultrices nulla sapien at leo. Duis ultricies porttitor diam. Nulla facilisi. Nullam elementum, lorem eu imperdiet laoreet, est turpis sollicitudin velit, in porttitor justo dolor vel urna. Mauris in ante magna. Curabitur vitae lacus in magna mollis commodo. 4 | 5 | ##Fusce lacinia, mauris ac aliquam consequat 6 | Fusce molestie blandit velit, sit amet dictum eros pharetra vitae. In erat urna, condimentum ac feugiat id, rutrum et nisi. Cras ac velit lorem. Nulla facilisi. Maecenas dignissim nulla in turpis tempus sed rhoncus augue dapibus. Nulla feugiat, urna non sagittis laoreet, dolor metus rhoncus justo, sed semper ante lacus eget quam. Sed ac ligula magna. Sed tincidunt pulvinar neque in porta. Nullam quis lacus orci. Pellentesque ornare viverra lacus, id aliquam magna venenatis a. 7 | 8 | Sed id tristique lorem. Ut sodales turpis nec mauris gravida interdum. Cras pellentesque, purus at suscipit euismod, elit nunc cursus nisi, ut venenatis metus sapien id velit. Sed lectus orci, pharetra non pulvinar vel, ullamcorper id lorem. Donec vulputate tincidunt ipsum, ut lacinia tortor sollicitudin id. Nunc nec nibh ut felis venenatis egestas. Proin risus mauris, eleifend eget interdum in, venenatis sed velit. Praesent sodales elit ut odio viverra posuere. Donec sapien lorem, molestie in egestas eget, vulputate sed orci. Aenean elit sapien, pellentesque vitae tempor sit amet, sagittis et ligula. Mauris aliquam sapien sit amet lacus ultrices rutrum. Curabitur nec dolor sed elit varius dignissim a a lacus. Aliquam ac convallis enim. 9 | 10 | Suspendisse orci massa, hendrerit sagittis lacinia consectetur, sagittis vitae purus. Aliquam id eros diam, eget elementum turpis. Nullam tellus magna, mollis in molestie id, venenatis rhoncus est. Proin id diam justo. Nunc tempus gravida justo at lobortis. Nam vitae venenatis nisi. Donec vel odio massa. Quisque interdum metus sit amet est iaculis tincidunt. Donec bibendum blandit purus, id semper orci aliquam quis. Nam tincidunt dolor eu felis ultricies tempor. Nulla non consectetur erat. 11 | -------------------------------------------------------------------------------- /utilities/jsdoc/fixtures/tutorials/Fence Test.md: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur non libero tristique, interdum quam in, fermentum massa. Aenean vestibulum velit eu massa faucibus accumsan. Aenean tempus quam ornare ligula gravida adipiscing. Suspendisse vestibulum diam quis quam lacinia convallis. Nunc rhoncus a elit ut dictum. Maecenas porta mi et risus convallis commodo. In hac habitasse platea dictumst. Morbi placerat sem nec eleifend hendrerit. Donec hendrerit pulvinar tristique. Pellentesque at nunc blandit, fringilla elit nec, dignissim arcu. Quisque sit amet enim urna. Nunc adipiscing lacinia justo. Pellentesque euismod nisi id elit auctor porttitor. Phasellus rutrum viverra felis, ac cursus ante vulputate ut. Donec laoreet felis ac risus vulputate sodales. 2 | 3 | Mauris sit amet risus non ligula lacinia iaculis. Sed ornare tellus velit, vel elementum quam porttitor tempus. Duis vestibulum augue eu diam malesuada auctor. Maecenas dignissim odio ut elit fermentum, id mollis leo mattis. Phasellus posuere augue sed interdum vestibulum. Etiam ac pharetra est. Integer tortor ligula, pharetra ac nisi nec, faucibus laoreet dolor. Nunc vehicula, enim et cursus tincidunt, nulla purus mollis urna, vel ultricies nisl mi a risus. Vestibulum sed urna sodales, pretium nisi sed, pretium sapien. Vivamus et massa tincidunt, semper nibh nec, eleifend urna. Integer auctor, eros at pharetra blandit, erat nibh mattis turpis, rhoncus elementum nisi mi vitae purus. 4 | 5 | Quisque elementum sapien id neque volutpat cursus non mattis velit. 6 | 7 | 8 | ``` 9 | $mod : function ( qu, value ) { 10 | var operands = sys.flatten( qu.operands ); 11 | if ( operands.length !== 2 ) { 12 | throw new Error( "$mod requires two operands" ); 13 | } 14 | var mod = operands[0]; 15 | var rem = operands[1]; 16 | return value % mod === rem; 17 | }, 18 | 19 | ``` 20 | 21 | 22 | ``` 23 | {@lang bash} 24 | #!/bin/bash 25 | echo Please, enter your firstname and lastname 26 | read FN LN 27 | echo "Hi! $LN, $FN !" 28 | ``` 29 | 30 | ```bash 31 | #!/bin/bash 32 | echo Please, enter your firstname and lastname 33 | read FN LN 34 | echo "Hi! $LN, $FN !" 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /utilities/jsdoc/fixtures/utils/logger.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @fileOverview The logging system for papyrus is based on [http://pimterry.github.io/loglevel/](loglevel) and slightly decorated 4 | * @module utils/logger 5 | * @requires dcl 6 | * @requires loglevel 7 | */ 8 | 9 | var dcl = require( "dcl" ); 10 | var log = require( 'loglevel' ); 11 | 12 | /** 13 | * A logger class that you can mix into your classes to handle logging settings and state at an object level. 14 | * See {@link utils/logger} for the members of this class 15 | * 16 | * @exports utils/logger.Logger 17 | * @class 18 | * @see utils/logger 19 | */ 20 | var Logger = dcl( null, /** @lends utils/logger.Logger# */{ 21 | declaredClass : "utils/Logger", 22 | 23 | /** 24 | * Turn off all logging. If you log something, it will not error, but will not do anything either 25 | * and the cycles are minimal. 26 | * 27 | */ 28 | silent : function () { 29 | log.disableAll(); 30 | }, 31 | /** 32 | * Turns on all logging levels 33 | * 34 | */ 35 | all : function () { 36 | log.enableAll(); 37 | }, 38 | /** 39 | * Sets the logging level to one of `trace`, `debug`, `info`, `warn`, `error`. 40 | * @param {string} lvl The level to set it to. Can be one of `trace`, `debug`, `info`, `warn`, `error`. 41 | * 42 | */ 43 | level : function ( lvl ) { 44 | if ( lvl.toLowerCase() === "none" ) { 45 | log.disableAll(); 46 | } else { 47 | log.setLevel( lvl ); 48 | } 49 | }, 50 | /** 51 | * Log a `trace` call 52 | * @method 53 | * @param {string} The value to log 54 | */ 55 | trace : log.trace, 56 | /** 57 | * Log a `debug` call 58 | * @method 59 | * @param {string} The value to log 60 | */ 61 | debug : log.debug, 62 | /** 63 | * Log a `info` call 64 | * @method 65 | * @param {string} The value to log 66 | */ 67 | info : log.info, 68 | /** 69 | * Log a `warn` call 70 | * @method 71 | * @param {string} The value to log 72 | */ 73 | warn : log.warn, 74 | /** 75 | * Log a `error` call 76 | * @method 77 | * @param {string} The value to log 78 | */ 79 | error : log.error 80 | } ); 81 | 82 | module.exports = new Logger(); 83 | /** 84 | * The system global, cross-platform logger 85 | * @name utils/logger 86 | * @static 87 | * @type {utils/logger.Logger} 88 | */ 89 | module.exports.Logger = Logger; 90 | -------------------------------------------------------------------------------- /utilities/jsdoc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "daybrush-jsdoc-template", 3 | "version": "1.6.0", 4 | "description": "A clean, responsive documentation template theme for JSDoc 3 inspired by lodash and minami", 5 | "main": "publish.js", 6 | "scripts": { 7 | "test": "jsdoc -c fixtures/fixtures.conf.json", 8 | "sync": "browser-sync start -s ../fixtures-doc -f ../fixtures-doc --reload-delay 1000 --no-ui --no-notify", 9 | "watch": "watch-run -d 1000 -p tmpl/**,static/** \"npm run test\"" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/daybrush/daybrush-jsdoc-template.git" 14 | }, 15 | "devDependencies": { 16 | "jsdoc": "latest", 17 | "browser-sync": "latest", 18 | "watch-run": "latest" 19 | }, 20 | "author": "Daybrush ", 21 | "license": "Apache-2.0", 22 | "keywords": [ 23 | "jsdoc", 24 | "template", 25 | "tsdoc", 26 | "javascript", 27 | "typescript" 28 | ], 29 | "dependencies": { 30 | "@daybrush/utils": "^0.10.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /utilities/jsdoc/static/scripts/custom.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iPzard/mkvtoolnix-batch-tool/33821381e38cf89a0702cd8276f86ccf0dd3189f/utilities/jsdoc/static/scripts/custom.js -------------------------------------------------------------------------------- /utilities/jsdoc/static/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /utilities/jsdoc/static/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /utilities/jsdoc/static/scripts/search.js: -------------------------------------------------------------------------------- 1 | 2 | (function () { 3 | var nav = document.querySelector("nav"); 4 | var searchBar = nav.querySelector(".search"); 5 | var input = searchBar.querySelector("input"); 6 | // var submit = searchBar.querySelector("button"); 7 | var groups = Array.prototype.slice.call(document.querySelectorAll("nav>ul .parent")).map(function (group) { 8 | var items = Array.prototype.slice.call(group.querySelectorAll("a")); 9 | var strings = items.map(function (a) { 10 | return a.innerText.toLowerCase(); 11 | }); 12 | 13 | return {el: group, items: items, strings, strings}; 14 | }); 15 | input.addEventListener("keyup", function (e) { 16 | var value = input.value.toLowerCase(); 17 | 18 | if (value) { 19 | utils.addClass(nav, "searching"); 20 | } else { 21 | utils.removeClass(nav, "searching"); 22 | return; 23 | } 24 | groups.forEach(function (group) { 25 | var isSearch = false; 26 | var items = group.items; 27 | 28 | group.strings.forEach(function (v, i) { 29 | var item = items[i]; 30 | if (utils.hasClass(item.parentNode, "parent")) { 31 | item = item.parentNode; 32 | } 33 | if (v.indexOf(value) > -1) { 34 | utils.addClass(item, "targeting"); 35 | isSearch = true; 36 | } else { 37 | utils.removeClass(item, "targeting"); 38 | } 39 | }); 40 | if (isSearch) { 41 | utils.addClass(group.el, "module-targeting"); 42 | } else { 43 | utils.removeClass(group.el, "module-targeting"); 44 | } 45 | }); 46 | }); 47 | })(); -------------------------------------------------------------------------------- /utilities/jsdoc/static/scripts/utils.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 Daybrush 3 | @name: @daybrush/utils 4 | license: MIT 5 | author: Daybrush 6 | repository: https://github.com/daybrush/utils 7 | @version 0.4.0 8 | */ 9 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.utils=t()}(this,function(){"use strict";var u="rgb",c="rgba",f="hsl",l="hsla",e=[u,c,f,l],t="function",n="object",r="string",i="undefined",a=typeof window!==i,o=["webkit","ms","moz","o"],s=function(e){if(typeof document===i)return"";var t=(document.body||document.documentElement).style,n=o.length;if(typeof t[e]!==i)return e;for(var r=0;rul>li:after { 14 | content: ""; 15 | position: absolute; 16 | right: 10px; 17 | top: 0; 18 | bottom: 0; 19 | width: 0; 20 | height: 0; 21 | margin: auto 0px; 22 | border-top: 7px solid #ccc; 23 | border-left: 6px solid transparent; 24 | border-right: 6px solid transparent; 25 | } 26 | nav li h4, nav li ul { 27 | display: none; 28 | } 29 | 30 | .name.typescript { 31 | background: #374E79; 32 | font-size: 14px; 33 | } 34 | .name.typescript .signature { 35 | color: #21de60; 36 | } 37 | .ts-params.typescript table .last { 38 | display: none; 39 | } 40 | table.params th, table.params tr td , table.params tr td.type{ 41 | word-break: break-word; 42 | white-space: normal; 43 | } 44 | 45 | nav .search { 46 | position: relative; 47 | margin: 0px 10px; 48 | border: 3px solid #333; 49 | height: 43px; 50 | } 51 | nav .search .input-area { 52 | position: absolute; 53 | left: 0; 54 | top: 0; 55 | right: 35px; 56 | height: 35px; 57 | } 58 | nav .search input { 59 | position: relative; 60 | width: 100%; 61 | height: 100%; 62 | border: 0; 63 | padding: 0; 64 | text-indent: 10px; 65 | font-weight: bold; 66 | font-size: 14px; 67 | outline: none; 68 | } 69 | nav .search button { 70 | position: absolute; 71 | top: 0; 72 | right: 0px; 73 | width: 35px; 74 | height: 35px; 75 | border: 0; 76 | padding: 0; 77 | outline: none; 78 | cursor: pointer; 79 | } 80 | nav .search button:before { 81 | position: absolute; 82 | content: ""; 83 | width: 18px; 84 | height: 18px; 85 | top: 7px; 86 | left: 7px; 87 | border: 3px solid #333; 88 | border-radius: 50%; 89 | box-sizing: border-box; 90 | } 91 | nav .search button:after { 92 | position: absolute; 93 | content: ""; 94 | width: 3px; 95 | height: 11px; 96 | top: 21px; 97 | left: 18px; 98 | background: #333; 99 | transform-origin: 50% 0%; 100 | -ms-transform-origin: 50% 0%; 101 | -webkit-transform-origin: 50% 0%; 102 | transform: rotate(-45deg); 103 | -ms-transform: rotate(-45deg); 104 | -webkit-transform: rotate(-45deg); 105 | } 106 | 107 | nav.searching li:after { 108 | display: none!important; 109 | } 110 | nav.searching li h4, nav.searching li ul { 111 | display: block!important; 112 | } 113 | 114 | nav.searching .parent { 115 | display: none; 116 | } 117 | nav.searching .parent ul li a { 118 | display: none; 119 | } 120 | 121 | nav.searching .parent.module-targeting { 122 | display: block; 123 | } 124 | nav.searching .parent.module-targeting ul li a { 125 | display: none; 126 | } 127 | nav.searching .parent.module-targeting ul li a.targeting { 128 | display: block; 129 | } 130 | nav.searching .parent.targeting ul li a { 131 | display: block; 132 | } 133 | 134 | nav>h2.custom>a { 135 | margin:12px 10px; 136 | } -------------------------------------------------------------------------------- /utilities/jsdoc/static/styles/prettify.css: -------------------------------------------------------------------------------- 1 | .pln { 2 | color: #ddd; 3 | } 4 | 5 | /* string content */ 6 | .str { 7 | color: #61ce3c; 8 | } 9 | 10 | /* a keyword */ 11 | .kwd { 12 | color: #fbde2d; 13 | } 14 | 15 | /* a comment */ 16 | .com { 17 | color: #aeaeae; 18 | } 19 | 20 | /* a type name */ 21 | .typ { 22 | color: #8da6ce; 23 | } 24 | 25 | /* a literal value */ 26 | .lit { 27 | color: #fbde2d; 28 | } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #ddd; 33 | } 34 | 35 | /* lisp open bracket */ 36 | .opn { 37 | color: #000000; 38 | } 39 | 40 | /* lisp close bracket */ 41 | .clo { 42 | color: #000000; 43 | } 44 | 45 | /* a markup tag name */ 46 | .tag { 47 | color: #8da6ce; 48 | } 49 | 50 | /* a markup attribute name */ 51 | .atn { 52 | color: #fbde2d; 53 | } 54 | 55 | /* a markup attribute value */ 56 | .atv { 57 | color: #ddd; 58 | } 59 | 60 | /* a declaration */ 61 | .dec { 62 | color: #EF5050; 63 | } 64 | 65 | /* a variable name */ 66 | .var { 67 | color: #c82829; 68 | } 69 | 70 | /* a function name */ 71 | .fun { 72 | color: #4271ae; 73 | } 74 | 75 | /* Specify class=linenums on a pre to get line numbering */ 76 | ol.linenums { 77 | margin-top: 0; 78 | margin-bottom: 0; 79 | } 80 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/augments.tmpl: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 |
    8 |
  • 9 |
10 | 11 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/container.tmpl: -------------------------------------------------------------------------------- 1 | 0) return; 7 | ?> 8 | 9 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 |
24 | 25 |

26 | 27 | 28 | 29 | 30 | 31 |

32 | 33 |
34 | 35 | 36 | 37 | 38 |
39 | 40 | 41 | 42 |
43 | 44 |
45 |
46 | 47 | 48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
61 | 62 | 63 | 64 |

Example 1? 's':'' ?>

65 | 66 | 67 | 68 |
69 | 70 | 71 |

Extends

72 | 73 | 74 | 75 | 76 | 77 |

Requires

78 | 79 |
    80 |
  • 81 |
82 | 83 | 84 | 88 |

Classes

89 | 90 |
91 |
92 |
93 |
94 | 95 | 96 | 100 |

Mixins

101 | 102 |
103 |
104 |
105 |
106 | 107 | 108 | 112 |

Namespaces

113 | 114 |
115 |
116 |
117 |
118 | 119 | 120 | 131 |

Members

132 | 133 | 134 | 135 | 136 | 137 | 138 | 142 |

Methods

143 | 144 | 145 | 146 | 147 | 148 | 149 | 153 |

Type Definitions

154 | 155 | 158 | 159 | 163 | 164 | 167 | 168 | 169 | 173 |

Events

174 | 175 | 176 | 177 | 178 | 179 |
180 | 181 |
182 | 183 | 184 | 185 | 186 | 187 | 206 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/details.tmpl: -------------------------------------------------------------------------------- 1 | " + data.defaultvalue + ""; 13 | defaultObjectClass = ' class="object-value"'; 14 | } 15 | ?> 16 | 17 |
18 | 19 | 20 |
Source:
21 |
  • 22 | , 23 |
24 | 25 | 26 | 27 |
Version:
28 |
29 | 30 | 31 | 32 |
Since:
33 |
34 | 35 | 36 | 37 |
Inherited From:
38 |
  • 39 | 40 |
41 | 42 | 43 | 44 |
Overrides:
45 |
  • 46 | 47 |
48 | 49 | 50 | 51 |
Implementations:
52 |
    53 | 54 |
  • 55 | 56 |
57 | 58 | 59 | 60 |
Implements:
61 |
    62 | 63 |
  • 64 | 65 |
66 | 67 | 68 | 69 |
Mixes In:
70 | 71 |
    72 | 73 |
  • 74 | 75 |
76 | 77 | 78 | 79 |
Deprecated:
  • Yes
83 | 84 | 85 | 86 |
Author:
87 |
88 |
    89 |
  • 90 |
91 |
92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
License:
101 |
102 | 103 | 104 | 105 |
Default Value:
106 |
    107 | > 108 |
109 | 110 | 111 | 112 |
Tutorials:
113 |
114 |
    115 |
  • 116 |
117 |
118 | 119 | 120 | 121 |
See:
122 |
123 |
    124 |
  • 125 |
126 |
127 | 128 | 129 | 130 |
To Do:
131 |
132 |
    133 |
  • 134 |
135 |
136 | 137 |
138 | 139 | 143 | 144 |
Properties:
145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/example.tmpl: -------------------------------------------------------------------------------- 1 | 2 |
3 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/examples.tmpl: -------------------------------------------------------------------------------- 1 | 8 |

9 | 10 |
11 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/exceptions.tmpl: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |
7 |
8 | 9 |
10 |
11 |
12 |
13 |
14 |
15 | Type 16 |
17 |
18 | 19 |
20 |
21 |
22 |
23 |
24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
32 | 33 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/layout.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <?js= title ?> - Documentation 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 32 | 33 |
34 | 35 |

36 | 37 | 38 | 39 |
40 | 41 |
42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/mainpage.tmpl: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 |
8 |
9 |
10 | 11 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/members.tmpl: -------------------------------------------------------------------------------- 1 | 5 |

6 | 7 | 8 |

9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 | 20 |
Type:
21 |
    22 |
  • 23 | 24 |
  • 25 |
26 | 27 | 28 | 29 |
Fires:
30 |
    31 |
  • 32 |
33 | 34 | 35 | 36 |
Example 1? 's':'' ?>
37 | 38 | 39 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/method.tmpl: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 |

Constructor

8 | 9 | 10 |

12 | 13 | 14 |

15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 |
24 | 25 | 26 | 27 |
Extends:
28 | 29 | 30 | 31 | 32 |
Type:
33 |
    34 |
  • 35 | 36 |
  • 37 |
38 | 39 | 40 | 41 |
This:
42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 | 56 |

57 | () 58 | → {} 59 |

60 |
61 | 62 |
63 | 67 | 68 | 69 |
Example 1? 's':'' ?>
70 | 71 | 72 | 73 | 74 | 75 |
Requires:
76 |
    77 |
  • 78 |
79 | 80 | 81 | 82 |
Fires:
83 |
    84 |
  • 85 |
86 | 87 | 88 | 89 |
Listens to Events:
90 |
    91 |
  • 92 |
93 | 94 | 95 | 96 |
Listeners of This Event:
97 |
    98 |
  • 99 |
100 | 101 | 102 | 103 |
Throws:
104 | 1) { ?>
    106 |
  • 107 |
110 | 111 | 113 | 114 | 115 |
Returns:
116 | 1) { ?>
    118 |
  • 119 |
122 | 123 | 125 | 126 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/params.tmpl: -------------------------------------------------------------------------------- 1 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 91 | 92 | 93 | 103 | 104 | 105 | 106 | 111 | 112 | 113 | 117 | 118 | 119 | 120 | 121 |
NameTypeAttributesDefaultDescription
? 87 | 88 | 89 | 90 | 94 | 95 | 96 | <nullable>
97 | 98 | 99 | 100 | <repeatable>
101 | 102 |
107 | 108 | 109 | 110 | 114 |
Properties
115 | 116 |
122 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/properties.tmpl: -------------------------------------------------------------------------------- 1 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 80 | 81 | 82 | 87 | 88 | 89 | 90 | 95 | 96 | 97 | 100 | 101 | 102 | 103 | 104 |
NameTypeAttributesDefaultDescription
? 76 | 77 | 78 | 79 | 83 | 84 | <nullable>
85 | 86 |
91 | 92 | 93 | 94 | 98 |
Properties
99 |
105 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/returns.tmpl: -------------------------------------------------------------------------------- 1 | 5 |
6 | 7 |
8 | 9 | 10 | 11 |
12 |
13 | Type 14 |
15 |
16 | 17 |
18 |
19 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/source.tmpl: -------------------------------------------------------------------------------- 1 | 4 |
5 |
6 |
7 |
8 |
-------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/tutorial.tmpl: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 0) { ?> 5 |
    8 |
  • 9 |
10 | 11 | 12 |

13 |
14 | 15 |
16 | 17 |
18 | 19 |
20 | -------------------------------------------------------------------------------- /utilities/jsdoc/tmpl/type.tmpl: -------------------------------------------------------------------------------- 1 | 5 | 6 | | 7 | -------------------------------------------------------------------------------- /utilities/loaders/react/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /utilities/loaders/react/assets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | min-height: 100vh; 3 | text-align: center; 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | align-items: center; 8 | font-size: calc(10px + 2vmin); 9 | overflow: hidden; 10 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 11 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 12 | sans-serif; 13 | -webkit-font-smoothing: antialiased; 14 | -moz-osx-font-smoothing: grayscale; 15 | background-color: #252525; 16 | } 17 | 18 | .app-logo { 19 | height: 48vmin; 20 | pointer-events: none; 21 | animation-name: rotate; 22 | animation-duration: 15s; 23 | animation-iteration-count: infinite; 24 | animation-timing-function: linear; 25 | } 26 | 27 | .loading-header { 28 | margin-top: -10px; 29 | color: #6adefc; 30 | } 31 | 32 | @keyframes rotate { 33 | from { 34 | -webkit-transform: rotate(0deg); 35 | } 36 | to { 37 | -webkit-transform: rotate(360deg); 38 | } 39 | } -------------------------------------------------------------------------------- /utilities/loaders/react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Loading Screen 6 | 7 | 8 | 9 | 10 |

Starting React
Development Server

11 | 12 | 13 | -------------------------------------------------------------------------------- /utilities/loaders/redux/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /utilities/loaders/redux/assets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | min-height: 100vh; 3 | text-align: center; 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | align-items: center; 8 | font-size: calc(10px + 2vmin); 9 | overflow: hidden; 10 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 11 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 12 | sans-serif; 13 | -webkit-font-smoothing: antialiased; 14 | -moz-osx-font-smoothing: grayscale; 15 | } 16 | 17 | .app-logo { 18 | height: 40vmin; 19 | pointer-events: none; 20 | } 21 | 22 | .loading-header { 23 | color: rgb(112, 76, 182); 24 | } 25 | 26 | @media (prefers-reduced-motion: no-preference) { 27 | .app-logo { 28 | animation: app-logo-float infinite 3s ease-in-out; 29 | } 30 | } 31 | 32 | @keyframes app-logo-float { 33 | 0% { 34 | transform: translateY(0); 35 | } 36 | 50% { 37 | transform: translateY(10px) 38 | } 39 | 100% { 40 | transform: translateY(0px) 41 | } 42 | } -------------------------------------------------------------------------------- /utilities/loaders/redux/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Loading Screen 6 | 7 | 8 | 9 | 10 |

Starting React
Development Server

11 | 12 | 13 | -------------------------------------------------------------------------------- /utilities/msi/images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iPzard/mkvtoolnix-batch-tool/33821381e38cf89a0702cd8276f86ccf0dd3189f/utilities/msi/images/background.png -------------------------------------------------------------------------------- /utilities/msi/images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iPzard/mkvtoolnix-batch-tool/33821381e38cf89a0702cd8276f86ccf0dd3189f/utilities/msi/images/banner.png -------------------------------------------------------------------------------- /utilities/msi/images/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iPzard/mkvtoolnix-batch-tool/33821381e38cf89a0702cd8276f86ccf0dd3189f/utilities/msi/images/icon.ico --------------------------------------------------------------------------------