diff --git a/CHANGELOG.md b/CHANGELOG.md index 71d947e5..395b1182 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +### 2.12.0 +- [#211](https://github.com/brentvollebregt/auto-py-to-exe/pull/211): Added Traditional Chinese translations +- [#218](https://github.com/brentvollebregt/auto-py-to-exe/issues/218): Added build directory override argument (`--build-directory-override`) +- [#221](https://github.com/brentvollebregt/auto-py-to-exe/issues/221): Added an overlay spinner to hide content until the UI is initialised + ### 2.11.0 - [#205](https://github.com/brentvollebregt/auto-py-to-exe/issues/205): Added support for PyInstaller 4.6 and its new options - Dropped support for Python 3.5 diff --git a/README.md b/README.md index 07f4317b..f7562368 100644 --- a/README.md +++ b/README.md @@ -68,13 +68,15 @@ Now to run the application, execute ```python -m auto_py_to_exe```. A Chrome win ### Arguments Usage: `auto-py-to-exe [-nc] [-c [CONFIG]] [-o [PATH]] [filename]` -| Argument | Type | Description | -|--------------------------------|------------|-----------------------------------------------------------------------------------------------------------------| -| filename | positional | Pre-fill the "Script Location" field in the UI. | -| -nc, --no-chrome | optional | Open the UI using the default browser (which may be Chrome). Will not try to find Chrome. | -| -nu, --no-ui | optional | Don't try to open the UI in a browser and simply print out the address that the application can be accessed at. | -| -c [CONFIG], --config [CONFIG] | optional | Provide a configuration file (json) to pre-fill the UI. These can be generated in the settings tab. | -| -o [PATH], --output-dir [PATH] | optional | Set the default output directory. This can still be changed in the ui. | +| Argument | Type | Description | +| ------------------------------------------------------------ | ------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| filename | positional/optional | Pre-fill the "Script Location" field in the UI. | +| -nc, --no-chrome | optional | Open the UI using the default browser (which may be Chrome). Will not try to find Chrome. | +| -nu, --no-ui | optional | Don't try to open the UI in a browser and simply print out the address that the application can be accessed at. | +| -c [CONFIG], --config [CONFIG] | optional | Provide a configuration file (json) to pre-fill the UI. These can be generated in the settings tab. | +| -o [PATH], --output-dir [PATH] | optional | Set the default output directory. This can still be changed in the ui. | +| -bdo [FOLDER_PATH], --build-directory-override [FOLDER_PATH] | optional | Override the default build directory. Useful if you need to whitelist a folder to stop your antivirus from removing files. | + > If you are running this package locally, you will need to call ```python -m auto_py_to_exe``` instead of ```auto-py-to-exe``` diff --git a/auto_py_to_exe/__init__.py b/auto_py_to_exe/__init__.py index fb7a749a..0b288f83 100644 --- a/auto_py_to_exe/__init__.py +++ b/auto_py_to_exe/__init__.py @@ -1 +1 @@ -__version__ = '2.11.0' +__version__ = '2.12.0' diff --git a/auto_py_to_exe/__main__.py b/auto_py_to_exe/__main__.py index 9a116983..d6244476 100644 --- a/auto_py_to_exe/__main__.py +++ b/auto_py_to_exe/__main__.py @@ -10,19 +10,23 @@ from . import ui -def start_ui(logging_level): +def start_ui(logging_level, build_directory_override): """ Open the interface """ # Suppress the global logger to only show error+ to the console logging.getLogger().handlers[0].setLevel(logging_level) - # Setup a temporary folder to build in - config.temporary_directory = tempfile.mkdtemp() + # Setup the build folder + if build_directory_override is None: + config.temporary_directory = tempfile.mkdtemp() + else: + config.temporary_directory = build_directory_override # Start UI ui.start(config.ui_open_mode) - # Remove temporary folder to clean up from builds - shutil.rmtree(config.temporary_directory) + # Remove build folder to clean up from builds (if we created it) + if build_directory_override is None: + shutil.rmtree(config.temporary_directory) def run(): @@ -64,6 +68,13 @@ def run(): help="the directory to put output in", default='output' ) + parser.add_argument( + "-bdo", + "--build-directory-override", + nargs='?', + help="a directory for build files (overrides the default)", + default=None + ) parser.add_argument( "--logging-level", nargs='?', @@ -91,12 +102,16 @@ def run(): else: config.ui_open_mode = config.UIOpenMode.CHROME + # Validate --build-directory-override exists if supplied + if (args.build_directory_override is not None) and (not os.path.isdir(args.build_directory_override)): + raise ValueError("--build-directory-override must be a directory") + # If the user has asked for the version, print it, otherwise run the application if args.version: print('auto-py-to-exe ' + __version__) else: logging_level = getattr(logging, args.logging_level) - start_ui(logging_level) + start_ui(logging_level, args.build_directory_override) if __name__ == '__main__': diff --git a/auto_py_to_exe/web/css/main.css b/auto_py_to_exe/web/css/main.css index ecbdc922..8e49a491 100644 --- a/auto_py_to_exe/web/css/main.css +++ b/auto_py_to_exe/web/css/main.css @@ -264,3 +264,64 @@ div[id*="section"] .content { #open-output-folder-button.show { display: block; } + +/* Loading spinner (from https://projects.lukehaas.me/css-loaders/) */ + +.loading-spinner-wrapper { + display: flex; + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100vh; + align-items: center; + justify-content: center; + background: rgb(0 0 0 / 75%); +} + +.loading-label { + color: white; +} + +.loading-spinner, +.loading-spinner:after { + border-radius: 50%; + width: 8em; + height: 8em; +} +.loading-spinner { + margin: 60px auto; + font-size: 10px; + position: relative; + text-indent: -9999em; + border-top: 1.1em solid rgba(256,256,256, 0.2); + border-right: 1.1em solid rgba(256,256,256, 0.2); + border-bottom: 1.1em solid rgba(256,256,256, 0.2); + border-left: 1.1em solid #FFFFFF; + -webkit-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); + -webkit-animation: load8 1.1s infinite linear; + animation: load8 1.1s infinite linear; +} +@-webkit-keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + diff --git a/auto_py_to_exe/web/index.html b/auto_py_to_exe/web/index.html index adb0aa4b..703cf0b5 100644 --- a/auto_py_to_exe/web/index.html +++ b/auto_py_to_exe/web/index.html @@ -232,6 +232,14 @@

Output

+ + +
+
+
+ Initializing... +
+
diff --git a/auto_py_to_exe/web/js/i18n.js b/auto_py_to_exe/web/js/i18n.js index e8374f4c..6cb9d28a 100644 --- a/auto_py_to_exe/web/js/i18n.js +++ b/auto_py_to_exe/web/js/i18n.js @@ -3,155 +3,191 @@ const translationMap = { title: { scriptLocation: { en: 'Script Location', - zh: '脚本位置' + zh: '脚本位置', + zh_tw: '腳本位置' }, oneFile: { en: 'Onefile', - zh: '单文件' + zh: '单文件', + zh_tw: '單檔案' }, consoleWindow: { en: 'Console Window', - zh: '控制台窗口' + zh: '控制台窗口', + zh_tw: '控制台視窗' }, icon: { en: 'Icon', - zh: '图标' + zh: '图标', + zh_tw: '圖示' }, additionalFiles: { en: 'Additional Files', - zh: '附加文件' + zh: '附加文件', + zh_tw: '附加檔案' }, advanced: { en: 'Advanced', - zh: '高级' + zh: '高级', + zh_tw: '進階' }, settings: { en: 'Settings', - zh: '设置' + zh: '设置', + zh_tw: '設定' }, currentCommand: { en: 'Current Command', - zh: '当前命令' + zh: '当前命令', + zh_tw: '當前命令' }, output: { en: 'Output', - zh: '输出' + zh: '输出', + zh_tw: '輸出' }, specificOptions: { en: 'auto-py-to-exe Specific Options', - zh: 'auto-py-to-exe 特定的选项' + zh: 'auto-py-to-exe 特定的选项', + zh_tw: 'auto-py-to-exe 特定的選項' }, outputDirectory: { en: 'Output Directory', - zh: '输出路径' + zh: '输出路径', + zh_tw: '輸出路徑' }, increaseRecursionLimit: { en: 'Increase Recursion Limit', - zh: '增加递归限制' + zh: '增加递归限制', + zh_tw: '增加遞歸限制' }, manuallyProvideOptions: { en: 'Manually Provide Options', - zh: '手动提供选项' + zh: '手动提供选项', + zh_tw: '手動提供選項' }, manualArgumentInput: { en: 'Manual Argument Input', - zh: '手动参数输入' + zh: '手动参数输入', + zh_tw: '手動參數輸入' }, configuration: { en: 'Configuration', - zh: '配置' + zh: '配置', + zh_tw: '配置' } }, button: { browse: { en: 'Browse', - zh: '浏览' + zh: '浏览', + zh_tw: '瀏覽' }, oneDirectory: { en: 'One Directory', - zh: '单目录' + zh: '单目录', + zh_tw: '單目錄' }, oneFile: { en: 'One File', - zh: '单文件' + zh: '单文件', + zh_tw: '單檔案' }, consoleBased: { en: 'Console Based', - zh: '基于控制台的' + zh: '基于控制台的', + zh_tw: '基於控制台' }, windowBased: { en: 'Window Based (hide the console)', - zh: '基于窗口的 (隐藏控制台)' + zh: '基于窗口的 (隐藏控制台)', + zh_tw: '基於視窗 (隱藏控制台)' }, addFiles: { en: 'Add Files', - zh: '添加文件' + zh: '添加文件', + zh_tw: '新增檔案' }, addFolder: { en: 'Add Folder', - zh: '添加目录' + zh: '添加目录', + zh_tw: '新增目錄' }, addBlank: { en: 'Add Blank', - zh: '添加空白' + zh: '添加空白', + zh_tw: '新增空白', }, importConfig: { en: 'Import Config From JSON File', - zh: '从JSON文件导入配置' + zh: '从JSON文件导入配置', + zh_tw: '從 JSON 檔案導入配置' }, exportConfig: { en: 'Export Config To JSON File', - zh: '将配置导出到JSON文件' + zh: '将配置导出到JSON文件', + zh_tw: '將配置導出到 JSON 檔案' }, convert: { en: 'Convert .py to .exe', - zh: '将.PY转换为.EXE' + zh: '将.PY转换为.EXE', + zh_tw: '將.PY 轉換為 .EXE' }, openOutputFolder: { en: 'Open Output Folder', - zh: '打开输出目录' + zh: '打开输出目录', + zh_tw: '打開輸出目錄' }, enable: { en: 'Enable', - zh: '开启' + zh: '开启', + zh_tw: '開啟' } }, links: { helpPost: { en: 'Help Post', - zh: '帮助帖子' + zh: '帮助帖子', + zh_tw: '幫助文章' } }, placeholders: { pathToFile: { en: 'Path to file', - zh: '文件路径' + zh: '文件路径', + zh_tw: '檔案路徑' }, icoFile: { en: '.ico file', - zh: '图标路径' + zh: '图标路径', + zh_tw: '圖示路徑' }, directory: { en: 'DIRECTORY', - zh: '目录' + zh: '目录', + zh_tw: '目錄' }, arguments: { en: 'ARGUMENTS', - zh: '参数' + zh: '参数', + zh_tw: '參數' }, }, helpText: { outputDirectory: { en: 'The directory to put the output in. Will be created if it doesn\'t exist', - zh: '用于放置输出的目录。如果不存在,将创建该目录' + zh: '用于放置输出的目录。如果不存在,将创建该目录', + zh_tw: '用於放置輸出的目錄如果不存在,將自動創建該目錄' }, increaseRecursionLimit: { en: 'Having this enabled will set the recursion limit to 5000 using sys.setrecursionlimit(5000).', - zh: '启用此功能将使用sys.setrecursionlimit(5000)将递归限制设置为5000。' + zh: '启用此功能将使用sys.setrecursionlimit(5000)将递归限制设置为5000。', + zh_tw: '啟用此功能將使用 sys.setrecursionlimit(5000)將遞歸限制設置為5000。' }, manualArgumentInput: { en: 'Inject raw text into the generated command.', - zh: '将原始文本插入到生成的命令中。' + zh: '将原始文本插入到生成的命令中。', + zh_tw: '將原始文字插入到產生的命令中。' } }, notes: { @@ -161,11 +197,15 @@ const translationMap = { 'and update your code to work with PyInstaller.', zh: '使用单文件模式的附加文件时要小心;\n'+ 'read this\n' + - '并更新您的代码以使用PyInstaller。' + '并更新您的代码以使用PyInstaller。', + zh_tw: '使用單檔案模式的附加檔案時要小心;\n'+ + 'read this\n' + + '並更新您的代碼以使用 PyInstaller。' }, rootDirectory: { en: 'If you want to put files in the root directory, put a period (.) in the destination.', - zh: '如果要将文件放到根目录中,请在目标目录中输入句点(.)。' + zh: '如果要将文件放到根目录中,请在目标目录中输入句点(.)。', + zh_tw: '如果要將檔案放到根目錄中,請在目標目錄中輸入句點(.)。' }, somethingWrongWithOutput: { en: 'Something wrong with your exe? Read\n' + @@ -177,7 +217,12 @@ const translationMap = { '\n' + ' 这篇文章是关于如何修复常见问题的\n' + '\n' + - '寻找可能的解决方案。' + '寻找可能的解决方案。', + zh_tw: '您的 exe 有問題? 請閱讀' + + '\n' + + ' 這篇文章是關於如何修復常見的問題\n' + + '\n' + + '尋找可能的解決方案。' } } }, @@ -187,83 +232,103 @@ const translationMap = { // For the usage of constants.js:advancedSections generalOptions: { en: 'General Options', - zh: '常规选项' + zh: '常规选项', + zh_tw: '一般選項' }, whatToBundleWhereToSearch: { en: 'What to bundle, where to search', - zh: '捆绑什么,搜索哪里' + zh: '捆绑什么,搜索哪里', + zh_tw: '怎樣捆綁,哪裡搜尋' }, howToGenerate: { en: 'How to generate', - zh: '如何生成' + zh: '如何生成', + zh_tw: '如何產生' }, windowsAndMacOsXSpecificOptions: { en: 'Windows And Mac Os X Specific Options', + zh_tw: 'Windows 和 Mac Os X 特定選項' }, windowsSpecificOptions: { en: 'Windows specific options', - zh: 'Windows特定选项' + zh: 'Windows特定选项', + zh_tw: 'Windows 特定選項' + }, windowsSideBySideAssemblySearchingOptions: { en: 'Windows Side-by-side Assembly searching options (advanced)', - zh: '窗口并排汇编搜索选项(高级)' + zh: '窗口并排汇编搜索选项(高级)', + zh_tw: '視窗並排彙編搜尋選項(進階)' }, macOsxSpecificOptions: { en: 'Mac OS X specific options', - zh: 'Mac OS X特定选项' + zh: 'Mac OS X特定选项', + zh_tw: 'Mac OS X 特定選項' }, rarelyUsedSpecialOptions: { en: 'Rarely used special options', - zh: '很少使用的特殊选项' + zh: '很少使用的特殊选项', + zh_tw: '很少使用的特殊選項' }, other: { en: 'Other', - zh: '其他' + zh: '其他', + zh_tw: '其它' }, }, button: { // For the usage of interface.js_createSubSectionInAdvanced browseForFile: { en: 'Browse for File', - zh: '浏览文件' + zh: '浏览文件', + zh_tw: '瀏覽檔案' }, browseForFolder: { en: 'Browse for Folder', - zh: '浏览文件夹' + zh: '浏览文件夹', + zh_tw: '瀏覽檔案夾' }, enable: { en: 'Enable', - zh: '开启' + zh: '开启', + zh_tw: '開啟' }, disable: { en: 'Disable', - zh: '关掉' + zh: '关掉', + zh_tw: '關閉' }, converting: { en: 'Converting...', - zh: '转换中······' + zh: '转换中······', + zh_tw: '轉換中······' }, clearOutput: { en: 'Clear Output', - zh: '清除输出f' + zh: '清除输出f', + zh_tw: '清除輸出' }, }, modal: { configModalTitle: { en: 'Override current configuration?', - zh: '覆盖当前配置?' + zh: '覆盖当前配置?', + zh_tw: '覆蓋當前配置?' }, configModalDescription: { en: 'All previously inserted values will be erased.', - zh: '所有先前插入的值将被删除。' + zh: '所有先前插入的值将被删除。', + zh_tw: '所有先前插入的值將被刪除。' }, configModalConfirmButton: { en: 'Confirm', - zh: '确认' + zh: '确认', + zh_tw: '確認' }, configModalCancelButton: { en: 'Cancel', - zh: '取消' + zh: '取消', + zh_tw: '取消' } } }, @@ -272,11 +337,13 @@ const translationMap = { alert: { noScriptsLocationProvided: { en: 'You have not provided your scripts location.\nPlease enter this at the top of the page.', - zh: '您尚未提供脚本位置。\n请在页面顶部输入。' + zh: '您尚未提供脚本位置。\n请在页面顶部输入。', + zh_tw: '您尚未提供腳本位置。\n請在頁面頂部輸入。' }, overwritePreviousOutput: { en: 'This action will overwrite a previous output in the output folder.\nContinue?', - zh: '此操作将覆盖输出文件夹中以前的输出。\n是否继续?' + zh: '此操作将覆盖输出文件夹中以前的输出。\n是否继续?', + zh_tw: '此操作將覆蓋輸出檔案夾中以前的輸出。\n是否繼續?' } }, } @@ -377,5 +444,9 @@ const supportedLanguages = [ name: 'Chinese Simplified (简体中文)', code: 'zh', }, + { + name: 'Chinese Traditional (繁體中文)', + code: 'zh_tw', + }, ]; let currentLanguage = _checkLanguageIsSupportedOrDefault(_getLanguage()); // Keeps track of the current language diff --git a/auto_py_to_exe/web/js/initialise.js b/auto_py_to_exe/web/js/initialise.js index 330008b9..ccb19335 100644 --- a/auto_py_to_exe/web/js/initialise.js +++ b/auto_py_to_exe/web/js/initialise.js @@ -60,7 +60,9 @@ const buildUpOptions = (providedOptions) => { // Get initialisation data from the server and setup the ui window.addEventListener("load", async () => { // Get initialisation data from Python + console.log("Getting initialisation data"); const initialisationData = await eel.initialise()(); + console.log("Received initialisation data"); options = buildUpOptions(initialisationData.options); pathSeparator = initialisationData.pathSeparator; @@ -99,4 +101,7 @@ window.addEventListener("load", async () => { // If the server stops, close the UI window.eel._websocket.addEventListener('close', e => window.close()); + + console.log("Application initialised"); + document.getElementById('spinner-root').style.display = 'none'; });