From ec5068e31ce92cc42186df6768cd59f7d0dd471f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Nov 2025 13:43:56 -0800 Subject: [PATCH] ... --- .bh.ps1 | 8 +++-- ebook2audiobook.cmd | 34 +++++++++++++------ ebook2audiobook.sh | 4 +++ lib/functions.py | 80 +++++++++++++++++++++++++++++++++++++-------- lib/models.py | 2 +- 5 files changed, 100 insertions(+), 28 deletions(-) diff --git a/.bh.ps1 b/.bh.ps1 index 69ac7679..f2d1ed99 100644 --- a/.bh.ps1 +++ b/.bh.ps1 @@ -1,17 +1,19 @@ param( [string]$HostName = "127.0.0.1", [int]$Port = 7860, - [int]$Timeout = 60 + [int]$Timeout = 90 ) + for ($i = 1; $i -le $Timeout; $i++) { try { $tcp = [System.Net.Sockets.TcpClient]::new() $tcp.Connect($HostName, $Port) $tcp.Close() Start-Process "http://${HostName}:$Port/" - break + exit 0 } catch { Start-Sleep -Seconds 1 } -} \ No newline at end of file +} +exit 0 \ No newline at end of file diff --git a/ebook2audiobook.cmd b/ebook2audiobook.cmd index 03f7e8a4..c83249ef 100755 --- a/ebook2audiobook.cmd +++ b/ebook2audiobook.cmd @@ -6,10 +6,14 @@ set "ARGS=%*" set "NATIVE=native" set "FULL_DOCKER=full_docker" set "SCRIPT_MODE=%NATIVE%" -set "APP_NAME=ebook2audiobook" set "SCRIPT_DIR=%~dp0" -set "RUN_SCRIPT=ebook2audiobook.cmd" -set "ICON_PATH=%SCRIPT_DIR%tools\icons\windows\appIcon.ico" +if "%SCRIPT_DIR:~-1%"=="\" set "SCRIPT_DIR=%SCRIPT_DIR:~0,-1%" +set "APP_NAME=ebook2audiobook" +set /p APP_VERSION=<"%SCRIPT_DIR%\VERSION.txt" +set "APP_FILE=%APP_NAME%.cmd" +set "TEST_HOST=127.0.0.1" +set "TEST_PORT=7860" +set "ICON_PATH=%SCRIPT_DIR%\tools\icons\windows\appIcon.ico" set "STARTMENU_DIR=%APPDATA%\Microsoft\Windows\Start Menu\Programs\%APP_NAME%" set "STARTMENU_LNK=%STARTMENU_DIR%\%APP_NAME%.lnk" set "DESKTOP_LNK=%USERPROFILE%\Desktop\%APP_NAME%.lnk" @@ -35,6 +39,7 @@ set "TESSDATA_PREFIX=%SCRIPT_DIR%\models\tessdata" set "NODE_PATH=%SCOOP_HOME%\apps\nodejs\current" set "PATH=%SCOOP_SHIMS%;%SCOOP_APPS%;%CONDA_PATH%;%NODE_PATH%;%PATH%" 2>&1 >nul set "INSTALLED_LOG=%SCRIPT_DIR%\.installed" +set "UNINSTALLER=%SCRIPT_DIR%\uninstall.cmd" set "HELP_FOUND=%ARGS:--help=%" set "HEADLESS_FOUND=%ARGS:--headless=%" @@ -253,13 +258,22 @@ goto :dispatch exit /b :make_shortcut +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\%APP_NAME%" /v "DisplayName" /d "%APP_NAME%" /f >nul 2>&1 +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\%APP_NAME%" /v "DisplayVersion" /d "%APP_VERSION%" /f >nul 2>&1 +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\%APP_NAME%" /v "Publisher" /d "ebook2audiobook Team" /f >nul 2>&1 +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\%APP_NAME%" /v "InstallLocation" /d "%SCRIPT_DIR%" /f >nul 2>&1 +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\%APP_NAME%" /v "UninstallString" /d "\"%UNINSTALLER%\"" /f >nul 2>&1 +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\%APP_NAME%" /v "DisplayIcon" /d "%ICON_PATH%" /f >nul 2>&1 +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\%APP_NAME%" /v "NoModify" /t REG_DWORD /d 1 /f >nul 2>&1 +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\%APP_NAME%" /v "NoRepair" /t REG_DWORD /d 1 /f >nul 2>&1 powershell -NoLogo -NoProfile -Command ^ - "$s=(New-Object -ComObject WScript.Shell).CreateShortcut('%~1');" ^ - "$s.TargetPath='cmd.exe';" ^ - "$s.Arguments='/k cd ""%SCRIPT_DIR%"" && %RUN_SCRIPT%';" ^ - "$s.WorkingDirectory='%SCRIPT_DIR%';" ^ - "$s.IconLocation='%ICON_PATH%';" ^ - "$s.Save()" + "$s = New-Object -ComObject WScript.Shell; " ^ + "$shortcut = $s.CreateShortcut('%~1'); " ^ + "$shortcut.TargetPath = 'cmd.exe'; " ^ + "$shortcut.Arguments = '/k \"cd /d \"%SCRIPT_DIR%\" && \"%APP_FILE%\"\"'; " ^ + "$shortcut.WorkingDirectory = '%SCRIPT_DIR%'; " ^ + "$shortcut.IconLocation = '%ICON_PATH%'; " ^ + "$shortcut.Save()" exit /b :build_gui @@ -269,7 +283,7 @@ if not "%HEADLESS_FOUND%"=="%ARGS%" ( call :make_shortcut "%STARTMENU_LNK%" call :make_shortcut "%DESKTOP_LNK%" ) - start "E2A" powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "%~dp0.bh.ps1" + start "E2A" powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "%~dp0.bh.ps1" -HostName "%TEST_HOST%" -Port %TEST_PORT% ) exit /b diff --git a/ebook2audiobook.sh b/ebook2audiobook.sh index 35b84ead..c6ca8266 100755 --- a/ebook2audiobook.sh +++ b/ebook2audiobook.sh @@ -49,11 +49,13 @@ NATIVE="native" FULL_DOCKER="full_docker" SCRIPT_MODE="$NATIVE" APP_NAME="ebook2audiobook" +APP_VERSION=$(<"$SCRIPT_DIR/VERSION.txt") WGET=$(which wget 2>/dev/null) REQUIRED_PROGRAMS=("curl" "pkg-config" "calibre" "ffmpeg" "nodejs" "espeak-ng" "rust" "sox" "tesseract") PYTHON_ENV="python_env" CURRENT_ENV="" INSTALLED_LOG="$SCRIPT_DIR/.installed" +UNINSTALLER="$SCRIPT_DIR/uninstall.sh" if [[ "$OSTYPE" != "linux"* && "$OSTYPE" != "darwin"* ]]; then echo "Error: OS $OSTYPE unsupported." @@ -637,4 +639,6 @@ EOF fi fi +exit 0 +exit 0 exit 0 \ No newline at end of file diff --git a/lib/functions.py b/lib/functions.py index be85f00b..6ef1c2b0 100644 --- a/lib/functions.py +++ b/lib/functions.py @@ -2418,7 +2418,7 @@ def build_interface(args:dict)->gr.Blocks: is_gui_process = args['is_gui_process'] is_gui_shared = args['share'] title = 'Ebook2Audiobook' - gr_glass_mask_msg = 'Initialization, please wait...' + gr_glassmask_msg = 'Initialization, please wait...' ebook_src = None language_options = [ ( @@ -2518,6 +2518,8 @@ def build_interface(args:dict)->gr.Blocks: justify-content: center !important; font-size: 1.2rem !important; color: #ffffff !important; + text-align: center !important; + border: none !important; opacity: 1; pointer-events: all !important; } @@ -3046,7 +3048,7 @@ def build_interface(args:dict)->gr.Blocks: gr_confirm_blocks_no_btn = gr.Button(elem_id='gr_confirm_blocks_no_btn', elem_classes=['hide-elem'], value='', variant='secondary', visible=True, scale=0, min_width=30) gr_modal = gr.HTML(visible=False) - gr_glass_mask = gr.HTML(gr_glass_mask_msg, elem_id='gr_glass_mask', elem_classes=['gr-glass-mask']) + gr_glassmask = gr.HTML(gr_glassmask_msg, elem_id='gr_glassmask', elem_classes=['gr-glass-mask']) gr_confirm_deletion_field_hidden = gr.Textbox(elem_id='confirm_hidden', visible=False) gr_confirm_deletion_yes_btn = gr.Button(elem_id='gr_confirm_deletion_yes_btn', elem_classes=['hide-elem'], value='', variant='secondary', visible=True, scale=0, size='sm', min_width=0) gr_confirm_deletion_no_btn = gr.Button(elem_id='gr_confirm_deletion_no_btn', elem_classes=['hide-elem'], value='', variant='secondary', visible=True, scale=0, size='sm', min_width=0) @@ -3246,8 +3248,8 @@ def build_interface(args:dict)->gr.Blocks: alert_exception(error, id) return gr.update(value=0), gr.update(value=None), gr.update(value=None) - def update_gr_glass_mask(str:str=gr_glass_mask_msg, attr:list=['gr-glass-mask'])->dict: - return gr.update(value=str, elem_id='gr_glass_mask', elem_classes=attr) + def update_gr_glassmask(str:str=gr_glassmask_msg, attr:list=['gr-glass-mask'])->dict: + return gr.update(value=str, elem_id='gr_glassmask', elem_classes=attr) def change_convert_btn(upload_file:str|None=None, upload_file_mode:str|None=None, custom_model_file:str|None=None, session:DictProxy=None)->dict: try: @@ -3941,7 +3943,7 @@ def build_interface(args:dict)->gr.Blocks: session['status'] = None if not context_tracker.start_session(session['id']): error = "Your session is already active.
If it's not the case please close your browser and relaunch it." - return gr.update(), gr.update(), gr.update(value=''), update_gr_glass_mask(str=error) + return gr.update(), gr.update(), gr.update(value=''), update_gr_glassmask(str=error) else: active_sessions.add(req.session_hash) session[req.session_hash] = req.session_hash @@ -4358,7 +4360,7 @@ def build_interface(args:dict)->gr.Blocks: gr_restore_session.change( fn=change_gr_restore_session, inputs=[gr_restore_session, gr_state_update], - outputs=[gr_save_session, gr_state_update, gr_session, gr_glass_mask] + outputs=[gr_save_session, gr_state_update, gr_session, gr_glassmask] ).then( fn=restore_interface, inputs=[gr_session], @@ -4374,9 +4376,9 @@ def build_interface(args:dict)->gr.Blocks: gr_group_audiobook_list, gr_audiobook_player, gr_timer ] ).then( - fn=lambda session: update_gr_glass_mask(attr=['gr-glass-mask', 'hide']) if session else gr.update(), + fn=lambda session: update_gr_glassmask(attr=['gr-glass-mask', 'hide']) if session else gr.update(), inputs=[gr_session], - outputs=[gr_glass_mask] + outputs=[gr_glassmask] ).then( fn=None, inputs=None, @@ -4428,6 +4430,8 @@ def build_interface(args:dict)->gr.Blocks: js=r''' ()=>{ try{ + const bc = new BroadcastChannel("E2A-channel"); + const tab_id = crypto.randomUUID(); let gr_root = (window.gradioApp && window.gradioApp()) || document; let gr_checkboxes; let gr_radios; @@ -4438,9 +4442,10 @@ def build_interface(args:dict)->gr.Blocks: let gr_playback_time; let gr_progress; let gr_voice_play; + let tabs_opened = false; let init_elements_timeout; let init_audiobook_player_timeout; - let audioFilter = ""; + let audio_filter = ""; let cues = []; if(typeof window.onElementAvailable !== "function"){ window.onElementAvailable = (selector, callback, { root = (window.gradioApp && window.gradioApp()) || document, once = false } = {})=> { @@ -4672,7 +4677,7 @@ def build_interface(args:dict)->gr.Blocks: } gr_audiobook_player.addEventListener("loadeddata", ()=>{ gr_audiobook_player.style.transition = "filter 1s ease"; - gr_audiobook_player.style.filter = audioFilter; + gr_audiobook_player.style.filter = audio_filter; gr_audiobook_player.currentTime = parseFloat(window.session_storage.playback_time); gr_audiobook_player.volume = window.session_storage.playback_volume; }); @@ -4701,16 +4706,16 @@ def build_interface(args:dict)->gr.Blocks: let osTheme; if(theme){ if(theme == "dark"){ - audioFilter = "invert(1) hue-rotate(180deg)"; + audio_filter = "invert(1) hue-rotate(180deg)"; } }else{ osTheme = window.matchMedia?.("(prefers-color-scheme: dark)").matches; if(osTheme){ - audioFilter = "invert(1) hue-rotate(180deg)"; + audio_filter = "invert(1) hue-rotate(180deg)"; } } gr_audiobook_player.style.transition = "filter 1s ease"; - gr_audiobook_player.style.filter = audioFilter; + gr_audiobook_player.style.filter = audio_filter; gr_audiobook_player.volume = window.session_storage.playback_volume; return true; } @@ -4841,7 +4846,40 @@ def build_interface(args:dict)->gr.Blocks: return [s.slice(0, idx).trim(), s.slice(idx + 1).trim()]; } } + if(typeof(show_glassmask) !== "function"){ + function show_glassmask(msg){ + let glassmask = document.querySelector("#gr_glassmask"); + if(!glassmask){ + glassmask = document.createElement("div"); + glassmask.id = "gr_glassmask"; + document.body.appendChild(glassmask); + } + glassmask.className = "gr-glass-mask"; + glassmask.innerHTML = `${msg}`; + } + } ////////////////////// + bc.onmessage = (event)=>{ + try{ + const msg = event.data; + if(!msg || msg.senderId === tab_id){ + return; + } + switch (msg.type){ + case "check-existing": + bc.postMessage({ type: "already-open", senderId: tab_id }); + break; + case "already-open": + tabs_opened = true; + break; + case "new-tab-opened": + show_glassmask(msg.text); + break; + } + }catch(e){ + console.warn("bc.onmessage error:", e); + } + }; window.addEventListener("beforeunload", ()=>{ try{ const newStorage = JSON.parse(localStorage.getItem("data") || "{}"); @@ -4859,7 +4897,7 @@ def build_interface(args:dict)->gr.Blocks: const currentStorage = localStorage.getItem("data"); if(currentStorage){ window.session_storage = JSON.parse(currentStorage); - window.session_storage.tab_id = "tab-" + performance.now().toString(36) + "-" + Math.random().toString(36).substring(2, 10); + window.session_storage.tab_id = tab_id; if(window.session_storage.playback_volume === 0){ window.session_storage.playback_volume = 1.0; } @@ -4874,6 +4912,20 @@ def build_interface(args:dict)->gr.Blocks: window.onElementAvailable("#gr_audiobook_player audio", (el)=>{ window.init_audiobook_player(); }, {once: false}); + try{ + bc.postMessage({ type: "check-existing", senderId: tab_id }); + setTimeout(()=>{ + if(tabs_opened){ + bc.postMessage({ + type: "new-tab-opened", + text: "Session expired.
You can close this window", + senderId: tab_id + }); + } + }, 250); + }catch(e){ + console.warn("bc.postMessage error:", e); + } return window.session_storage; }catch(e){ console.warn("gr_raed_data js error:", e); diff --git a/lib/models.py b/lib/models.py index 42b75d3a..7062d254 100644 --- a/lib/models.py +++ b/lib/models.py @@ -148,7 +148,7 @@ default_engine_settings = { "samplerate": 16000, "files": ['config.json', 'model_file.pth'], "voices": {"Machinella-5": "female-en-5", "ElectroMale-2": "male-en-2", 'Machinella-4': 'female-pt-4\n', 'ElectroMale-3': 'male-pt-3\n'}, - "rating": {"VRAM": 0, "CPU": 5, "RAM": 1, "Realism": 2} + "rating": {"VRAM": 1, "CPU": 5, "RAM": 1, "Realism": 2} } } models = {