Notes de version
Dernières mises à jour et améliorations de Songbook Buddy.
Version 1.0.26
September 12, 2026
1.0.26+4
September 12, 2026
A Linux-only repair build on top of 1.0.26+3. Nothing changes for macOS, Windows, Android or iOS — if the app starts for you today, this build has nothing new in it.
- The Linux download starts again on Ubuntu 22.04 LTS, Linux Mint 21.x and Debian 12. 1.0.26 stopped with
symbol lookup error: undefined symbol: g_once_init_enter_pointerand never showed a window. The app itself was fine; the machine that builds it simply has a newer GLib than those systems, and its headers quietly wrote that newer function into the program — the runner and eight plugins. The build now pins the GLib API to the version those systems ship, which is what every earlier release did before the build machine was upgraded.
Why this is the third repair of its kind, and what changed so there is no fourth. The same class of problem — the build machine raising the requirements without anyone asking it to — cost 1.0.24, 1.0.25 and 1.0.26. The pre-upload check that was supposed to catch it only asked whether every library exists and carries the right symbol versions; this function carries no version at all, so the check passed a build that could not start. It now also asks the loader to bind every symbol before shipping, and a release fails if a single one is missing. Measured against the published 1.0.26: silent before, nine files named after. On top of that, the build is now started on a real Ubuntu 22.04 userland and has to draw its window there before it can be uploaded.
1.0.26+3
September 12, 2026
A repair build on top of 1.0.26. It fixes one defect, and that defect destroys data, so it is worth installing even if 1.0.26 has been running fine for you.
- Interpreters no longer disappear from the library list — and the app no longer overwrites the stored one with a blank. On some libraries an interpreter would vanish from the Songs pane and come back the moment the song was opened, then vanish again later. Behind that was a repair that ran the wrong way round: when the app rebuilds a missing interpreter from the
{artist:}line in the song text, it queues that one column to be uploaded. If a sync brought the server's empty value back in the moment between queueing and uploading, the app sent the empty value — and marked it as the newest edit of that column. From then on the blank won against every later repair, so a song that could still have been healed became permanently blank. Measured against the live database on 12 September 2026, this had already happened to 16 songs across two accounts. Uploading an emptied column this way is now blocked outright: a repair the app performs on its own can only ever add an interpreter, never clear one. Clearing an interpreter yourself still works exactly as before.
What this build does and does not do: it stops any further damage. Songs whose interpreter was already overwritten with a blank keep their {artist:} line in the song text, so the value itself is not lost — those rows need a follow-up repair on our side, which happens once this build is out.
1.0.26+2
September 11, 2026
Interim build for the App Store submission of 1.0.26 — testers only, not published to the direct-download channel. It carries two fixes on top of the released 1.0.26, one of which only exists on the Mac App Store channel:
- The Mac App Store build no longer shares its library key with the direct-download app. The two Mac builds are separate apps with separate containers and separate libraries, but their E2EE key lived at the same keychain address:
CryptoServiceandKeypairServicesetuseDataProtectionKeyChain: false, so their items sit in the shared login keychain, addressed by service and account alone — the bundle id plays no part. Measured on 2026-09-11: the store build's first launch, with nobody signed in, removed the direct-download app's key, and that app asked for the library password again. The store build now carries its own namespace (SBB_STORAGE_NAMESPACE=mas), the way the beta flavor and the test-rig instances already did. The direct-download and iOS channels deliberately keep the unnamespaced address — moving them would be a key migration for every existing user. - A first-run tip no longer points at a control you cannot see. After ending the welcome tour, the one-time hint "Tap to switch between reading and editing this song" appeared over the upgrade screen on a brand-new install, with an empty library and no song open. The tip only checked whether its anchor could be measured, not whether it was visible; the song area stays mounted behind another tab, so the bubble was drawn over whatever was on top.
If you already installed the 1.0.26 store build: the first start of this one asks for your library password once. That is the namespace change taking effect, not a fault — nothing was deleted, and the key is derived from your password and email again.
1.0.26
September 9, 2026
Three weeks of device testing on top of 1.0.25: 271 commits, 69 reported problems closed, 5,026 automated tests, and a device pass across real Macs, an iPad, an Android tablet and a two-instance band rig. The headline work is a permanent transposition, section headings that speak the reader's language, and a setlist that starts correctly even when one of its songs is in the trash:
- Apply a transposition to the song for good. Press and hold (or right-click) the transpose controls in the status bar and pick "Apply transposition to the song…". Every chord is rewritten into the key you are playing, with the sharp/flat spelling shown on screen, and the transposition returns to zero; the capo can be folded in, and chord-diagram assignments follow the chords. One Undo in the editor takes the whole rewrite back — chords, key, offset and capo — and Redo brings it forward. The menu is offered only for the song's own transposition; one that came from a setlist or a band says so instead.
- Section headings are localised. VERSE, CHORUS, PRE-CHORUS, BRIDGE, INTRO, OUTRO, TAB and GRID were hard-coded English literals in two byte-identical switches (screen and PDF); both now read one value object, and the ARB carries the display form rather than a word the code upper-cases at render time —
String.toUpperCase()is locale-independent and would turn TurkishiintoI, and CJK and Devanagari have no upper form at all. A label the user typed is still printed verbatim. - Setlists: starting one steps over trashed songs. A setlist whose first entry pointed at a deleted song started into nothing and dropped the status-bar setlist row; it now opens the first live song, Next/Prev skip dead rows, and the row with its position and exit button stays. Next and Prev also continue from the song you started on instead of jumping to entry 1. A transposition made inside a solo setlist writes the setlist entry even for a song published in a band, where it used to land in a band overlay the solo setlist never reads.
- Band Mode: a live session shows up on every device. A device left on the Bands tab built the live-session provider in its first frame, before Supabase initialisation had published the client; the synchronous throw ended
build()as an error, the postgres-changes subscription never came up, and the instance stayed blind for the whole run — across restarts, because the tab is restored. It now waits for the client and rebuilds when it arrives. Alongside: a follower keeps following a leader who restarted (broadcast epoch), ending a session clears the leader's own panel instead of waiting for an echo that may never come, and a late joiner replays its snapshot in sequence order. - Send-only devices stop re-uploading everything every cycle. A send-only device has no pull, so nothing ever stamped its rows
synced; the stranded-row healer re-queued them every round as full rows withoutchanged_fields— no field-level merge, a freshupdated_at, plus a reorder call for every affected setlist. The push now stamps the local row itself, unless a newer un-acked outbox entry for the same row exists, so an edit made during a push keeps its pending state and goes out next cycle. - The key field accepts only a key, and the key reaches your other devices. Pressing Return wrote the typed value and the previous one back in the same instant; and with "Key, capo, transpose & play time live in their fields" on, a key set through the field never entered the sync outbox. Typing past a key ("EA", "AD") turned the text into the song's key and pushed it everywhere. One edit is now one write, an invalid entry is refused with a red frame and an explanatory tooltip, "am" is stored as "Am", and the key column goes through the outbox like the capo.
- The header names the key the chords are written in. A song without a stored key derived its displayed key from the de-duplicated chord list while the transposer read every occurrence, so a template song read "F" instead of "C"; header, sidebar and transposer now read the same list, and flat-spelled input yields Gb/Ebm rather than F#/D#m.
- Editor and parser. A mistyped directive is named in a footer with its line number while you type, instead of being dropped silently on save. A
{comment}between{soc}and{eoc}no longer closes the block early. A section directive's label is its heading in both the colon and thelabel="…"attribute form, and the attribute form survives saving and import.{sortartist:}survives and sorts. Returning to transpose 0 reaches the editor. - Theater and playback. Page-turn mode paginates real pages — a sheet of fixed size that ends where its content ends, with tabs, grids and comments counted, the page band covering both pages during a turn, and no sliced first turn. Single-tap page turning is a setting, shown only for the modes that turn pages. A sync cycle no longer resets the transport mid-performance, and a linked audio file reaching its end respects "Automatic scrollback".
- Interface scaling and colour theme. A 48 pt touch floor sat above every offered step (26 × 0.85 … 1.5 = 22.1 … 39), making the status bar a constant size rather than a scaled one, while half the same bar still stood on the raw 26; five files now read one set of metrics. The Songs filter row scales as one row. 110 call sites derive accent, border and the empty star from the chosen palette instead of a fixed sage and iOS grey; red/orange/gold stay semantic.
- Print and export. The run sheet builds its lines from the same observed query the setlist panels use, so a changed artist, title or key shows immediately instead of a session-old value. Both print dialogs distinguish a trashed song from a band song that has not arrived, and name the trash in a neutral notice instead of a red "no songs to export". Run sheets put position numbers outside the titles and the artist on its own line (a switch restores the inline form).
{ci:}prints italic. A ChordPro export round-trips transposition and play time. - Chord diagrams. "Assign to all" is reachable from a chord tapped above the lyrics, not only from the chord strip, and it clears per-occurrence overrides that would otherwise win. The diagram heading follows the chosen chord notation (German H/B, Nashville, solfège). The fret filter and the sign-in screen are localised.
- Reliability. Quitting closes the database cleanly — the close could abort on a
Concurrent modificationwhile a watch stream was torn down, leaving a-walfile and a crash report on the next launch; a background listener reading the database after close did the same. A manual sync aborted by the watchdog is reported as a sync error with thesynccategory rather than as a crash: Account → Sync now, the Settings button, the keyboard shortcut and the status-bar button all go through the sync engine now. A crash report carries the log around the incident instead of the following session's opening lines, and the recovered prior-session log keeps the incident's own category. - Linux. The bundle no longer ships copies of libraries the startup path already needs — the libmpv closure overlapped GTK's text stack in four files and the host builds shadowed the user's working ones, which is why 1.0.25 still failed to start on Mint 21. A pre-upload smoke test resolves the finished bundle inside a real Ubuntu 22.04 userland (bubblewrap, no sudo, no Docker, no display) and aborts the release instead of warning.
- Starter plan. Eleven actions in the middle of the Setlists tab — adding a song, reordering by drag, removing an entry — did nothing at all on the free plan; they now show the upgrade screen like the sidebar always did. Redeeming a connect code no longer reports success while the People tab stays empty for ever.
- Songs and library. PDF and image songs get a "Song details" dialog with Title and Artist, and the artist is what run sheets, the songbook contents and artist sorting use. The song list builds only what is on screen, no longer rests with empty space under the last row, and the key cache stops emptying itself above 1024 songs.
- Translations and help. All 23 locales caught up, including the sharing dialogs, "Start Setlist" and the collapsed theater pills, which were hard-coded English. The English help gained sections for the permanent transposition, the Song details dialog, the directive warning and the heading language; 23 manual PDFs rebuilt.
- Smaller fixes: the "Don't show this again" flag for the directive notice holds across a restart; the first ChordPro export of a session reads the key settings from disk; pixel sliders no longer offer 5 % snapping; the key detector resolves a tie in favour of the major key; the directive footer is no longer clipped to two lines; the locked synchronised preferences on a receive-only device explain themselves by tap as well as hover; support-report auto-tagging no longer lets the oldest catalogue pattern win blindly; the statistics digest takes a version as a cohort filter; and the screenshot pipeline gained three gates so a wrong frame cannot be published.
Version 1.0.25
August 31, 2026
A large release built out of three weeks of device testing: 507 commits since 1.0.24, 101 reported problems closed, verified by roughly 4,400 automated tests and 217 hands-on checks on real Macs, iPads, an Android tablet, a Windows machine and a Linux box. The password-change story is finished on the other devices, "receive only" turned into a working mirror, and these are the fixes that came out of the campaign:
- Your other devices notice a password change themselves. Detection used to hang on sign-in only, so a device that stayed signed in kept pulling rows it could not decrypt and said nothing — thousands of failed fields, no hint, no prompt. The sync cycle now recognises a rotated key, stops touching the encrypted tables and asks for the new password. A second lock in the same app run asks again instead of leaving a red icon and no way in.
- A password change is no longer rolled back by another device. While the re-encryption sweep runs the library is half rotated; a second device holding the old key pulled the half it could not read, held it back and pushed it up again under the old key. A stale local copy can no longer overwrite a newer server row.
- A password change signs out your other devices, and the dialog says so. This used to be offered as an opt-in checkbox whose hint promised that, left unticked, the other devices stay signed in. Measured on a live account on 2026-08-28 with the box off: the second machine was signed out within minutes and the account was left with one session. The server ends those sessions whatever the client asks for, so the control was inert and its sentence untrue — both are gone, replaced by a plain statement of what happens. Signing out also clears the encryption key, which used to survive the sign-out and be reloaded on the next launch.
- The password change checks its precondition before it asks. On a device with an incomplete local mirror the dialog opened, three fields were filled in and GoTrue changed the password — and only then did the sweep refuse. It now states the situation up front, with an explicit "change it anyway". The forgotten-password flow warns before sending the mail that a reset does not unlock the cloud library.
- "Receive only" is a mirror with temporary edits. A receive-only device still writes into the outbox, but every sync cycle resets those edits to the server's state: fetch the server's rows by id, drop never-pushed local creations, purge. First-edit notice, status-bar counter chip with a details sheet, reset notice with "Switch to manual". Four classes are locked instead of reset — song creation/import, synchronised preferences, band actions, permanent delete — including the band buttons themselves, which used to stay enabled and fail after the confirm dialog. Band content writes that bypassed the outbox entirely are refused. Switching direction offers "Keep and send" or "Discard". The refetch expands bulk entries into their row ids, and an offline abort marks the reset as waiting for a connection.
- End-to-end encryption reads a wrapped data key. The password-derived key now only encrypts the data key. Existing accounts were migrated at no cost, and no ciphertext was touched. Write support ships off (
kE2eeWrapWritesEnabled = false): this release reads and tolerates wraps, a password change still re-encrypts the library. Sheet blobs survive a rotation, the re-key sweep no longer strands rows, and the self-healer no longer rolls a sweep back. - Fonts get their own Preferences section, with missing bold/italic styles shown and individually re-fetchable — a failed cut used to render silently in the regular style. Intro/outro/lyrics/custom blocks now print with their own font settings, and emoji print monochrome instead of vanishing.
- The ChordPro parser and the editor agree again. A raw newline inside
{t:…}is not a title — the metadata extractor swallowed it while the tokenizer did not, so the sheet printed a lyric line while the song list mirrored a two-line title. Backslash line continuation (ChordPro 6.010) is implemented. The editor's highlighter no longer colours past what the tokenizer accepts: unclosed braces, mid-line#, open chord brackets.{socm}is a multi-line comment, not a lyrics synonym. - Wi-Fi sync answers instead of hanging. Peer search ends in a verdict, "Sync now" no longer requires a visible peer, transfer and write failures are explained and counted, a dead
synced_audiostore is probed every two minutes and named in the report footer, quitting withdraws the Bonjour announcement, and a peer that fails three times in a row is dropped. - Support reports carry what the questions actually need. A new Display/Print section (deltas only, capped) with font, display and print settings. Attachments upload rather than failing RLS, the 10 MB promise is enforced by the bucket, skipped files are named in one sentence, and a key rotation no longer floods the tail — repeating lines are collapsed instead of enumerated per field.
- Linux: the published zip starts on the oldest supported LTS base again — Ubuntu 22.04, Mint 21.x, Debian 12 (glibc 2.35 / GLIBCXX_3.4.30). 1.0.24 was built on a newer host whose headers silently raised the floor to 2.38, so it did not launch there at all. A pinned ABI floor header is pulled into every translation unit, a pre-upload check measures the finished bundle, and a bundled libmpv that cannot load now hands over to the system one instead of taking playback down with it.
- Band setlists no longer lose other members' rows. The reconcile pass took the server set as "songs owned by me" and deleted every entry contributed by someone else as an orphan — in both directions, silently, leaving the owner unable to add anything afterwards (position collision into the dead-letter queue).
- Sheet blobs: re-uploading a score no longer looks like a mismatch (ciphertext differs per encryption — the pointer is what is compared), a cloud object that was deleted reports "not on this device" instead of a failed download retried against a 404, and a discarded sweep hangs off the state rather than the upload branch.
- macOS keychain: an item owned by a differently-named bundle (
Songbook Buddy.appvs.SongbookBuddy.app) refused every delete with-25244, so a signed-out device kept handing the library key back. The app now rotates to a slot of its own, reportsstorage_cleared=falsehonestly, and the next sign-in writes an item it owns. The stale item stays behind and can be removed by hand. - Notices that carry an action disappear again. Flutter defaults such a SnackBar to
persist = true, which made itsdurationdead code — the two "receive only" hints stood indefinitely and their button led into Preferences rather than closing them. - Crash reporting: an unsent crash log is no longer evicted by newer sessions, a hard-killed session is recovered as a
crashrather than an ordinary log, a report deferred during a bad start is sent at the next healthy one, and acknowledging an incident no longer disarms the start that is still running. - macOS 12: Impeller is globally off (
FLTEnableImpeller=false) — its pipeline pre-compilation deadlocked in the Metal XPC compiler before the first frame, so the app never started. - Play Store / App Store:
.sbblsetlist import now counts against the Starter library cap. Content-identical songs merge for free, bundle-internally too; on overflow the user picks "import the first N" or cancels, and a fully blocked import gets the normal song-limit upsell. - Smaller fixes: iOS "Bold Text" no longer overrides the song display; touch line metrics match desktop (no +16 px); the footswitch hot path is a gate plus a set lookup with a key-storm counter; the shell reclaims orphaned focus after an iPad field commit; the DMX interface verdict is calibrated for iOS, where an empty enumeration proves nothing; an epoch-start pull saves a fresh cursor so the stale loop converges; an offline cycle ends at the first failure and says it once; hard delete clears local junction rows and the reconcile pass drops pre-existing orphans; a deleted chord fingering is no longer re-uploaded every cycle; the trash keeps the sheet plaintext and permanent delete clears file and bucket object; attachment paths are canonical POSIX rather than platform-dependent; quotes in the search field search exactly; the pinned insert sidebar is suppressed below the minimum editor width; the import-plan flow moved to the app shell with the wait spinner as a cancel route; PDF autoscroll re-measures after viewport changes; a missing sheet song shows the Wi-Fi route instead of an exception;
ConnectionClosedExceptionat quit counts as teardown noise; the song header is localised in both branches; the signed-out dialog can no longer become a dead end; the manual PDF renders blockquotes as hint blocks with real em dashes; the password-change progress dialog can no longer be dismissed, leaving progress and result invisible;ensure()returns only once the ready flag is actually set; 8 px of breathing room before the help block in Preferences; plus refreshed translations and rebuilt manuals for all 23 locales.
Version 1.0.24
August 23, 2026
A reliability release for stage output, sync convergence and the purchase flow, plus an in-app password change that keeps the encrypted library readable:
- Change your account password in the app (Preferences → Account → Advanced). The dialog takes the current password alongside the new one — GoTrue requires it even after a fresh sign-in — and states the policy up front. Because the E2EE key derives from the password, the change runs a full library re-encryption sweep (~93 s for 1301 songs, resumable, progress shown) and only then rotates the account's key fingerprint. Other devices are not signed out: they keep their session and need the new password before they can read anything written after the change. (Corrected 2026-08-23 — this note originally claimed a server-side sign-out with a prefilled banner. That was never implemented. From 1.0.25 the other devices notice the rotation themselves and ask for the new password.) A wrong password verifies before anything is persisted, so it changes nothing.
- Sheet PDFs: Windows scrolls freely instead of snapping page by page, autoscroll is driven by playing time on every viewer family, pinch-zoom works again on iOS/macOS, the raster viewer re-renders at zoom instead of scaling pixels, and a malformed PDF is rejected at import rather than crashing the app.
- Space controls playback again after editing a song's play time; the text field kept the focus scope and the shell shortcut never saw the key. On Windows a quit the OS ignored could leave the process alive behind the closing scrim — that now ends in a dead process.
- DMX / Art-Net leaves macOS and iOS devices again. Packets were sent to the catch-all 255.255.255.255 broadcast, which Darwin drops without a word, so nothing reached the fixtures however correct the setup looked. They now go to the network's own directed broadcast address, with an explicit interface binding.
- Discarding a failed sync item is final. The discard removed the dead-letter row that had exempted the record from the stranded-pending sweep, so the next sync re-queued the very mutation the user discarded, spent five more attempts on it and filed it again. The pending stamp is now cleared as part of the discard.
- Setlist position collisions converge. Two devices reordering one setlist could reach a collision that blocked that setlist's sync permanently, because recovery bypassed the reorder RPC. Both sides now converge instead.
- The reconcile scan paginates. It stopped at PostgREST's 1000-row cap, so any library larger than that was compared against a truncated set of server ids.
- A rotated end-to-end encryption key is detected and reported instead of surfacing as an opaque decrypt failure.
- Purchase and sign-in dead ends. "Secure your purchase" hung when GoTrue parked the new address in
new_email, and failed outright when that address already had an account; the sign-in escape hatch no longer offers a button the current channel does not have. Orphaned purchases now move onto the real account atomically, and Restore no longer gives up when a single App Store host is slow to answer. - Import: duplicates are now detected within a single import run, not only against the existing library, and an imported archive can no longer write outside its target folder (Zip-Slip guard).
- Smaller fixes: PDF-backed sheet songs open again on Windows, a restored backup bundle no longer keeps its file locked, database streams are fully closed on quit so the app cannot hang there, the delete tooltip names the trash, mDNS discovery for linked audio ends with the foreground, the import-plan heading is back in the English help, plus refreshed translations and rebuilt manuals for every locale.
Version 1.0.23
August 12, 2026
A sync-reliability release fixing a permanent resync loop and a false "library was repaired" prompt on wiped devices:
- Uploaded rows are no longer stored as
pending. The generic outbox push uploaded the full local row without stamping its sync status, sopending— the local marker for "still waiting to be pushed" — was written into the server copy and pulled straight back down. The row then looked stranded, the 1.0.21 stranded-row rescue re-queued it, and that local write scheduled the next sync: a self-sustaining loop that resynced hundreds of rows on a library nobody had touched (one report: 765 rows, four cycles in a row). Uploads now strip the server-managed columns and stampsyncedat the single choke point every full-row upload passes, and pulls assertsyncedon every row written locally, so the wedged state cannot be represented on the device whatever arrives from the server. Existing backlogs heal on the next pull with no migration, and because the push also repairs the stored server value, devices still running an older build stop looping without updating. - A device with no library is not "behind a library repair". "Wipe local database" deletes the device's library-generation marker along with everything else, and reading it back defaulted to generation 1 while the account's server generation stays where an earlier repair left it. "This device has no idea which generation it is on" was therefore indistinguishable from "this device is two generations behind", so every wiped or freshly installed device on a once-repaired account took the destructive catch-up path — prompting about unsynced changes an empty device cannot have, and on a send-only device raising a hard sync block it had no way to clear. A missing marker together with an empty library and an empty outbox is now recognised as a fresh device: it adopts the server generation and lets the ordinary full pull fetch the library. A library that has rows but no marker still gets the prompt, because those rows can genuinely be pushed at the wrong generation.
- Smaller fixes: the release publisher no longer aborts one channel's publish because a different, deliberately retired channel still lists deleted artifacts — asset checks are now scoped to the channel being published, and a channel marked unavailable is skipped entirely.
Version 1.0.22
August 12, 2026
A fix release for chord spelling, enharmonic chord diagrams, silent DMX output and a stuck macOS modifier:
- Transposed chords keep their scale degree. The tonic moves a fixed number of letter steps and every chord moves with it, so a D in a song in E now transposes to Bb in C rather than A#. Borrowed and diatonic chords are both spelled the way a chart spells them; where the degree-correct name would need a double accidental or one of B#/E#/Cb/Fb, the song's own preference decides instead.
- Both spellings of a note reach the same chord diagrams. Db and C#, Gb and F# were separate namespaces in the chord lookup, so one of each pair fell through to calculated shapes while 254 of 260 curated fingerings sat unused. Reads now match either spelling for guitar, ukulele, banjo and mandolin, existing user grips and synced rows are found without a rename, and duplicate twins are folded away.
- DMX output reports when it is being dropped. When the OS refuses the app's Art-Net datagrams, the DMX sidebar now shows a warning naming the likely cause (the "Local network" permission on iOS/macOS) instead of looking healthy while nothing reaches the fixtures. The automatic socket rebind now backs off exponentially (2 s → 60 s) rather than retrying every two seconds indefinitely, and resets on recovery or a new target address.
- macOS: a stale ⌘ modifier heals itself. A lost key-up from a native menu or sheet could leave Command permanently "held", turning every plain keystroke in the editor into its shortcut until the app was switched away and back. The keyboard state is now reconciled against the engine after native menu callbacks and after each shell shortcut fires, so at most one keystroke misfires before typing works again.
- Smaller fixes: support reports now record which modifier keys were held when a shortcut fired; the DMX rebind log pair is throttled so it no longer crowds the rest of the support log out of the tail; two macOS marketing-capture failures (an IFS leak and a first-launch Gatekeeper timeout) fixed in the build tooling.
Version 1.0.21
August 12, 2026
A reliability release: multi-device sync integrity, uninterrupted playback, and a working update check:
- Sync updates carry only the fields you changed. An edit on one device no longer overwrites unrelated fields edited on another — every update path in the library now reports per-field changes.
- Conflicts resolve by edit time, not upload time. An offline edit no longer loses to an older change that happened to reach the server later.
- Stuck syncs recover on their own. A hung network request no longer blocks sync until restart, queued changes stranded as "pending" are re-enqueued, and bulk edits carry their record IDs.
- Stable installs see updates again. The update check followed a channel preference that could point release installs at the beta feed and report "no update"; the channel now follows the build itself and the picker is gone.
- Playback keeps playing. Starting autoscroll no longer stops running audio, and a background plan re-check no longer tears playback down.
- Editor & import. A typed {duration: 3:45} survives the save path; the editor honours "Move field directives into controls"; the import dialog mirrors the typed title, artist and album live into the ChordPro preview.
- Smaller fixes: support-report logs are no longer flooded by DMX frame traffic; artist-metadata healing stays local instead of re-uploading on every open; the iOS upload's export-compliance declaration is fixed; help, manuals and screenshots refreshed across all 22 languages.
Version 1.0.20
July 23, 2026
Songbook Buddy's first public (non-beta) release: the four-plan licensing model introduced across the 1.0.19 beta line goes stable, with account-less purchasing.
- Four plans, hierarchical. Starter (free) · Basic (€7.99 one-time) · Pro (€29.99/year) · Pro Cloud (€79.99/year); each plan includes everything below it. The upgrade screen leads with your current plan and offers only the steps above it.
- Buy without an account. Unlock a plan with PayPal without first creating a Sync account; add an email and password afterwards to protect the purchase, restore it on another device, and turn on sync.
- Android direct download. A sideloadable Android build (its own applicationId and
songbookbuddy-directdeep-link scheme) is published from the website for the PayPal purchase path, installing alongside the Play Store build. - Printing. Songbook and setlist printing are Pro; single-song print stays Basic. Setlist portability:
.sbblexport (Pro) and import (free, merge), from the normal Import dialog. - Apple font collections on macOS. The font browser lists
.ttccollections (Avenir Next, Optima, Palatino …) for use in songs, print and PDF. - Smaller fixes: a plan change made on the server — a refund or an expiry — now reaches the running app within seconds instead of waiting for the next launch; after paying with PayPal the browser returns to the app on its own; refunds restore the year they bought, not just a pointer; every paid tier grants the permanent Basic floor; restrictions no longer fire on an unhydrated tier (no "Starter library full" flash for paying users); nine upsells no longer told paying users to buy what they already own; export/print default filenames keep non-ASCII characters; a corrupt local database self-heals on open; band-song decrypt recovery; device-identity convergence ends the solo-owner band-key ping-pong; refreshed help, manuals and screenshots in all supported languages.