NSIS improvements (#1692)

* Much better, but still broken

It crashes with two custom pages after one another. (So when the service should be installed).

* Fixed the problems and finished the NSIS installer.

Also ignored some of the artifacts.

* Added changes to CI for setup building.

Consolidate building and fixed git error.

Small CI fixes.

Move UX repo to SourcesDirectory

Fix stupid checkout <> clone error.

Fix typo in PowerShell command.

Artifact publish tasks can not have wildcards.
This commit is contained in:
Erwin de Haan 2019-09-09 23:40:51 +02:00 committed by Anthony Lavado
parent e6a1407786
commit 2f2010ce59
13 changed files with 646 additions and 291 deletions

View File

@ -30,28 +30,6 @@ jobs:
submodules: true submodules: true
persistCredentials: false persistCredentials: false
- task: DotNetCoreCLI@2
displayName: Restore
inputs:
command: restore
projects: '$(RestoreBuildProjects)'
enabled: false
- task: DotNetCoreCLI@2
displayName: Build
inputs:
projects: '$(RestoreBuildProjects)'
arguments: '--configuration $(BuildConfiguration)'
enabled: false
- task: DotNetCoreCLI@2
displayName: Test
inputs:
command: test
projects: '$(RestoreBuildProjects)'
arguments: '--configuration $(BuildConfiguration)'
enabled: false
- task: DotNetCoreCLI@2 - task: DotNetCoreCLI@2
displayName: Publish displayName: Publish
inputs: inputs:
@ -96,6 +74,56 @@ jobs:
targetPath: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Common.dll' targetPath: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Common.dll'
artifactName: 'Jellyfin.Common' artifactName: 'Jellyfin.Common'
- job: main_build_win
displayName: Main Build Windows
pool:
vmImage: windows-latest
strategy:
matrix:
release:
BuildConfiguration: Release
maxParallel: 2
steps:
- checkout: self
clean: true
submodules: true
persistCredentials: false
- task: CmdLine@2
displayName: Clone the UX repository
inputs:
script: git clone --depth=1 https://github.com/jellyfin/jellyfin-ux $(Agent.TempDirectory)\jellyfin-ux
- task: PowerShell@2
displayName: Build the NSIS Installer
inputs:
targetType: 'filePath' # Optional. Options: filePath, inline
filePath: ./deployment/windows/build-jellyfin.ps1 # Required when targetType == FilePath
arguments: -InstallFFMPEG -InstallNSSM -MakeNSIS -UXLocation $(Agent.TempDirectory)\jellyfin-ux -InstallLocation $(build.artifactstagingdirectory)
#script: '# Write your PowerShell commands here.Write-Host Hello World' # Required when targetType == Inline
errorActionPreference: 'stop' # Optional. Options: stop, continue, silentlyContinue
#failOnStderr: false # Optional
#ignoreLASTEXITCODE: false # Optional
#pwsh: false # Optional
workingDirectory: $(Build.SourcesDirectory) # Optional
- task: CopyFiles@2
displayName: Copy the NSIS Installer to the artifact directory
inputs:
sourceFolder: $(Build.SourcesDirectory)/deployment/windows/ # Optional
contents: 'jellyfin*.exe'
targetFolder: $(System.ArtifactsDirectory)/setup
cleanTargetFolder: true # Optional
overWrite: true # Optional
flattenFolders: true # Optional
- task: PublishPipelineArtifact@0
displayName: 'Publish Setup Artifact'
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
inputs:
targetPath: '$(build.artifactstagingdirectory)/setup'
artifactName: 'Jellyfin Server Setup'
- job: dotnet_compat - job: dotnet_compat
displayName: Compatibility Check displayName: Compatibility Check
pool: pool:

4
.gitignore vendored
View File

@ -264,3 +264,7 @@ ci/
# Doxygen # Doxygen
doc/ doc/
# Deployment artifacts
dist
*.exe

View File

@ -1,10 +1,13 @@
[CmdletBinding()] [CmdletBinding()]
param( param(
[switch]$MakeNSIS, [switch]$MakeNSIS,
[switch]$InstallNSIS,
[switch]$InstallFFMPEG, [switch]$InstallFFMPEG,
[switch]$InstallNSSM, [switch]$InstallNSSM,
[switch]$SkipJellyfinBuild,
[switch]$GenerateZip, [switch]$GenerateZip,
[string]$InstallLocation = "$Env:AppData/Jellyfin-Server/", [string]$InstallLocation = "./dist/jellyfin-win-nsis",
[string]$UXLocation = "../jellyfin-ux",
[ValidateSet('Debug','Release')][string]$BuildType = 'Release', [ValidateSet('Debug','Release')][string]$BuildType = 'Release',
[ValidateSet('Quiet','Minimal', 'Normal')][string]$DotNetVerbosity = 'Minimal', [ValidateSet('Quiet','Minimal', 'Normal')][string]$DotNetVerbosity = 'Minimal',
[ValidateSet('win','win7', 'win8','win81','win10')][string]$WindowsVersion = 'win', [ValidateSet('win','win7', 'win8','win81','win10')][string]$WindowsVersion = 'win',
@ -17,6 +20,10 @@ if(($PSVersionTable.PSEdition -eq 'Core') -and (-not $IsWindows)){
}else{ }else{
$TempDir = $env:Temp $TempDir = $env:Temp
} }
#Create staging dir
New-Item -ItemType Directory -Force -Path $InstallLocation
$ResolvedInstallLocation = Resolve-Path $InstallLocation
$ResolvedUXLocation = Resolve-Path $UXLocation
function Build-JellyFin { function Build-JellyFin {
if(($Architecture -eq 'arm64') -and ($WindowsVersion -ne 'win10')){ if(($Architecture -eq 'arm64') -and ($WindowsVersion -ne 'win10')){
@ -28,14 +35,14 @@ function Build-JellyFin {
exit exit
} }
Write-Verbose "windowsversion-Architecture: $windowsversion-$Architecture" Write-Verbose "windowsversion-Architecture: $windowsversion-$Architecture"
Write-Verbose "InstallLocation: $InstallLocation" Write-Verbose "InstallLocation: $ResolvedInstallLocation"
Write-Verbose "DotNetVerbosity: $DotNetVerbosity" Write-Verbose "DotNetVerbosity: $DotNetVerbosity"
dotnet publish -c $BuildType -r `"$windowsversion-$Architecture`" MediaBrowser.sln -o $InstallLocation -v $DotNetVerbosity dotnet publish --self-contained -c $BuildType --output $ResolvedInstallLocation -v $DotNetVerbosity -p:GenerateDocumentationFile=false -p:DebugSymbols=false -p:DebugType=none --runtime `"$windowsversion-$Architecture`" Jellyfin.Server
} }
function Install-FFMPEG { function Install-FFMPEG {
param( param(
[string]$InstallLocation, [string]$ResolvedInstallLocation,
[string]$Architecture [string]$Architecture
) )
Write-Verbose "Checking Architecture" Write-Verbose "Checking Architecture"
@ -44,31 +51,31 @@ function Install-FFMPEG {
Write-Warning "FFMPEG will not be installed" Write-Warning "FFMPEG will not be installed"
}elseif($Architecture -eq 'x64'){ }elseif($Architecture -eq 'x64'){
Write-Verbose "Downloading 64 bit FFMPEG" Write-Verbose "Downloading 64 bit FFMPEG"
Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-4.0.2-win64-static.zip -UseBasicParsing -OutFile "$tempdir/fmmpeg.zip" | Write-Verbose Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win64/shared/ffmpeg-4.0.2-win64-shared.zip -UseBasicParsing -OutFile "$tempdir/ffmpeg.zip" | Write-Verbose
}else{ }else{
Write-Verbose "Downloading 32 bit FFMPEG" Write-Verbose "Downloading 32 bit FFMPEG"
Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-4.0.2-win32-static.zip -UseBasicParsing -OutFile "$tempdir/fmmpeg.zip" | Write-Verbose Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win32/shared/ffmpeg-4.0.2-win32-shared.zip -UseBasicParsing -OutFile "$tempdir/ffmpeg.zip" | Write-Verbose
} }
Expand-Archive "$tempdir/fmmpeg.zip" -DestinationPath "$tempdir/ffmpeg/" | Write-Verbose Expand-Archive "$tempdir/ffmpeg.zip" -DestinationPath "$tempdir/ffmpeg/" -Force | Write-Verbose
if($Architecture -eq 'x64'){ if($Architecture -eq 'x64'){
Write-Verbose "Copying Binaries to Jellyfin location" Write-Verbose "Copying Binaries to Jellyfin location"
Get-ChildItem "$tempdir/ffmpeg/ffmpeg-4.0.2-win64-static/bin" | ForEach-Object { Get-ChildItem "$tempdir/ffmpeg/ffmpeg-4.0.2-win64-shared/bin" | ForEach-Object {
Copy-Item $_.FullName -Destination $installLocation | Write-Verbose Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
} }
}else{ }else{
Write-Verbose "Copying Binaries to Jellyfin location" Write-Verbose "Copying Binaries to Jellyfin location"
Get-ChildItem "$tempdir/ffmpeg/ffmpeg-4.0.2-win32-static/bin" | ForEach-Object { Get-ChildItem "$tempdir/ffmpeg/ffmpeg-4.0.2-win32-shared/bin" | ForEach-Object {
Copy-Item $_.FullName -Destination $installLocation | Write-Verbose Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
} }
} }
Remove-Item "$tempdir/ffmpeg/" -Recurse -Force -ErrorAction Continue | Write-Verbose Remove-Item "$tempdir/ffmpeg/" -Recurse -Force -ErrorAction Continue | Write-Verbose
Remove-Item "$tempdir/fmmpeg.zip" -Force -ErrorAction Continue | Write-Verbose Remove-Item "$tempdir/ffmpeg.zip" -Force -ErrorAction Continue | Write-Verbose
} }
function Install-NSSM { function Install-NSSM {
param( param(
[string]$InstallLocation, [string]$ResolvedInstallLocation,
[string]$Architecture [string]$Architecture
) )
Write-Verbose "Checking Architecture" Write-Verbose "Checking Architecture"
@ -81,7 +88,7 @@ function Install-NSSM {
Invoke-WebRequest -Uri https://nssm.cc/ci/nssm-2.24-101-g897c7ad.zip -UseBasicParsing -OutFile "$tempdir/nssm.zip" | Write-Verbose Invoke-WebRequest -Uri https://nssm.cc/ci/nssm-2.24-101-g897c7ad.zip -UseBasicParsing -OutFile "$tempdir/nssm.zip" | Write-Verbose
} }
Expand-Archive "$tempdir/nssm.zip" -DestinationPath "$tempdir/nssm/" | Write-Verbose Expand-Archive "$tempdir/nssm.zip" -DestinationPath "$tempdir/nssm/" -Force | Write-Verbose
if($Architecture -eq 'x64'){ if($Architecture -eq 'x64'){
Write-Verbose "Copying Binaries to Jellyfin location" Write-Verbose "Copying Binaries to Jellyfin location"
Get-ChildItem "$tempdir/nssm/nssm-2.24-101-g897c7ad/win64" | ForEach-Object { Get-ChildItem "$tempdir/nssm/nssm-2.24-101-g897c7ad/win64" | ForEach-Object {
@ -99,40 +106,59 @@ function Install-NSSM {
function Make-NSIS { function Make-NSIS {
param( param(
[string]$InstallLocation [string]$ResolvedInstallLocation
) )
Write-Verbose "Downloading NSIS"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $env:InstallLocation = $ResolvedInstallLocation
Invoke-WebRequest -Uri https://nchc.dl.sourceforge.net/project/nsis/NSIS%203/3.04/nsis-3.04.zip -UseBasicParsing -OutFile "$tempdir/nsis.zip" | Write-Verbose if($InstallNSIS.IsPresent -or ($InstallNSIS -eq $true)){
& "$tempdir/nsis/nsis-3.04/makensis.exe" /D$Architecture /DUXPATH=$ResolvedUXLocation ".\deployment\windows\jellyfin.nsi"
} else {
& "makensis" /D$Architecture /DUXPATH=$ResolvedUXLocation ".\deployment\windows\jellyfin.nsi"
}
Copy-Item .\deployment\windows\jellyfin_*.exe $ResolvedInstallLocation\..\
}
function Install-NSIS {
Write-Verbose "Downloading NSIS"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri https://nchc.dl.sourceforge.net/project/nsis/NSIS%203/3.04/nsis-3.04.zip -UseBasicParsing -OutFile "$tempdir/nsis.zip" | Write-Verbose
Expand-Archive "$tempdir/nsis.zip" -DestinationPath "$tempdir/nsis/" -Force | Write-Verbose Expand-Archive "$tempdir/nsis.zip" -DestinationPath "$tempdir/nsis/" -Force | Write-Verbose
$env:InstallLocation = $InstallLocation }
& "$tempdir/nsis/nsis-3.04/makensis.exe" ".\deployment\windows\jellyfin.nsi"
Copy-Item .\deployment\windows\jellyfin_*.exe $InstallLocation\..\ function Cleanup-NSIS {
Remove-Item "$tempdir/nsis/" -Recurse -Force -ErrorAction Continue | Write-Verbose Remove-Item "$tempdir/nsis/" -Recurse -Force -ErrorAction Continue | Write-Verbose
Remove-Item "$tempdir/nsis.zip" -Force -ErrorAction Continue | Write-Verbose Remove-Item "$tempdir/nsis.zip" -Force -ErrorAction Continue | Write-Verbose
} }
if(-not $SkipJellyfinBuild.IsPresent -and -not ($InstallNSIS -eq $true)){
Write-Verbose "Starting Build Process: Selected Environment is $WindowsVersion-$Architecture"
Write-Verbose "Starting Build Process: Selected Environment is $WindowsVersion-$Architecture" Build-JellyFin
Build-JellyFin }
if($InstallFFMPEG.IsPresent -or ($InstallFFMPEG -eq $true)){ if($InstallFFMPEG.IsPresent -or ($InstallFFMPEG -eq $true)){
Write-Verbose "Starting FFMPEG Install" Write-Verbose "Starting FFMPEG Install"
Install-FFMPEG $InstallLocation $Architecture Install-FFMPEG $ResolvedInstallLocation $Architecture
} }
if($InstallNSSM.IsPresent -or ($InstallNSSM -eq $true)){ if($InstallNSSM.IsPresent -or ($InstallNSSM -eq $true)){
Write-Verbose "Starting NSSM Install" Write-Verbose "Starting NSSM Install"
Install-NSSM $InstallLocation $Architecture Install-NSSM $ResolvedInstallLocation $Architecture
}
#Copy-Item .\deployment\windows\install-jellyfin.ps1 $ResolvedInstallLocation\install-jellyfin.ps1
#Copy-Item .\deployment\windows\install.bat $ResolvedInstallLocation\install.bat
Copy-Item .\LICENSE $ResolvedInstallLocation\LICENSE
if($InstallNSIS.IsPresent -or ($InstallNSIS -eq $true)){
Write-Verbose "Installing NSIS"
Install-NSIS
} }
Copy-Item .\deployment\windows\install-jellyfin.ps1 $InstallLocation\install-jellyfin.ps1
Copy-Item .\deployment\windows\install.bat $InstallLocation\install.bat
Copy-Item .\LICENSE $InstallLocation\LICENSE
if($MakeNSIS.IsPresent -or ($MakeNSIS -eq $true)){ if($MakeNSIS.IsPresent -or ($MakeNSIS -eq $true)){
Write-Verbose "Starting NSIS Package creation" Write-Verbose "Starting NSIS Package creation"
Make-NSIS $InstallLocation Make-NSIS $ResolvedInstallLocation
}
if($InstallNSIS.IsPresent -or ($InstallNSIS -eq $true)){
Write-Verbose "Cleanup NSIS"
Cleanup-NSIS
} }
if($GenerateZip.IsPresent -or ($GenerateZip -eq $true)){ if($GenerateZip.IsPresent -or ($GenerateZip -eq $true)){
Compress-Archive -Path $InstallLocation -DestinationPath "$InstallLocation/jellyfin.zip" -Force Compress-Archive -Path $ResolvedInstallLocation -DestinationPath "$ResolvedInstallLocation/jellyfin.zip" -Force
} }
Write-Verbose "Finished" Write-Verbose "Finished"

View File

@ -1 +1,2 @@
dotnet dotnet
nsis

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file was created by NSISDialogDesigner 1.4.4.0
http://coolsoft.altervista.org/nsisdialogdesigner
Do not edit manually!
-->
<Dialog Name="confirmation" Title="Confirmation Page" Subtitle="Please confirm your choices for Jellyfin Server installation" GenerateShowFunction="False">
<HeaderCustomScript>!include "helpers\StrSlash.nsh"</HeaderCustomScript>
<CreateFunctionCustomScript>${StrSlash} '$0' $INSTDIR
${StrSlash} '$1' $_JELLYFINDATADIR_
${NSD_SetText} $hCtl_confirmation_ConfirmRichText "{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1043\viewkind4\uc1 \
\pard\widctlpar\sa160\sl252\slmult1\b The installer will proceed based on the following inputs gathered on earlier screens.\par \
Installation Folder:\b0 $0\line\b \
Service install:\b0 $_INSTALLSERVICE_\line\b \
Service start:\b0 $_SERVICESTART_\line\b \
Service account:\b0 $_SERVICEACCOUNTTYPE_\line\b \
Jellyfin Data Folder:\b0 $1\par \
\
\pard\sa200\sl276\slmult1\f1\lang1043\par \
}"</CreateFunctionCustomScript>
<RichText Name="ConfirmRichText" Location="12, 12" Size="426, 204" TabIndex="0" ExStyle="WS_EX_STATICEDGE" />
</Dialog>

View File

@ -0,0 +1,61 @@
; =========================================================
; This file was generated by NSISDialogDesigner 1.4.4.0
; http://coolsoft.altervista.org/nsisdialogdesigner
;
; Do not edit it manually, use NSISDialogDesigner instead!
; Modified by EraYaN (2019-09-01)
; =========================================================
; handle variables
Var hCtl_confirmation
Var hCtl_confirmation_ConfirmRichText
; HeaderCustomScript
!include "helpers\StrSlash.nsh"
; dialog create function
Function fnc_confirmation_Create
; === confirmation (type: Dialog) ===
nsDialogs::Create 1018
Pop $hCtl_confirmation
${If} $hCtl_confirmation == error
Abort
${EndIf}
!insertmacro MUI_HEADER_TEXT "Confirmation Page" "Please confirm your choices for Jellyfin Server installation"
; === ConfirmRichText (type: RichText) ===
nsDialogs::CreateControl /NOUNLOAD "RichEdit20A" ${ES_READONLY}|${WS_VISIBLE}|${WS_CHILD}|${WS_TABSTOP}|${WS_VSCROLL}|${ES_MULTILINE}|${ES_WANTRETURN} ${WS_EX_STATICEDGE} 8u 7u 280u 126u ""
Pop $hCtl_confirmation_ConfirmRichText
${NSD_AddExStyle} $hCtl_confirmation_ConfirmRichText ${WS_EX_STATICEDGE}
; CreateFunctionCustomScript
${StrSlash} '$0' $INSTDIR
${StrSlash} '$1' $_JELLYFINDATADIR_
${If} $_INSTALLSERVICE_ == "Yes"
${NSD_SetText} $hCtl_confirmation_ConfirmRichText "{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1043\viewkind4\uc1 \
\pard\widctlpar\sa160\sl252\slmult1\b The installer will proceed based on the following inputs gathered on earlier screens.\par \
Installation Folder:\b0 $0\line\b \
Service install:\b0 $_INSTALLSERVICE_\line\b \
Service start:\b0 $_SERVICESTART_\line\b \
Service account:\b0 $_SERVICEACCOUNTTYPE_\line\b \
Jellyfin Data Folder:\b0 $1\par \
\
\pard\sa200\sl276\slmult1\f1\lang1043\par \
}"
${Else}
${NSD_SetText} $hCtl_confirmation_ConfirmRichText "{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1043\viewkind4\uc1 \
\pard\widctlpar\sa160\sl252\slmult1\b The installer will proceed based on the following inputs gathered on earlier screens.\par \
Installation Folder:\b0 $0\line\b \
Service install:\b0 $_INSTALLSERVICE_\line\b \
Jellyfin Data Folder:\b0 $1\par \
\
\pard\sa200\sl276\slmult1\f1\lang1043\par \
}"
${EndIf}
FunctionEnd

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file was created by NSISDialogDesigner 1.4.4.0
http://coolsoft.altervista.org/nsisdialogdesigner
Do not edit manually!
-->
<Dialog Name="service_config" Title="CoOnfigure the service" Subtitle="This controls what type of access the server gets to this system." GenerateShowFunction="False">
<CheckBox Name="StartServiceAfterInstall" Location="12, 192" Size="426, 24" Text="Start Service after Install" Checked="True" TabIndex="0" />
<Label Name="LocalSystemAccountLabel" Location="12, 115" Size="426, 46" Text="The Local System account has full access to every resource and file on the system. This can have very real security implications, do not use unless absolutely neseccary." TabIndex="1" />
<Label Name="NetworkServiceAccountLabel" Location="12, 39" Size="426, 46" Text="The NetworkService account is a predefined local account used by the service control manager. It is the recommended way to install the Jellyfin Server service." TabIndex="2" />
<RadioButton Name="UseLocalSystemAccount" Location="12, 88" Size="426, 24" Text="Use Local System account" TabIndex="3" />
<RadioButton Name="UseNetworkServiceAccount" Location="12, 12" Size="426, 24" Text="Use Network Service account (Recommended)" Font="Microsoft Sans Serif, 8.25pt, style=Bold" Checked="True" TabIndex="4" />
</Dialog>

View File

@ -0,0 +1,56 @@
; =========================================================
; This file was generated by NSISDialogDesigner 1.4.4.0
; http://coolsoft.altervista.org/nsisdialogdesigner
;
; Do not edit it manually, use NSISDialogDesigner instead!
; =========================================================
; handle variables
Var hCtl_service_config
Var hCtl_service_config_StartServiceAfterInstall
Var hCtl_service_config_LocalSystemAccountLabel
Var hCtl_service_config_NetworkServiceAccountLabel
Var hCtl_service_config_UseLocalSystemAccount
Var hCtl_service_config_UseNetworkServiceAccount
Var hCtl_service_config_Font1
; dialog create function
Function fnc_service_config_Create
; custom font definitions
CreateFont $hCtl_service_config_Font1 "Microsoft Sans Serif" "8.25" "700"
; === service_config (type: Dialog) ===
nsDialogs::Create 1018
Pop $hCtl_service_config
${If} $hCtl_service_config == error
Abort
${EndIf}
!insertmacro MUI_HEADER_TEXT "Configure the service" "This controls what type of access the server gets to this system."
; === StartServiceAfterInstall (type: Checkbox) ===
${NSD_CreateCheckbox} 8u 118u 280u 15u "Start Service after Install"
Pop $hCtl_service_config_StartServiceAfterInstall
${NSD_Check} $hCtl_service_config_StartServiceAfterInstall
; === LocalSystemAccountLabel (type: Label) ===
${NSD_CreateLabel} 8u 71u 280u 28u "The Local System account has full access to every resource and file on the system. This can have very real security implications, do not use unless absolutely neseccary."
Pop $hCtl_service_config_LocalSystemAccountLabel
; === NetworkServiceAccountLabel (type: Label) ===
${NSD_CreateLabel} 8u 24u 280u 28u "The NetworkService account is a predefined local account used by the service control manager. It is the recommended way to install the Jellyfin Server service."
Pop $hCtl_service_config_NetworkServiceAccountLabel
; === UseLocalSystemAccount (type: RadioButton) ===
${NSD_CreateRadioButton} 8u 54u 280u 15u "Use Local System account"
Pop $hCtl_service_config_UseLocalSystemAccount
${NSD_AddStyle} $hCtl_service_config_UseLocalSystemAccount ${WS_GROUP}
; === UseNetworkServiceAccount (type: RadioButton) ===
${NSD_CreateRadioButton} 8u 7u 280u 15u "Use Network Service account (Recommended)"
Pop $hCtl_service_config_UseNetworkServiceAccount
SendMessage $hCtl_service_config_UseNetworkServiceAccount ${WM_SETFONT} $hCtl_service_config_Font1 0
${NSD_Check} $hCtl_service_config_UseNetworkServiceAccount
FunctionEnd

View File

@ -0,0 +1,10 @@
; Show error
!macro ShowError TEXT RETRYLABEL
MessageBox MB_ABORTRETRYIGNORE|MB_ICONSTOP "${TEXT}" IDIGNORE +2 IDRETRY ${RETRYLABEL}
Abort
!macroend
!macro ShowErrorFinal TEXT
MessageBox MB_OK|MB_ICONSTOP "${TEXT}"
Abort
!macroend

View File

@ -0,0 +1,47 @@
; Adapted from: https://nsis.sourceforge.io/Another_String_Replace_(and_Slash/BackSlash_Converter) (2019-08-31)
!macro _StrSlashConstructor out in
Push "${in}"
Push "\"
Call StrSlash
Pop ${out}
!macroend
!define StrSlash '!insertmacro "_StrSlashConstructor"'
; Push $filenamestring (e.g. 'c:\this\and\that\filename.htm')
; Push "\"
; Call StrSlash
; Pop $R0
; ;Now $R0 contains 'c:/this/and/that/filename.htm'
Function StrSlash
Exch $R3 ; $R3 = needle ("\" or "/")
Exch
Exch $R1 ; $R1 = String to replacement in (haystack)
Push $R2 ; Replaced haystack
Push $R4 ; $R4 = not $R3 ("/" or "\")
Push $R6
Push $R7 ; Scratch reg
StrCpy $R2 ""
StrLen $R6 $R1
StrCpy $R4 "\"
StrCmp $R3 "/" loop
StrCpy $R4 "/"
loop:
StrCpy $R7 $R1 1
StrCpy $R1 $R1 $R6 1
StrCmp $R7 $R3 found
StrCpy $R2 "$R2$R7"
StrCmp $R1 "" done loop
found:
StrCpy $R2 "$R2$R4"
StrCmp $R1 "" done loop
done:
StrCpy $R3 $R2
Pop $R7
Pop $R6
Pop $R4
Pop $R2
Pop $R1
Exch $R3
FunctionEnd

View File

@ -1,38 +1,52 @@
; Shows a lot of debug information while compiling ; Shows a lot of debug information while compiling
; This can be removed once stable. ; This can be removed once stable.
!verbose 4 !verbose 4
SetCompressor lzma
ShowInstDetails show
ShowUninstDetails show
;-------------------------------- ;--------------------------------
!define SF_USELECTED 0 ; used to check selected options status, rest are inherited from Sections.nsh !define SF_USELECTED 0 ; used to check selected options status, rest are inherited from Sections.nsh
!include "MUI2.nsh" !include "MUI2.nsh"
!include "Sections.nsh" !include "Sections.nsh"
!include "LogicLib.nsh" !include "LogicLib.nsh"
!include "helpers\ShowError.nsh"
; Global variables that we'll use ; Global variables that we'll use
Var _JELLYFINVERSION_ Var _JELLYFINVERSION_
Var _JELLYFINDATADIR_ Var _JELLYFINDATADIR_
Var _INSTALLSERVICE_ Var _INSTALLSERVICE_
Var _SERVICESTART_ Var _SERVICESTART_
Var _LOCALSYSTEMACCOUNT_ Var _SERVICEACCOUNTTYPE_
Var _EXISTINGINSTALLATION_ Var _EXISTINGINSTALLATION_
Var _EXISTINGSERVICE_ Var _EXISTINGSERVICE_
Var _CUSTOMDATAFOLDER_ ;
!ifdef x64
!define ARCH "x64"
!define NAMESUFFIX "(64 bit)"
!define INSTALL_DIRECTORY "$PROGRAMFILES64\Jellyfin\Server"
!endif
!if ${NSIS_PTR_SIZE} > 4 !ifdef x84
!define BITS 64 !define ARCH "x86"
!define NAMESUFFIX " (64 bit)" !define NAMESUFFIX "(32 bit)"
!else !define INSTALL_DIRECTORY "$PROGRAMFILES32\Jellyfin\Server"
!define BITS 32 !endif
!define NAMESUFFIX ""
!ifndef ARCH
!error "Set the Arch with /Dx86 or /Dx64"
!endif !endif
;-------------------------------- ;--------------------------------
!define REG_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\Jellyfin" ;Registry to show up in Add/Remove Programs !define REG_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\JellyfinServer" ;Registry to show up in Add/Remove Programs
!define REG_CONFIG_KEY "Software\Jellyfin\Server" ;Registry to store all configuration
!getdllversion "$%InstallLocation%\jellyfin.dll" ver_ ;Align installer version with jellyfin.dll version !getdllversion "$%InstallLocation%\jellyfin.dll" ver_ ;Align installer version with jellyfin.dll version
Name "Jellyfin Server ${ver_1}.${ver_2}.${ver_3}" ; This is referred in various header text labels
OutFile "jellyfin_${ver_1}.${ver_2}.${ver_3}_windows.exe" ; Naming convention jellyfin_{version}_windows-{arch].exe Name "Jellyfin Server ${ver_1}.${ver_2}.${ver_3} ${NAMESUFFIX}" ; This is referred in various header text labels
OutFile "jellyfin_${ver_1}.${ver_2}.${ver_3}_windows-${ARCH}.exe" ; Naming convention jellyfin_{version}_windows-{arch].exe
BrandingText "Jellyfin Server ${ver_1}.${ver_2}.${ver_3} Installer" ; This shows in just over the buttons BrandingText "Jellyfin Server ${ver_1}.${ver_2}.${ver_3} Installer" ; This shows in just over the buttons
; installer attributes, these show up in details tab on installer properties ; installer attributes, these show up in details tab on installer properties
@ -40,167 +54,218 @@
VIFileVersion "${ver_1}.${ver_2}.${ver_3}.0" ; VIFileVersion format, should be X.X.X.X VIFileVersion "${ver_1}.${ver_2}.${ver_3}.0" ; VIFileVersion format, should be X.X.X.X
VIAddVersionKey "ProductName" "Jellyfin Server" VIAddVersionKey "ProductName" "Jellyfin Server"
VIAddVersionKey "FileVersion" "${ver_1}.${ver_2}.${ver_3}.0" VIAddVersionKey "FileVersion" "${ver_1}.${ver_2}.${ver_3}.0"
VIAddVersionKey "LegalCopyright" "Jellyfin, Free Software Media System" VIAddVersionKey "LegalCopyright" "(c) 2019 Jellyfin Contributors. Code released under the GNU General Public License"
VIAddVersionKey "FileDescription" "Jellyfin Server" VIAddVersionKey "FileDescription" "Jellyfin Server: The Free Software Media System"
;TODO, check defaults ;TODO, check defaults
InstallDir "$PROGRAMFILES\Jellyfin" ;Default installation folder InstallDir ${INSTALL_DIRECTORY} ;Default installation folder
InstallDirRegKey HKLM "Software\Jellyfin" "InstallFolder" ;Read the registry for install folder, InstallDirRegKey HKLM "${REG_CONFIG_KEY}" "InstallFolder" ;Read the registry for install folder,
RequestExecutionLevel admin ; ask it upfront for service control, and installing in priv folders RequestExecutionLevel admin ; ask it upfront for service control, and installing in priv folders
CRCCheck on ; make sure the installer wasn't corrupted while downloading CRCCheck on ; make sure the installer wasn't corrupted while downloading
!define MUI_ABORTWARNING ;Prompts user in case of aborting install !define MUI_ABORTWARNING ;Prompts user in case of aborting install
; TODO: Replace with nice Jellyfin Icons ; TODO: Replace with nice Jellyfin Icons
!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\nsis3-install.ico" ; Installer Icon !ifdef UXPATH
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\nsis3-uninstall.ico" ; Uninstaller Icon !define MUI_ICON "${UXPATH}\branding\NSIS\modern-install.ico" ; Installer Icon
!define MUI_UNICON "${UXPATH}\branding\NSIS\modern-uninstall.ico" ; Uninstaller Icon
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Header\nsis3-branding.bmp" !define MUI_HEADERIMAGE
!define MUI_WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\nsis3-branding.bmp" !define MUI_HEADERIMAGE_BITMAP "${UXPATH}\branding\NSIS\installer-header.bmp"
!define MUI_WELCOMEFINISHPAGE_BITMAP "${UXPATH}\branding\NSIS\installer-right.bmp"
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "${UXPATH}\branding\NSIS\installer-right.bmp"
!endif
;-------------------------------- ;--------------------------------
;Pages ;Pages
; Welcome Page ; Welcome Page
!define MUI_WELCOMEPAGE_TEXT "The installer will ask for details to install Jellyfin Server.$\r$\n$\r$\n$\r$\n\ !define MUI_WELCOMEPAGE_TEXT "The installer will ask for details to install Jellyfin Server."
ADVANCED:$\r$\n\ !insertmacro MUI_PAGE_WELCOME
The default service install uses Network Service account and is sufficient for most users. $\r$\n$\r$\n\
You can choose to install using Local System account under Advanced options. This also affects where Jellyfin Server and Jellyfin data can be installed. The installer will NOT check this, you should know what you are doing.$\r$\n$\r$\n\
You can choose the folder for Jellyfin Metadata under advanced options based on your needs."
!insertmacro MUI_PAGE_WELCOME
; License Page ; License Page
!insertmacro MUI_PAGE_LICENSE "$%InstallLocation%\LICENSE" ; picking up generic GPL !insertmacro MUI_PAGE_LICENSE "$%InstallLocation%\LICENSE" ; picking up generic GPL
; Components Page ; Components Page
!define MUI_COMPONENTSPAGE_SMALLDESC
!insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_COMPONENTS
!define MUI_PAGE_CUSTOMFUNCTION_PRE HideInstallDirectoryPage ; Controls when to hide / show !define MUI_PAGE_CUSTOMFUNCTION_PRE HideInstallDirectoryPage ; Controls when to hide / show
!define MUI_DIRECTORYPAGE_TEXT_DESTINATION "Install folder" ; shows just above the folder selection dialog !define MUI_DIRECTORYPAGE_TEXT_DESTINATION "Install folder" ; shows just above the folder selection dialog
!insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_DIRECTORY
; Metadata folder Page ; Data folder Page
!define MUI_PAGE_CUSTOMFUNCTION_PRE HideDataDirectoryPage ; Controls when to hide / show !define MUI_PAGE_CUSTOMFUNCTION_PRE HideDataDirectoryPage ; Controls when to hide / show
!define MUI_PAGE_HEADER_SUBTEXT "Choose the folder in which to install the Jellyfin Server metadata." !define MUI_PAGE_HEADER_TEXT "Choose Data Location"
!define MUI_DIRECTORYPAGE_TEXT_TOP "The installer will set the following folder for Jellyfin Server metadata. To install in a differenct folder, click Browse and select another folder. Please make sure the folder exists. Click Next to continue." !define MUI_PAGE_HEADER_SUBTEXT "Choose the folder in which to install the Jellyfin Server data."
!define MUI_DIRECTORYPAGE_TEXT_DESTINATION "Metadata folder" !define MUI_DIRECTORYPAGE_TEXT_TOP "The installer will set the following folder for Jellyfin Server data. To install in a different folder, click Browse and select another folder. Please make sure the folder exists and is accessible. Click Next to continue."
!define MUI_DIRECTORYPAGE_VARIABLE $_JELLYFINDATADIR_ !define MUI_DIRECTORYPAGE_TEXT_DESTINATION "Data folder"
!insertmacro MUI_PAGE_DIRECTORY !define MUI_DIRECTORYPAGE_VARIABLE $_JELLYFINDATADIR_
!insertmacro MUI_PAGE_DIRECTORY
; Confirmation Page ; Custom Dialogs
Page custom ConfirmationPage ; just letting the user know what they chose to install !include "dialogs\service-config.nsdinc"
!include "dialogs\confirmation.nsdinc"
; Actual Installion Page ; Select service account type
!insertmacro MUI_PAGE_INSTFILES #!define MUI_PAGE_CUSTOMFUNCTION_PRE HideServiceConfigPage ; Controls when to hide / show (This does not work for Page, might need to go PageEx)
#!define MUI_PAGE_CUSTOMFUNCTION_SHOW fnc_service_config_Show
#!define MUI_PAGE_CUSTOMFUNCTION_LEAVE ServiceConfigPage_Config
#!insertmacro MUI_PAGE_CUSTOM ServiceAccountType
Page custom ShowServiceConfigPage ServiceConfigPage_Config
; Confirmation Page
Page custom ShowConfirmationPage ; just letting the user know what they chose to install
; Actual Installion Page
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH #!insertmacro MUI_UNPAGE_FINISH
;-------------------------------- ;--------------------------------
;Languages; Add more languages later here if needed ;Languages; Add more languages later here if needed
!insertmacro MUI_LANGUAGE "English" !insertmacro MUI_LANGUAGE "English"
;-------------------------------- ;--------------------------------
;Installer Sections ;Installer Sections
Section "Jellyfin Server (required)" InstallJellyfin Section "!Jellyfin Server (required)" InstallJellyfinServer
SectionIn RO ; Mandatory section, isn't this the whole purpose to run the installer. SectionIn RO ; Mandatory section, isn't this the whole purpose to run the installer.
StrCmp "$_EXISTINGINSTALLATION_" "YES" RunUninstaller CarryOn ; Silently uninstall in case of previous installation StrCmp "$_EXISTINGINSTALLATION_" "Yes" RunUninstaller CarryOn ; Silently uninstall in case of previous installation
RunUninstaller: RunUninstaller:
DetailPrint "Looking for uninstaller at $INSTDIR" DetailPrint "Looking for uninstaller at $INSTDIR"
FindFirst $0 $1 "$INSTDIR\Uninstall.exe" FindFirst $0 $1 "$INSTDIR\Uninstall.exe"
FindClose $0 FindClose $0
StrCmp $1 "" CarryOn ; the registry key was there but uninstaller was not found StrCmp $1 "" CarryOn ; the registry key was there but uninstaller was not found
DetailPrint "Silently running the uninstaller at $INSTDIR" DetailPrint "Silently running the uninstaller at $INSTDIR"
ExecWait '"$INSTDIR\Uninstall.exe" /S _?=$INSTDIR' $0 ExecWait '"$INSTDIR\Uninstall.exe" /S _?=$INSTDIR' $0
DetailPrint "Uninstall finished, $0" DetailPrint "Uninstall finished, $0"
CarryOn: CarryOn:
${If} $_EXISTINGSERVICE_ == 'Yes'
ExecWait '"$INSTDIR\nssm.exe" stop JellyfinServer' $0
${If} $0 <> 0
MessageBox MB_OK|MB_ICONSTOP "Could not stop the Jellyfin Server service."
Abort
${EndIf}
DetailPrint "Stopped Jellyfin Server service, $0"
${EndIf}
SetOutPath "$INSTDIR" SetOutPath "$INSTDIR"
File /r $%InstallLocation%\* File /r $%InstallLocation%\*
; Write the InstallFolder, DataFolder, Network Service info into the registry for later use ; Write the InstallFolder, DataFolder, Network Service info into the registry for later use
WriteRegExpandStr HKLM "Software\Jellyfin" "InstallFolder" "$INSTDIR" WriteRegExpandStr HKLM "${REG_CONFIG_KEY}" "InstallFolder" "$INSTDIR"
WriteRegExpandStr HKLM "Software\Jellyfin" "DataFolder" "$_JELLYFINDATADIR_" WriteRegExpandStr HKLM "${REG_CONFIG_KEY}" "DataFolder" "$_JELLYFINDATADIR_"
WriteRegStr HKLM "Software\Jellyfin" "LocalSystemAccount" "$_LOCALSYSTEMACCOUNT_" WriteRegStr HKLM "${REG_CONFIG_KEY}" "ServiceAccountType" "$_SERVICEACCOUNTTYPE_"
!getdllversion "$%InstallLocation%\jellyfin.dll" ver_ !getdllversion "$%InstallLocation%\jellyfin.dll" ver_
StrCpy $_JELLYFINVERSION_ "${ver_1}.${ver_2}.${ver_3}" ; StrCpy $_JELLYFINVERSION_ "${ver_1}.${ver_2}.${ver_3}" ;
; Write the uninstall keys for Windows ; Write the uninstall keys for Windows
WriteRegStr HKLM "${REG_UNINST_KEY}" "DisplayName" "Jellyfin $_JELLYFINVERSION_" WriteRegStr HKLM "${REG_UNINST_KEY}" "DisplayName" "Jellyfin Server $_JELLYFINVERSION_ ${NAMESUFFIX}"
WriteRegExpandStr HKLM "${REG_UNINST_KEY}" "UninstallString" '"$INSTDIR\Uninstall.exe"' WriteRegExpandStr HKLM "${REG_UNINST_KEY}" "UninstallString" '"$INSTDIR\Uninstall.exe"'
WriteRegStr HKLM "${REG_UNINST_KEY}" "DisplayIcon" '"$INSTDIR\Jellyfin.exe",0' WriteRegStr HKLM "${REG_UNINST_KEY}" "DisplayIcon" '"$INSTDIR\Uninstall.exe",0'
WriteRegStr HKLM "${REG_UNINST_KEY}" "Publisher" "The Jellyfin project" WriteRegStr HKLM "${REG_UNINST_KEY}" "Publisher" "The Jellyfin Project"
WriteRegStr HKLM "${REG_UNINST_KEY}" "URLInfoAbout" "https://jellyfin.github.io/" WriteRegStr HKLM "${REG_UNINST_KEY}" "URLInfoAbout" "https://jellyfin.media/"
WriteRegStr HKLM "${REG_UNINST_KEY}" "DisplayVersion" "$_JELLYFINVERSION_" WriteRegStr HKLM "${REG_UNINST_KEY}" "DisplayVersion" "$_JELLYFINVERSION_"
WriteRegDWORD HKLM "${REG_UNINST_KEY}" "NoModify" 1 WriteRegDWORD HKLM "${REG_UNINST_KEY}" "NoModify" 1
WriteRegDWORD HKLM "${REG_UNINST_KEY}" "NoRepair" 1 WriteRegDWORD HKLM "${REG_UNINST_KEY}" "NoRepair" 1
;Create uninstaller ;Create uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe" WriteUninstaller "$INSTDIR\Uninstall.exe"
SectionEnd SectionEnd
Section "Jellyfin Service" InstallService Section "Jellyfin Server Service" InstallService
ExecWait '"$INSTDIR\nssm.exe" statuscode JellyfinServer' $0
DetailPrint "Jellyfin Server service statuscode, $0"
${If} $0 == 0
InstallRetry:
ExecWait '"$INSTDIR\nssm.exe" install JellyfinServer "$INSTDIR\jellyfin.exe" --datadir "$_JELLYFINDATADIR_"' $0
${If} $0 <> 0
!insertmacro ShowError "Could not install the Jellyfin Server service." InstallRetry
${EndIf}
DetailPrint "Jellyfin Server Service install, $0"
${Else}
DetailPrint "Jellyfin Server Service exists, updating..."
ConfigureApplicationRetry:
ExecWait '"$INSTDIR\nssm.exe" set JellyfinServer Application "$INSTDIR\jellyfin.exe"' $0
${If} $0 <> 0
!insertmacro ShowError "Could not configure the Jellyfin Server service." ConfigureApplicationRetry
${EndIf}
DetailPrint "Jellyfin Server Service setting (Application), $0"
ConfigureAppParametersRetry:
ExecWait '"$INSTDIR\nssm.exe" set JellyfinServer AppParameters --datadir "$_JELLYFINDATADIR_"' $0
${If} $0 <> 0
!insertmacro ShowError "Could not configure the Jellyfin Server service." ConfigureAppParametersRetry
${EndIf}
DetailPrint "Jellyfin Server Service setting (AppParameters), $0"
${EndIf}
ExecWait '"$INSTDIR\nssm.exe" install Jellyfin "$INSTDIR\jellyfin.exe" --datadir "$_JELLYFINDATADIR_"' $0
DetailPrint "Jellyfin Service install, $0"
Sleep 3000 ; Give time for Windows to catchup Sleep 3000 ; Give time for Windows to catchup
ConfigureStartRetry:
ExecWait '"$INSTDIR\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START' $0 ExecWait '"$INSTDIR\nssm.exe" set JellyfinServer Start SERVICE_DELAYED_AUTO_START' $0
DetailPrint "Jellyfin Service setting, $0" ${If} $0 <> 0
!insertmacro ShowError "Could not configure the Jellyfin Server service." ConfigureStartRetry
${EndIf}
DetailPrint "Jellyfin Server Service setting (Start), $0"
ConfigureDescriptionRetry:
ExecWait '"$INSTDIR\nssm.exe" set JellyfinServer Description "Jellyfin Server: The Free Software Media System"' $0
${If} $0 <> 0
!insertmacro ShowError "Could not configure the Jellyfin Server service." ConfigureDescriptionRetry
${EndIf}
DetailPrint "Jellyfin Server Service setting (Description), $0"
ConfigureDisplayNameRetry:
ExecWait '"$INSTDIR\nssm.exe" set JellyfinServer DisplayName "Jellyfin Server"' $0
${If} $0 <> 0
!insertmacro ShowError "Could not configure the Jellyfin Server service." ConfigureDisplayNameRetry
${EndIf}
DetailPrint "Jellyfin Server Service setting (DisplayName), $0"
Sleep 3000 Sleep 3000
${If} $_LOCALSYSTEMACCOUNT_ == "NO" ; the default install using NSSM is Local System ${If} $_SERVICEACCOUNTTYPE_ == "NetworkService" ; the default install using NSSM is Local System
DetailPrint "Attempting to change service account to Network Service" ConfigureNetworkServiceRetry:
ExecWait '"$INSTDIR\nssm.exe" set Jellyfin Objectname "Network Service"' $0 ExecWait '"$INSTDIR\nssm.exe" set JellyfinServer Objectname "Network Service"' $0
DetailPrint "Jellyfin service account change, $0" ${If} $0 <> 0
${EndIf} !insertmacro ShowError "Could not configure the Jellyfin Server service account." ConfigureNetworkServiceRetry
${EndIf}
DetailPrint "Jellyfin Server service account change, $0"
${EndIf}
SectionEnd SectionEnd
Section "Start Jellyfin service after install" StartService Section "-start service" StartService
${If} $_SERVICESTART_ == "Yes"
ExecWait '"$INSTDIR\nssm.exe" start Jellyfin' $0 ${AndIf} $_INSTALLSERVICE_ == "Yes"
DetailPrint "Jellyfin service start, $0" StartRetry:
ExecWait '"$INSTDIR\nssm.exe" start JellyfinServer' $0
${If} $0 <> 0
!insertmacro ShowError "Could not start the Jellyfin Server service." StartRetry
${EndIf}
DetailPrint "Jellyfin Server service start, $0"
${EndIf}
SectionEnd SectionEnd
SectionGroup "Advanced" Advanced
Section /o "Use Local System account" LocalSystemAccount
; The section is for user choice, nothing to do here
SectionEnd
Section /o "Custom Jellyfin metadata folder" CustomDataFolder
; The section is for user choice, nothing to do here
SectionEnd
SectionGroupEnd
;-------------------------------- ;--------------------------------
;Descriptions ;Descriptions
;Language strings ;Language strings
LangString DESC_InstallJellyfin ${LANG_ENGLISH} "Install Jellyfin Server" LangString DESC_InstallJellyfinServer ${LANG_ENGLISH} "Install Jellyfin Server"
LangString DESC_InstallService ${LANG_ENGLISH} "Install As a Service" LangString DESC_InstallService ${LANG_ENGLISH} "Install As a Service"
LangString DESC_StartService ${LANG_ENGLISH} "Start Jellyfin service after Install"
LangString DESC_LocalSystemAccount ${LANG_ENGLISH} "Use Local System account to start windows service"
LangString DESC_CustomDataFolder ${LANG_ENGLISH} "Choose Jellyfin Server metadata folder in subsequent steps"
;Assign language strings to sections ;Assign language strings to sections
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${InstallJellyfin} $(DESC_InstallJellyfin) !insertmacro MUI_DESCRIPTION_TEXT ${InstallJellyfinServer} $(DESC_InstallJellyfinServer)
!insertmacro MUI_DESCRIPTION_TEXT ${InstallService} $(DESC_InstallService) !insertmacro MUI_DESCRIPTION_TEXT ${InstallService} $(DESC_InstallService)
!insertmacro MUI_DESCRIPTION_TEXT ${StartService} $(DESC_StartService)
!insertmacro MUI_DESCRIPTION_TEXT ${LocalSystemAccount} $(DESC_LocalSystemAccount)
!insertmacro MUI_DESCRIPTION_TEXT ${CustomDataFolder} $(DESC_CustomDataFolder)
!insertmacro MUI_FUNCTION_DESCRIPTION_END !insertmacro MUI_FUNCTION_DESCRIPTION_END
;-------------------------------- ;--------------------------------
@ -208,179 +273,199 @@ SectionGroupEnd
Section "Uninstall" Section "Uninstall"
ReadRegStr $INSTDIR HKLM "Software\Jellyfin" "InstallFolder" ; read the installation folder ReadRegStr $INSTDIR HKLM "${REG_CONFIG_KEY}" "InstallFolder" ; read the installation folder
ReadRegStr $_JELLYFINDATADIR_ HKLM "Software\Jellyfin" "DataFolder" ; read the metadata folder ReadRegStr $_JELLYFINDATADIR_ HKLM "${REG_CONFIG_KEY}" "DataFolder" ; read the data folder
DetailPrint "Jellyfin Install location : $INSTDIR" DetailPrint "Jellyfin Install location: $INSTDIR"
DetailPrint "Jellyfin data folder : $_JELLYFINDATADIR_" DetailPrint "Jellyfin Data folder: $_JELLYFINDATADIR_"
MessageBox MB_YESNO|MB_ICONINFORMATION "Do you want to retain Jellyfin metadata folder? The media will not be touched. $\r$\nIf unsure choose YES." /SD IDYES IDYES PreserveData MessageBox MB_YESNO|MB_ICONINFORMATION "Do you want to retain the Jellyfin Server data folder? The media will not be touched. $\r$\nIf unsure choose YES." /SD IDYES IDYES PreserveData
RMDir /r /REBOOTOK "$_JELLYFINDATADIR_" RMDir /r /REBOOTOK "$_JELLYFINDATADIR_"
PreserveData:
DetailPrint "Attempting to stop Jellyfin Server" PreserveData:
ExecWait '"$INSTDIR\nssm.exe" stop Jellyfin' $0
DetailPrint "Jellyfin service stop, $0"
DetailPrint "Attempting to remove Jellyfin service"
ExecWait '"$INSTDIR\nssm.exe" remove Jellyfin confirm' $0
DetailPrint "Jellyfin Service remove, $0"
ExecWait '"$INSTDIR\nssm.exe" statuscode JellyfinServer' $0
DetailPrint "Jellyfin Server service statuscode, $0"
IntCmp $0 0 NoServiceUninstall ; service doesn't exist, may be run from desktop shortcut
Sleep 3000 ; Give time for Windows to catchup
UninstallStopRetry:
ExecWait '"$INSTDIR\nssm.exe" stop JellyfinServer' $0
${If} $0 <> 0
!insertmacro ShowError "Could not stop the Jellyfin Server service." UninstallStopRetry
${EndIf}
DetailPrint "Stopped Jellyfin Server service, $0"
UninstallRemoveRetry:
ExecWait '"$INSTDIR\nssm.exe" remove JellyfinServer confirm' $0
${If} $0 <> 0
!insertmacro ShowError "Could not remove the Jellyfin Server service." UninstallRemoveRetry
${EndIf}
DetailPrint "Removed Jellyfin Server service, $0"
Sleep 3000 ; Give time for Windows to catchup
NoServiceUninstall: ; existing install was present but no service was detected
Delete "$INSTDIR\*.*"
RMDir /r /REBOOTOK "$INSTDIR\jellyfin-web"
Delete "$INSTDIR\Uninstall.exe" Delete "$INSTDIR\Uninstall.exe"
RMDir /r /REBOOTOK "$INSTDIR"
RMDir /r /REBOOTOK "$INSTDIR"
DeleteRegKey HKLM "Software\Jellyfin" DeleteRegKey HKLM "Software\Jellyfin"
DeleteRegKey HKLM "${REG_UNINST_KEY}" DeleteRegKey HKLM "${REG_UNINST_KEY}"
SectionEnd SectionEnd
Function .onInit Function .onInit
; Setting up defaults ; Setting up defaults
StrCpy $_INSTALLSERVICE_ "YES" StrCpy $_INSTALLSERVICE_ "Yes"
StrCpy $_SERVICESTART_ "YES" StrCpy $_SERVICESTART_ "Yes"
StrCpy $_CUSTOMDATAFOLDER_ "NO" StrCpy $_SERVICEACCOUNTTYPE_ "NetworkService"
StrCpy $_LOCALSYSTEMACCOUNT_ "NO" StrCpy $_EXISTINGINSTALLATION_ "No"
StrCpy $_EXISTINGINSTALLATION_ "NO" StrCpy $_EXISTINGSERVICE_ "No"
StrCpy $_EXISTINGSERVICE_ "NO"
SetShellVarContext current SetShellVarContext current
StrCpy $_JELLYFINDATADIR_ "$%ProgramData%\jellyfin\" StrCpy $_JELLYFINDATADIR_ "$%ProgramData%\Jellyfin\Server"
System::Call 'kernel32::CreateMutex(p 0, i 0, t "JellyfinServerMutex") p .r1 ?e'
Pop $R0
StrCmp $R0 0 +3
!insertmacro ShowErrorFinal "The installer is already running."
;Detect if Jellyfin is already installed. ;Detect if Jellyfin is already installed.
; In case it is installed, let the user choose either ; In case it is installed, let the user choose either
; 1. Exit installer ; 1. Exit installer
; 2. Upgrade without messing with data ; 2. Upgrade without messing with data
; 2a. Don't ask for any details, uninstall and install afresh with old settings ; 2a. Don't ask for any details, uninstall and install afresh with old settings
; Read Registry for previous installation ; Read Registry for previous installation
ClearErrors ClearErrors
ReadRegStr "$0" HKLM "Software\Jellyfin" "InstallFolder" ReadRegStr "$0" HKLM "${REG_CONFIG_KEY}" "InstallFolder"
IfErrors NoExisitingInstall IfErrors NoExisitingInstall
DetailPrint "Existing Jellyfin detected at: $0" DetailPrint "Existing Jellyfin Server detected at: $0"
StrCpy "$INSTDIR" "$0" ; set the location fro registry as new default StrCpy "$INSTDIR" "$0" ; set the location fro registry as new default
StrCpy $_EXISTINGINSTALLATION_ "YES" ; Set our flag to be used later StrCpy $_EXISTINGINSTALLATION_ "Yes" ; Set our flag to be used later
SectionSetText ${InstallJellyfin} "Upgrade Jellyfin Server(required)" ; Change install text to "Upgrade" SectionSetText ${InstallJellyfinServer} "Upgrade Jellyfin Server (required)" ; Change install text to "Upgrade"
; check if there is a service called Jellyfin, there should be ; check if there is a service called Jellyfin, there should be
; hack : nssm statuscode Jellyfin will return non zero return code in case it exists ; hack : nssm statuscode Jellyfin will return non zero return code in case it exists
ExecWait '"$INSTDIR\nssm.exe" statuscode Jellyfin' $0 ExecWait '"$INSTDIR\nssm.exe" statuscode JellyfinServer' $0
DetailPrint "Jellyfin service statuscode, $0" DetailPrint "Jellyfin Server service statuscode, $0"
IntCmp $0 0 NoService ; service doesn't exist, may be run from desktop shortcut IntCmp $0 0 NoService ; service doesn't exist, may be run from desktop shortcut
; if service was detected, set defaults going forward. ; if service was detected, set defaults going forward.
StrCpy $_EXISTINGSERVICE_ "YES" StrCpy $_EXISTINGSERVICE_ "Yes"
StrCpy $_INSTALLSERVICE_ "YES" StrCpy $_INSTALLSERVICE_ "Yes"
StrCpy $_SERVICESTART_ "YES" StrCpy $_SERVICESTART_ "Yes"
; check if service was run using Network Service account
ClearErrors
ReadRegStr "$_LOCALSYSTEMACCOUNT_" HKLM "Software\Jellyfin" "LocalSystemAccount" ; in case of error _LOCALSYSTEMACCOUNT_ will be NO as default
ClearErrors ; check if service was run using Network Service account
ReadRegStr $_JELLYFINDATADIR_ HKLM "Software\Jellyfin" "DataFolder" ; in case of error, the default holds ClearErrors
ReadRegStr $_SERVICEACCOUNTTYPE_ HKLM "${REG_CONFIG_KEY}" "ServiceAccountType" ; in case of error _SERVICEACCOUNTTYPE_ will be NetworkService as default
; Hide sections which will not be needed in case of previous install
SectionSetText ${InstallService} "" ClearErrors
SectionSetText ${StartService} "" ReadRegStr $_JELLYFINDATADIR_ HKLM "${REG_CONFIG_KEY}" "DataFolder" ; in case of error, the default holds
SectionSetText ${LocalSystemAccount} ""
SectionSetText ${CustomDataFolder} "" ; Hide sections which will not be needed in case of previous install
SectionSetText ${Advanced} "" ; SectionSetText ${InstallService} ""
NoService: ; existing install was present but no service was detected
NoService: ; existing install was present but no service was detected
; Let the user know that we'll upgrade and provide an option to quit. ; Let the user know that we'll upgrade and provide an option to quit.
MessageBox MB_OKCANCEL|MB_ICONINFORMATION "Existing installation of Jellyfin was detected, it'll be upgraded, settings will be retained. \ MessageBox MB_OKCANCEL|MB_ICONINFORMATION "Existing installation of Jellyfin Server was detected, it'll be upgraded, settings will be retained. \
$\r$\nClick OK to proceed, Cancel to exit installer." /SD IDOK IDOK ProceedWithUpgrade $\r$\nClick OK to proceed, Cancel to exit installer." /SD IDOK IDOK ProceedWithUpgrade
Quit ; Quit if the user is not sure about upgrade Quit ; Quit if the user is not sure about upgrade
ProceedWithUpgrade: ProceedWithUpgrade:
NoExisitingInstall: NoExisitingInstall:
; by this time, the variables have been correctly set to reflect previous install details ; by this time, the variables have been correctly set to reflect previous install details
FunctionEnd FunctionEnd
Function HideInstallDirectoryPage Function HideInstallDirectoryPage
${If} $_EXISTINGINSTALLATION_ == "YES" ; Existing installation detected, so don't ask for InstallFolder ${If} $_EXISTINGINSTALLATION_ == "Yes" ; Existing installation detected, so don't ask for InstallFolder
Abort Abort
${EndIf} ${EndIf}
FunctionEnd FunctionEnd
; Don't show custom folder option in case it wasn't chosen
Function HideDataDirectoryPage Function HideDataDirectoryPage
${If} $_CUSTOMDATAFOLDER_ == "NO" ${If} $_EXISTINGINSTALLATION_ == "Yes" ; Existing installation detected, so don't ask for InstallFolder
Abort Abort
${EndIf} ${EndIf}
FunctionEnd
Function HideServiceConfigPage
${If} $_INSTALLSERVICE_ == "No" ; Not running as a service, don't ask for service type
${OrIf} $_EXISTINGINSTALLATION_ == "Yes" ; Existing installation detected, so don't ask for InstallFolder
Abort
${EndIf}
FunctionEnd
Function HideConfirmationPage
${If} $_EXISTINGINSTALLATION_ == "Yes" ; Existing installation detected, so don't ask for InstallFolder
Abort
${EndIf}
FunctionEnd
; Service Config dialog show function
Function ShowServiceConfigPage
Call HideServiceConfigPage
Call fnc_service_config_Create
nsDialogs::Show
FunctionEnd
; Confirmation dialog show function
Function ShowConfirmationPage
Call HideConfirmationPage
Call fnc_confirmation_Create
nsDialogs::Show
FunctionEnd
; Declare temp variables to read the options from the custom page.
Var StartServiceAfterInstall
Var UseNetworkServiceAccount
Var UseLocalSystemAccount
Function ServiceConfigPage_Config
${NSD_GetState} $hCtl_service_config_StartServiceAfterInstall $StartServiceAfterInstall
${If} $StartServiceAfterInstall == 1
StrCpy $_SERVICESTART_ "Yes"
${Else}
StrCpy $_SERVICESTART_ "No"
${EndIf}
${NSD_GetState} $hCtl_service_config_UseNetworkServiceAccount $UseNetworkServiceAccount
${NSD_GetState} $hCtl_service_config_UseLocalSystemAccount $UseLocalSystemAccount
${If} $UseNetworkServiceAccount == 1
StrCpy $_SERVICEACCOUNTTYPE_ "NetworkService"
${ElseIf} $UseLocalSystemAccount == 1
StrCpy $_SERVICEACCOUNTTYPE_ "LocalSystem"
${Else}
!insertmacro ShowErrorFinal "Service account type not properly configured."
${EndIf}
FunctionEnd FunctionEnd
; This function handles the choices during component selection ; This function handles the choices during component selection
Function .onSelChange Function .onSelChange
SectionGetFlags ${CustomDataFolder} $0
${If} $0 = ${SF_SELECTED}
StrCpy $_CUSTOMDATAFOLDER_ "YES"
${Else}
StrCpy $_CUSTOMDATAFOLDER_ "NO"
${EndIf}
; If we are not installing service, we don't need to set the NetworkService account or StartService ; If we are not installing service, we don't need to set the NetworkService account or StartService
SectionGetFlags ${InstallService} $0 SectionGetFlags ${InstallService} $0
${If} $0 = ${SF_SELECTED} ${If} $0 = ${SF_SELECTED}
StrCpy $_INSTALLSERVICE_ "YES" StrCpy $_INSTALLSERVICE_ "Yes"
SectionGetFlags ${LocalSystemAccount} $0 ${Else}
IntOp $0 $0 | ${SF_RO} StrCpy $_INSTALLSERVICE_ "No"
IntOp $0 $0 ^ ${SF_RO} StrCpy $_SERVICESTART_ "No"
SectionSetFlags ${LocalSystemAccount} $0 StrCpy $_SERVICEACCOUNTTYPE_ "None"
SectionGetFlags ${StartService} $0 ${EndIf}
IntOp $0 $0 | ${SF_RO}
IntOp $0 $0 ^ ${SF_RO}
SectionSetFlags ${StartService} $0
${Else}
StrCpy $_INSTALLSERVICE_ "NO"
IntOp $0 ${SF_USELECTED} | ${SF_RO}
SectionSetFlags ${LocalSystemAccount} $0
SectionSetFlags ${StartService} $0
${EndIf}
SectionGetFlags ${StartService} $0
${If} $0 = ${SF_SELECTED}
StrCpy $_SERVICESTART_ "YES"
${Else}
StrCpy $_SERVICESTART_ "NO"
${EndIf}
SectionGetFlags ${LocalSystemAccount} $0
${If} $0 = ${SF_SELECTED}
StrCpy $_LOCALSYSTEMACCOUNT_ "YES"
${Else}
StrCpy $_LOCALSYSTEMACCOUNT_ "NO"
${EndIf}
FunctionEnd
Function ConfirmationPage
!insertmacro MUI_HEADER_TEXT "Confirmation Page" "Please confirm your choices for Jellyfin Server installation"
nsDialogs::Create 1018
${NSD_CreateLabel} 0 0 100% 100% "The installer will proceed based on the following inputs gathered on earlier screens.$\r$\n$\r$\n\
Installation Folder : $INSTDIR$\r$\n\
Service install : $_INSTALLSERVICE_$\r$\n\
Service start : $_SERVICESTART_$\r$\n\
Local System account for service: $_LOCALSYSTEMACCOUNT_$\r$\n\
Custom Metadata folder : $_CUSTOMDATAFOLDER_$\r$\n\
Jellyfin Metadata Folder: $_JELLYFINDATADIR_"
nsDialogs::Show
FunctionEnd FunctionEnd
Function .onInstSuccess Function .onInstSuccess
ExecShell "open" "http://localhost:8096" #ExecShell "open" "http://localhost:8096"
FunctionEnd FunctionEnd