diff --git a/README.md b/README.md
index 9509dee4..0e535e87 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
[^1]: External EPG doesn't work with **local** m3u accounts.
# Downloads
[](https://github.com/sebdelsol/sfvip-all/releases/download/Sfvip.All.1.4.12.42/Install.Sfvip.All.1.4.12.42.x64.exe)
-_by MS Defender • 1.1.24020.9 • 1.407.627.0_
+_by MS Defender • 1.1.24020.9 • 1.407.703.0_
[](https://github.com/sebdelsol/sfvip-all/releases/download/Sfvip.All.1.4.12.42/Install.Sfvip.All.1.4.12.42.x86.exe)
_by MS Defender • 1.1.24020.9 • 1.407.627.0_
@@ -43,7 +43,7 @@ You'll find them in the app folder:
# Build
-[![version](https://custom-icon-badges.demolab.com/badge/Build%201.4.12.42-informational?logo=github)](/build_config.py#L27)
+[![version](https://custom-icon-badges.demolab.com/badge/Build%201.4.12.43-informational?logo=github)](/build_config.py#L27)
[![Sloc](https://custom-icon-badges.demolab.com/badge/Sloc%208.5k-informational?logo=file-code)](https://api.codetabs.com/v1/loc/?github=sebdelsol/sfvip-all)
[![Ruff](https://custom-icon-badges.demolab.com/badge/Ruff-informational?logo=ruff-color)](https://docs.astral.sh/ruff/)
[![Python](https://custom-icon-badges.demolab.com/badge/Python%203.11.8-linen?logo=python-color)](https://www.python.org/downloads/release/python-3118/)
diff --git a/build/changelog.md b/build/changelog.md
index fc89277e..6a6b0631 100644
--- a/build/changelog.md
+++ b/build/changelog.md
@@ -1,3 +1,8 @@
+## 1.4.12.43
+* Option to modify _Sfvip All_ install directory.
+* When updating the Install directory won't be asked again
+and _Sfvip All_ will be automatically relaunched.
+
## 1.4.12.42
* Fix Minor bugs.
* Better translations.
diff --git a/build_config.py b/build_config.py
index 62efbadd..dcdf3807 100644
--- a/build_config.py
+++ b/build_config.py
@@ -24,7 +24,7 @@ class Build:
main: ClassVar = "sfvip_all.py"
company: ClassVar = "sebdelsol"
name: ClassVar = "Sfvip All"
- version: ClassVar = "1.4.12.42"
+ version: ClassVar = "1.4.12.43"
dir: ClassVar = "build"
enable_console: ClassVar = False
logs_dir: ClassVar = "../logs"
diff --git a/dev/tools/nsis/template.nsi b/dev/tools/nsis/template.nsi
index 7c7506c6..df7111eb 100644
--- a/dev/tools/nsis/template.nsi
+++ b/dev/tools/nsis/template.nsi
@@ -5,6 +5,7 @@ VIAddVersionKey "ProductName" "{{name}}"
VIAddVersionKey "CompanyName" "{{company}}"
!include "MUI2.nsh" ; modern UI
+!include "FileFunc.nsh" ; GetParameters and GetOptions
Name "{{name}} {{version}} {{bitness}}"
OutFile "{{installer}}"
RequestExecutionLevel user
@@ -18,25 +19,47 @@ ShowUninstDetails hide
!define MUI_ICON "{{dist}}\{{ico}}"
!define MUI_UNICON "{{dist}}\{{ico}}"
+; -------------
+; directory page
+; -------------
+!define MUI_PAGE_CUSTOMFUNCTION_PRE "SetInstDir"
+!insertmacro MUI_PAGE_DIRECTORY
+
; -------------
; install pages
; -------------
+!define MUI_PAGE_CUSTOMFUNCTION_PRE "UninstallOldVersionIfNeeded"
Page Custom AppRunningPage AppRunningPageFinalize
!insertmacro MUI_PAGE_INSTFILES
+; -------------
+; finish pages
+; -------------
{% if finish_page %}
Function RunApp
SetOutPath "$InstDir\{{dist}}" ; exe working directory
Exec "$InstDir\{{dist}}\{{name}}.exe"
FunctionEnd
+Function AbortFinishPage
+ ; Abort if /AUTORUN=yes
+ ${GetParameters} $0
+ ${GetOptions} $0 "/AUTORUN=" $1
+ ClearErrors
+ ${If} $1 == "yes"
+ Call RunApp
+ Abort
+ ${Endif}
+FunctionEnd
+
+!define MUI_PAGE_CUSTOMFUNCTION_PRE "AbortFinishPage"
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_FUNCTION "RunApp"
!insertmacro MUI_PAGE_FINISH
{% endif %}
; ---------------
-; uninstall pages
+; uninstall page
; ---------------
UninstPage Custom un.AppRunningPage un.AppRunningPageFinalize
!insertmacro MUI_UNPAGE_INSTFILES
@@ -56,7 +79,6 @@ LangString retry ${LANG_{{lang.upper}}} "{{lang.retry}}"
{% endfor %}
; Cmd argument /LANG= to force the language (case insensitive)
-!include "FileFunc.nsh" ; GetParameters and GetOptions
!include "StrFunc.nsh" ; StrCase
${Using:StrFunc} StrCase
@@ -194,4 +216,38 @@ Section "Uninstall"
{% endif %}
Delete "$InstDir\uninstall.exe"
Delete "$SMPROGRAMS\{{name}} {{bitness}}.lnk"
-SectionEnd
\ No newline at end of file
+SectionEnd
+
+; --------------
+; Set install directory if in the registry
+; --------------
+Function SetInstDir
+ ; check in the registry for already installed version
+ ReadRegStr $0 HKCU "${UNINSTALL_KEY}" "InstallLocation"
+ ${If} ${Errors}
+ ClearErrors
+ ${Else}
+ StrCpy $InstDir $0
+ ${Endif}
+ ; no directory page if /AUTOINSTDIR=yes
+ ${GetParameters} $0
+ ${GetOptions} $0 "/AUTOINSTDIR=" $1
+ ClearErrors
+ ${If} $1 == "yes"
+ Abort
+ ${Endif}
+FunctionEnd
+
+; --------------
+; Uninstall version stored in the registry if different from instdir
+; --------------
+Function UninstallOldVersionIfNeeded
+ ReadRegStr $0 HKCU "${UNINSTALL_KEY}" "InstallLocation"
+ ${If} ${Errors}
+ ClearErrors
+ ${ElseIf} $InstDir != $0
+ ${If} ${FileExists} "$0\uninstall.exe"
+ ExecWait "$0\uninstall.exe /S"
+ ${EndIf}
+ ${Endif}
+FunctionEnd
diff --git a/src/sfvip/app_updater.py b/src/sfvip/app_updater.py
index 1d064dee..1cf8d3fe 100644
--- a/src/sfvip/app_updater.py
+++ b/src/sfvip/app_updater.py
@@ -51,7 +51,7 @@ def _update_exe(self, update: AppUpdate) -> Path:
def _install(self, update_exe: Path) -> None:
# replace current process with the update exe
def launch() -> None:
- update_exe_args = update_exe.name, f"/LANG={LOC.language}"
+ update_exe_args = update_exe.name, f"/LANG={LOC.language}", "/AUTOINSTDIR=yes", "/AUTORUN=yes"
logger.info("Launch %s %s", *update_exe_args)
os.execl(update_exe, *update_exe_args)
diff --git a/src/sfvip/ui/infos.py b/src/sfvip/ui/infos.py
index 830d3e1a..572cae25 100644
--- a/src/sfvip/ui/infos.py
+++ b/src/sfvip/ui/infos.py
@@ -145,9 +145,12 @@ def _app_version_tooltip(app_info: AppInfo) -> Style:
lines.extend(("", f"{prefix}{text}:"))
case "*":
lines.append(f"{tab}- {text}")
+ case _:
+ line = f"{first} {text}"
+ raise ValueError
except ValueError:
if line:
- lines.append(f"{tab}{line}")
+ lines.append(f"{tab} {line}")
except (PermissionError, FileNotFoundError, OSError):
pass