#!/usr/bin/env pwsh # The Windows download: one setup program, carrying everything Dikte needs to # record and to be started again after a sign-in. # # Run from anywhere; it works in build\ at the top of the checkout and leaves # the finished .exe in dist\. x64 only, because that is what the PyQt6 wheel and # whisper.cpp both publish for Windows; a Windows on ARM machine runs it under # the emulation it runs everything else under. # # powershell -ExecutionPolicy Bypass -File packaging\build-windows.ps1 $ErrorActionPreference = "Stop" $root = Split-Path -Parent $PSScriptRoot $build = Join-Path $root "build" $out = Join-Path $root "dist" $dist = Join-Path $build "dist\dikte" $env:PYTHONPATH = $root $version = & python -c "import dikte; print(dikte.__version__)" if ($LASTEXITCODE -ne 0) { throw "could not read the version out of dikte/__init__.py" } # A pinned tag and a checksum rather than "whatever is newest": this binary goes # out inside something people run, so what it is has to be decided here and not # by whoever pushes to that repository next. The same release the disk image # takes its ffmpeg from, which is gyan.dev's essentials build repackaged, and # dshow is in it, which is the one part of ffmpeg recording here goes through. $ffmpegTag = "b6.1.1" $ffmpegAsset = "ffmpeg-win32-x64.gz" $ffmpegSha = "8883A3DFFBD0A16CF4EF95206EA05283F78908DBFB118F73C83F4951DCC06D77" if (Test-Path $build) { Remove-Item $build -Recurse -Force } if (Test-Path $out) { Remove-Item $out -Recurse -Force } New-Item -ItemType Directory -Path $build, $out | Out-Null # 1. The icon --------------------------------------------------------------- # Drawn by Dikte itself, offscreen, which is why there is no image file in the # repository. Before the application, because PyInstaller writes it into the # executable rather than beside it, and the setup program uses the same file. $icon = Join-Path $build "Dikte.ico" $env:QT_QPA_PLATFORM = "offscreen" & python -m dikte.trayicon --ico $icon if ($LASTEXITCODE -ne 0) { throw "the icon would not draw" } Remove-Item Env:\QT_QPA_PLATFORM $env:DIKTE_ICO = $icon # 2. The application -------------------------------------------------------- # Two executables in the one directory: Dikte.exe, which is windowed and is # what a shortcut starts, and dikte.exe, which has a console and is what the # `dikte` command runs. & python -m PyInstaller (Join-Path $root "packaging\dikte.spec") ` --distpath (Join-Path $build "dist") --workpath (Join-Path $build "work") ` --noconfirm --clean if ($LASTEXITCODE -ne 0) { throw "PyInstaller failed" } # 3. ffmpeg ----------------------------------------------------------------- # Recording on Windows goes through ffmpeg's DirectShow input, and Windows # ships nothing like it, so without this the download would be an application # that cannot record until the person who downloaded it installs one. bin\ # beside the executables, because integrate.py puts that directory in front of # PATH at startup and everything reaching for ffmpeg goes through shutil.which. $archive = Join-Path $build $ffmpegAsset Invoke-WebRequest -UseBasicParsing -OutFile $archive ` "https://github.com/eugeneware/ffmpeg-static/releases/download/$ffmpegTag/$ffmpegAsset" $got = (Get-FileHash $archive -Algorithm SHA256).Hash if ($got -ne $ffmpegSha) { throw "ffmpeg checksum: expected $ffmpegSha, got $got" } $bin = Join-Path $dist "bin" New-Item -ItemType Directory -Path $bin | Out-Null $compressed = [System.IO.File]::OpenRead($archive) $stream = New-Object System.IO.Compression.GzipStream( $compressed, [System.IO.Compression.CompressionMode]::Decompress) $binary = [System.IO.File]::Create((Join-Path $bin "ffmpeg.exe")) try { $stream.CopyTo($binary) } finally { $binary.Dispose(); $stream.Dispose(); $compressed.Dispose() } # 4. The setup program ------------------------------------------------------ # Inno Setup comes with the GitHub runner. On a machine that has not got it: # winget install JRSoftware.InnoSetup $iscc = (Get-Command iscc -ErrorAction SilentlyContinue).Source if (-not $iscc) { $iscc = Join-Path ${env:ProgramFiles(x86)} "Inno Setup 6\ISCC.exe" } if (-not (Test-Path $iscc)) { throw "no Inno Setup found. Install it with: winget install JRSoftware.InnoSetup" } & $iscc "/DVersion=$version" "/DSource=$dist" "/DIcon=$icon" ` (Join-Path $root "packaging\dikte.iss") if ($LASTEXITCODE -ne 0) { throw "Inno Setup failed" } Write-Host "dist\Dikte-$version-x64-setup.exe"