Skip to content

Releases: revtex/offstream

Release list

Offstream 0.1.0

Choose a tag to compare

@github-actions github-actions released this 15 Aug 04:07
4bd7761

Install it with Offstream-0.1.0-setup.exe — a per-user install that never asks
for administrator rights — or take the zip and run it from wherever you unpack it.
Both hold the same build.

This build is not code-signed. Windows SmartScreen will warn the first time you
run it: choose More info and then Run anyway. Verify the download against its
SHA-256 below before you do.

VB-CABLE is not included. Offstream detects it and tells you if it is missing;
install it yourself from https://vb-audio.com/Cable/ if you want to record Spotify
alone rather than everything the machine plays.

ffmpeg n8.1.2-40-g852b0552f0 is included (LGPL-3.0-or-later), unmodified and run as a
separate process. Its source is attached to this release as required, and its licence
travels in the ffmpeg folder beside it.

99253ab73bca124cdec71a9fc2fe4a66d1dbb3ac90217742953dfdf9530fdea2  Offstream-0.1.0-setup.exe
7beafde656b7050c2436a9318d66b8272625a6cd4a329548f20b714ae71b463a  Offstream-0.1.0-win-x64.zip

The first release. Everything below is the whole of Offstream rather than a change to it:
phases 0–8 of docs/MODERNIZATION-PLAN.md, from the .NET 10 retarget through to a per-user
installer.

Added

  • The licences are readable from inside the app, not just present as files in the folder.
    "Licence and notices" on the Advanced page's Application section opens Offstream's own MIT
    licence, the predecessor's copyright notice it carries, the bundled LGPL ffmpeg and its source
    offer, TagLib#, and VB-CABLE's origin and donationware terms — with the running build's version
    and commit at the top, so a bug report can name the build it came from. The text is embedded in
    the executable rather than read from beside it: the MIT and LGPL notices are obliged to travel
    with the software, and a loose file does not survive a zip unpacked selectively or a copy of just
    the .exe. A test asserts the window still shows what LICENSE and NOTICE actually say, so the
    two cannot drift.

  • Credit for the track details, beside the provider that supplies them. Choosing Spotify or
    Last.fm now says whose data is being written into the recordings — an attribution Spotify's
    Developer Terms require and that the app had never carried anywhere. It is empty when no provider
    is selected, because crediting a service the app is not calling would be a false statement.

  • The Settings page names which Spotify account is signed in, as display name and account id
    — not just that one exists. Recordings go untagged when the signed-in account is not the one
    the music plays on, and nothing on screen says which it is, so the only way to find out was to
    read the logs. Costs one scope, user-read-private. The id is there because a display name is
    not an identifier: two accounts can share one, and telling exactly those apart is what this is
    for. user-read-email would be the obvious way to do that and is deliberately not requested —
    Spotify removed the email field in its late-2024 cull, so that permission now covers data the
    endpoint no longer returns.

  • A release pipeline, with the git tag as the only place a version number lives. Pushing v1.2.3
    builds, tests, publishes, signs and attaches a self-contained win-x64 zip and its SHA-256 to a
    GitHub release; the changelog becomes the release notes. Nothing in the repository records a
    released version, so a build cannot claim a number the tag disagrees with — a file that has to be
    bumped in lockstep with a tag is a file that eventually is not. A malformed tag is rejected before
    anything is built, because a tag stops being editable the moment anyone fetches it, and a
    prerelease suffix (v1.2.3-rc.1) marks the GitHub release as one so it does not become what
    "latest" resolves to. Unreleased builds call themselves 0.1.0-dev rather than borrowing the last
    release's number, which is what turns "which build is this?" into a question with an answer. The
    same workflow runs from the Actions tab to exercise the pipeline without spending a version.
    Cutting a release is two steps — close ## [Unreleased] into ## [1.2.3] in a pull request, then
    tag — and a tag with no matching section fails in seconds rather than at the end of the pipeline.
    Falling back to [Unreleased] would have worked exactly once, and every release after that would
    republish the previous one's entries with no fix short of amending a release people had read.

  • A per-user installer that never asks for administrator rights. Offstream needs no elevation to
    run — routing, session mute and loopback capture were all verified unelevated — so the thing that
    installs it asks for none either. An elevation prompt is a decision the user has to make about
    software they have not run yet. It installs into %LOCALAPPDATA%\Programs\Offstream, refuses
    anything below Windows 11 with a sentence during setup rather than a crash on first run, notices a
    running copy through the app's own single-instance mutex instead of failing halfway through
    replacing a locked file, and is offered in English and French to match the app.
    It is built from the same staged folder the portable zip is made from, so the two downloads
    cannot hold different software under one version number, and the installer script is compiled on
    every pull request — one that is only compiled when a tag is pushed is one that breaks when a tag
    is pushed.
    Uninstalling asks about settings and logs rather than guessing. Deleting them silently loses a
    Last.fm API key and a Spotify sign-in; keeping them silently is wrong for someone uninstalling
    because they are done. Recordings are never in scope: they live outside the install folder and no
    uninstaller should reach them.

  • ffmpeg travels with the app. Releases carry an unmodified LGPL-3.0 build of ffmpeg in an
    ffmpeg folder beside the executable, which is where the locator already looked, so a download
    records audio without the user installing anything first. A copy on PATH, or one named on the
    Settings page, still wins — bundling is a floor, not a preference. It costs about 45 MB of the
    download, which is the price of the app working when it is opened.
    The build is pinned by SHA-256, not fetched by name from a moving tag: an encoder that changes
    between two builds of the same Offstream version turns a reproducible bug into an unreproducible
    one, and a release asset can be replaced after the fact. A mismatch fails the release rather than
    quietly shipping something else. The binaries are not committed — 108 MB of someone else's build
    does not belong in a git history — so build/windows/ffmpeg.json records what to fetch and
    fetch-ffmpeg.ps1 fetches it, for the pipeline and for build.ps1 -Publish -BundleFfmpeg alike.
    Only ffmpeg.exe ships; ffprobe is used by the integration tests and by nothing in the app, and
    would have added another 108 MB.
    The LGPL obligation is met by attaching the source, not by offering it. Every release carries
    the FFmpeg source archive for the exact commit the binary was built from, because a written offer
    has to outlive whatever was going to host it and this one does not have to. The bundle also carries
    ffmpeg's own licence text and a SOURCE.txt naming that commit, and the vendor binary is never
    re-signed or otherwise altered on its way in.

  • Signing, wired and waiting. build/windows/sign.ps1 Authenticode-signs whatever it is given,
    and when no certificate is configured it says so and exits 0 rather than failing the build.
    Offstream has no certificate yet, so every artefact is currently unsigned and Windows SmartScreen
    will warn on first run
    — the release notes say this outright instead of letting users find out,
    and ship a SHA-256 as the only integrity check available in the meantime. Building the step now
    means acquiring a certificate later is two repository secrets rather than a pipeline change, and it
    gets reviewed while nothing depends on it. Timestamping is on by default: without it every
    signature stops verifying the day the certificate expires, including on copies installed years
    earlier.

  • A security policy, and the reporting channel it points at. SECURITY.md says where to send a
    vulnerability and what the app actually handles that is worth attention — track metadata being
    untrusted input that reaches ffmpeg arguments and file paths, the PKCE sign-in, DPAPI token
    storage, and the hand-marshalled COM interop — along with what is deliberate, such as the Last.fm
    key sitting in plain text next to a DPAPI-protected refresh token. Private vulnerability
    reporting, Dependabot alerts and security updates, and secret scanning with push protection are
    enabled on the repository, so a reporter has somewhere private to go and a committed credential
    is refused at push time rather than found later.

  • CodeQL code scanning on pushes to main, on pull requests, and weekly, over C#, the workflows
    themselves and the one Python script. It runs on Ubuntu with build-mode: none: the analysis
    reads C# without compiling it, which is what makes scanning a Windows-only WPF app on a Linux
    runner possible at all.

  • Solution scaffold on .NET 10. SDK-style projects (Offstream.Core, Offstream.App,
    Offstream.Core.Tests, Offstream.UI.Tests, Offstream.FakeSpotify) under an .slnx
    solution, central package management, nullable reference types, and analyzers as errors.

  • GitHub Actions CI on windows-latest: build, dotnet format --verify-no-changes,
    analyzers as errors, and the test suite with ffmpeg pinned. A parallel job fails any pull
    request that does not update this file, since a stale changelog reads as a current one; a
    user-invisible change skip...

Read more