The release binary dynamically links libwebkitgtk-6.0, which is not preinstalled on most distros and is not shipped in the tarball, so installs failed at first launch with a missing-.so error. Add a step-0 dependency stage to install_linux.sh that maps Arch/Debian-Ubuntu/Fedora/OpenMandriva/Void to their verified runtime package names (ID plus ID_LIKE, so derivatives resolve), requires root/sudo, and stays idempotent. musl systems (Alpine, Void-musl) get a warning plus hard-abort: the glibc-linked binary cannot run there and no package fixes that. Unknown distros get the package table and exit 1. Existing desktop/icons/binary steps untouched. Verified with an 11-case stub harness (all families route correctly; sudo/no-sudo/missing-manager/musl/unknown all behave).
Append one sentence to the V3_MIGRATION build record noting make release now bumps both wails.json and build/config.yml info.version (TEMP until wails.json retires). Keeps the migration doc from contradicting the automated flow; history above the line untouched.
make release only bumped wails.json, leaving build/config.yml info.version stale (it sat at 1.6.8 while wails.json moved to 1.99.0). Add a companion python one-liner that rewrites only the indented info.version line - the regex cannot match the top-level schema version 3 - and stage both files into the same bump commit. Marked TEMP until wails.json (v2 leftover) is retired. The companion NOTE in build/config.yml is updated to describe the automation and warn off the schema line. Verified with make -n dry-run and a scratch-copy regex proof (schema line byte-identical, single-line diff).
Source builders need the WebKitGTK 6 dev stack, which replaces the v2-era 4.x packages and is not preinstalled anywhere: give copy-paste distro commands (Arch/Debian-Ubuntu, names verified against the repos and the release workflow) plus the pinned wails3 CLI install. Same section records the version convention: 1.99.x is the v3-migration beta series (Wails v3 live, Svelte 4/Vite 4 refresh pending), 2.0.0 reserved for the finished article.
The release binary dynamically links libwebkitgtk-6.0 and libgtk-4, neither of which ships in the tarball or gets installed by install_linux.sh, and webkitgtk-6.0 is not preinstalled on most distros. Tell runners up front which runtime package to install (Arch/Debian-Ubuntu names verified) and what the missing-.so launch error looks like.
Relocate RefreshWatchListButton from the Home route into the WatchList header row beside Sort, so refresh lives with the list it refreshes. Tweak header styling to fit the new layout (text-nowrap on the button, max-h/margins on the sort select).
The Wails dev flow regenerates frontend/package.json.md5 (package.json change-detection hash) on every run, so it showed as untracked after each make dev. Scoped to frontend/; the tracked frontend/package-lock.json rule is unaffected.
WebKitGTK 6.0 removed WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND, so Wails maps OnDemand to ALWAYS. Never (the old Nvidia/X11 blank-window workaround) forces CPU raster on the GTK4/WebKit 6 stack. All target machines are AMD or Intel, where the Nvidia DMABUF workaround is unnecessary, so let the GPU handle scrolling/compositing.
The Future plans header (Not in this branch) read as if follow-up work were banned from wailsv3. Reword to Not yet done and give each item an explicit home: stabilization + toolchain majors stay on wailsv3, Android goes to a short-lived wailsv3-android feature branch so mobile scaffolding does not pollute the desktop-to-main merge, CI follow-ups live with whatever they support.
Task (used by wails3 via Taskfile.yml) stores incremental-build fingerprints under .task/checksum/. Purely local cache — hashes of sources/deps, machine-generated, recreated on next wails3 dev/build. Keep it out of git like node_modules/frontend/dist/build/bin (already ignored). No files were tracked; this just stops it showing as untracked on branches that have run wails3.
Add docs/V3_MIGRATION.md — a full write-up of the wailsv3 desktop migration (backend/frontend/build/CI changes, verification, branch map) and the planned follow-ups (toolchain majors + Android sideload). No behavior change.
Add a short notice to README.md: Migrating from v2 — v2 and v3 Secret Service collections coexist (AniTrack vs login) so both versions keep working after the first v3 re-login; the orphaned v2 entries are harmless. Details in docs/V3_MIGRATION.md. No cleanup instructions, by request.
Fixes the wails3 dev boot failure and removes remaining v2-isms so the tree matches a stock v3 project.
- frontend/package.json: add missing build:dev script (vite build --minify false --mode development). The dev taskflow runs npm run build:dev, which v2-era package.json never had - this was the wails3 dev boot failure.
- frontend/vite.config.ts: add the @wailsio/runtime vite plugin (typed custom events, as in every v3 template) and the server host/port/strictPort block (5173, matching the dev task).
- Remove stale v2 build dirs build/darwin + build/windows (v2 wails scaffolding; v3 generates its own via build-assets if ever needed).
- Delete untracked frontend/package.json.md5 (v2 change-detection artifact; v3 Taskfile uses content-hash sources) and drop its gitignore rule.
- go.mod: delete the leftover commented-out v2 replace directive.
- README.md: dev/build docs updated to make dev / make build (wails3), dropping the v2 :34115 browser-server paragraph; install link points at v3 docs.
Verified: production vite build green with the plugin, and wails3 dev boots end-to-end (bindings regen, build:dev, vite on :5173, asset server connected, AniTrack 1.6.8 window mapped).
Release flow (make build -> build/bin/AniTrack -> tarball) is unchanged; only the toolchain moves to v3.
- Wails CLI: v2@v2.15.0 -> wails3@v3.0.0-beta.20 (binary path, cache key, and install pin updated together).
- System deps: libgtk-3-dev/libwebkit2gtk-4.1-dev -> libgtk-4-dev/libwebkitgtk-6.0-dev for the v3 default GTK4/WebKit 6.0 stack.
- Unchanged and still valid: Go/npm/go-build/Wails-CLI caches (npm cache now resolves since the frontend lockfile is committed), environment.go generation, version guard, idempotent release+asset upload.
Desktop-Linux-only scaffolding adapted from the stock v3 svelte template; no mobile taskfiles added yet.
- Taskfile.yml (root): APP_NAME AniTrack, BIN_DIR build/bin (keeps the v2 output path so release packaging is untouched), includes common+linux only, build/run/dev tasks.
- build/Taskfile.yml: stock common tasks (frontend build, bindings regen, go mod tidy).
- build/linux/Taskfile.yml: stock, minus the common:generate:icons dep (it targets macOS/Windows icons from a build/appicon.png this project does not have; icons ship via build/icon + the release tarball). Generated build/linux/AniTrack.desktop committed (stable output).
- build/config.yml: AniTrack metadata, version 1.6.8. NOTE: ./release only bumps wails.json productVersion, not this file - bump both on release until the script learns about it.
- wails.json: v3 frontend block (dir/install/build/dev/devServerUrl :5173); author + info.productVersion kept for the in-app title and the release version guard.
- Makefile: wails dev/build -> wails3 dev -port 5173 / wails3 build. The v2 webkit2_41 tag is a v2-ism v3 ignores; v3 defaults to GTK4/WebKitGTK 6.0 (same 2.52.x engine generation), so no tags.
- .gitignore: task cache dir .task/ ignored.
Regenerated bindings with wails3 generate bindings (1 service, 29 methods, 25 models) into frontend/bindings/AniTrack as TypeScript; output verified byte-deterministic across regens, so it is committed like wailsjs was.
- 10 Svelte files: wailsjs/go/main/App imports -> import {App} from bindings/AniTrack with App.* call prefixes. No logic or markup changes.
- WebsiteLink.svelte: BrowserOpenURL -> Browser.OpenURL from @wailsio/runtime.
- AvatarMenu.svelte: runtime.Quit -> Application.Quit from @wailsio/runtime.
- package.json: add @wailsio/runtime pinned to 3.0.0-beta.20 (exact, matching the Go framework); lockfile updated, all deps still max in-range, majors deferred.
- Production vite build passes with the new bindings.
Minimal-structure migration to Wails v3.0.0-beta.20 (CLI-matching pin). Single App service preserved; no domain logic touched.
- main.go: wails.Run(options.App) -> application.New + RegisterService + Window.NewWithOptions. Window keeps title-with-version, 1024x768, RGBA background, Linux icon/translucency/GpuPolicyNever, ProgramName. SingleInstanceLock -> SingleInstanceOptions (same UniqueID); callback closes over the service variable set right after New.
- app.go: App holds *application.App instead of a context. startup(ctx) is gone; the version title moves into the window options via appTitle(). onSecondInstanceLaunch takes v3 SecondInstanceData (Args/WorkingDir) and uses Window.Current() Restore+Focus plus Event.Emit for launchArgs. ShowVersion uses Dialog.Info.
- AniList/MAL/Simkl *UserFunctions.go: runtime.BrowserOpenURL -> app.Browser.OpenURL (errors logged), runtime.MessageDialog -> app.Dialog.Info chains. OAuth callback servers, token flows, and key names unchanged.
- Secrets: 99designs/keyring replaced with zalando/go-keyring (what v3 itself depends on) under the same AniTrack service name, so existing stored tokens keep working. Per-file Set helpers kept; Open/Ready boilerplate deleted (zalando needs no handle).
- go.mod: v2 + 99designs dropped (stale v2 replace directive removed), v3 beta.20 + zalando v0.2.8 added.
The blanket package-lock.json gitignore rule meant the frontend lockfile was never committed, so every release installed whatever the registry handed it (silent transitive drift) and setup-node npm caching failed outright with unable to cache dependencies. Scope the ignore rule to the repo root (/package-lock.json; no root package.json exists) and commit the freshly updated frontend lockfile: all deps at max in-range versions (autoprefixer 10.5.6 -> 10.6.0), majors intentionally deferred to the v3 frontend refresh. Verified with a green vite build before committing.
Release runs were fully cold every time: ~13s npm install, ~39s full cgo/WebKit compile, and ~34s rebuilding the Wails CLI from source on each tag. Now that the runner cache backend is reachable again, persist all three across runs. Expected total drops from ~3.5 min toward ~2.5 min with apt as the remaining floor.
- Set up Node: cache npm keyed on frontend/package-lock.json, so the npm install inside wails build stops fetching cold
- New Cache Go build cache step: setup-go only persists modules (GOMODCACHE); this persists compiled packages (GOCACHE) with a go.sum-hashed key plus a version-prefix restore-key fallback, turning the WebKit compile incremental from the second run on
- Wails CLI: split install into cache (key wails-v2.15.0-Linux, bump with the version pin), conditional go install on miss, and an unconditional PATH step so cache hits still land on PATH
First run after this still compiles cold (it saves); the payoff shows from the second run on. Verify with the throwaway-tag loop and compare Build Linux binary times.
The migration plan belongs to the wailsv3 branch, not main. It was merged forward into wailsv3 (now at origin/wailsv3) before this revert, so no content is lost. Main keeps only the v2 keyring error-handling fix.
Skimmable phased plan for getting AniTrack onto Android for personal
sideload use (no Play Store, no official F-Droid). Written for both the
maintainer and as working context for AI-assisted implementation.
Covers: desktop v3 parity as a mechanical step (main.go, runtime call
mapping, wailsjs import rewrite), per-file Android storage shims
(keyring on desktop vs EncryptedSharedPreferences via
Android.Secure*), the localhost :6734 to anitrack:// deep-link OAuth
redesign with per-provider dashboard changes, and the sideload run/
package commands plus Obtainium updates. Includes guardrails: small
diffs, per-service file ownership, build-tagged platform files only,
runnable check per phase, and open decisions (first provider, desktop
parallel builds, redirect URI registration).
Stop ignoring keyring.Open failures in all three login files. A failed
Open previously left a nil ring behind the blank identifier, so the next
Get/Set panicked with no message. Each service now opens its ring in
init, logs a service-prefixed warning when storage is unavailable, and
guards every use with a Ready check that fails safe to logged-out.
- AniListUserFunctions.go: add aniRingReady/aniRingSet helpers, log
Open and per-key Set failures, reject invalid ExpiresIn instead of
silently storing 0, clear in-memory JWT on logout even when storage
is missing
- MALUserFunctions.go: add malRingReady/malRingSet helpers covering
login, OAuth callback, and token-refresh saves; same Open/Set/
ExpiresIn/logout treatment
- SimklUserFunctions.go: add simklRingReady/simklRingSet helpers;
same Open/Set/logout treatment
No wallet, key names, or login flow changed. Same ServiceName
AniTrack, same keys, same OAuth callback behavior.
Local flow is now ./release 1.6.7 (or make release VERSION=1.6.7):
bump wails.json productVersion, commit the bump, generate git-cliff
notes into an annotated plain-version tag, and push commit plus tag.
The tag push fires the new Gitea Actions workflow.
- cliff.toml: git-cliff groups matching Bookhoard, tag_pattern for
plain versions so --latest scopes correctly.
- Makefile release target: strict plain-semver validation, dirty-tree
and existing-tag guards, python3 wails.json bump committed as
chore(release), throwaway-tag notes generation, push of main + tag.
- release: wrapper normalizing v/AniTrack- prefixes to plain versions.
- .gitea/workflows/release.yml: version guard (wails.json vs tag,
base-match for -suffix pre-releases), Go 1.25 / Node 20 / Wails
v2.15.0 + webkit2_41 system deps, environment.go from Actions
secrets, make build, AniTrack-<version>.tar.gz packaged from
build/ (bin, icon, desktop, install script, README), idempotent
Release create/update named AniTrack-<version> with archive
attached via REGISTRY_TOKEN PAT.
AniListSearch hardcoded false for the authenticated flag to
AniListQuery, forcing anonymous searches even with a valid AniList
session. Pass a.CheckIfAniListLoggedIn() instead so the stored token
is attached when available, enabling user-specific data and
authenticated rate limits while keeping anonymous search as fallback.
In CheckIfMyAnimeListLoggedIn and MyAnimeListLogin the keyring lookups
assigned MyAnimeListAccessToken to refreshToken and
MyAnimeListRefreshToken to accessToken. Downstream code checks
len(accessToken.Data) for login state and assigns
accessToken.Data -> myAnimeListJwt.AccessToken, so the swap gated
login on the refresh token and stored each token in the wrong field.
Swap the variable names to match their keyring keys so login detection,
JWT restoration, and the empty-token fallback in MyAnimeListLogin use
the correct values.
The search dropdown toggled blindly before the async call settled
and only handled success, so API failures left a blank dropdown
that looked like search did nothing.
- Replace toggle with explicit open/close, Escape and outside-click
to dismiss, and disabled search button while a request is in flight
- Add isSearching/searchError/hasSearched states: loading text,
failure panel with message plus Retry, empty prompt, and a
no-results message for the searched term
- Guard null coverImage/title with a romaji/native fallback and a
keyed each block; ignore stale late responses via request ids
- Tolerate slow AniList days: slow notice at 8s, 30s Promise.race
fail-safe (backend allows 20s), and an immediate offline message
via navigator.onLine so the UI never spins indefinitely
AniListQuery previously ignored json.Marshal/http.NewRequest errors,
logged the wrong variable on client.Do failure, and dereferenced a
nil response body, which could panic and leave callers hanging.
- Return early with user-safe messages on encode/request failures
- Add 20s http.Client timeout and nil guards for res/res.Body
- Keep logs generic so no auth material is ever printed
- Add aniListGraphQLErrorMessage/aniListSearchStatusError helpers
mapping 429 to a rate-limit retry message, 5xx to a temporary
outage message, and GraphQL errors[] (even on HTTP 200) to a
surfaced message
- AniListSearch rejects empty bodies and unparseable payloads with
actionable errors instead of failing silently downstream
The 1.6.1 fix exposed a latent decoding bug: AniList returns
airingSchedule.nodes and relations.nodes as arrays, but the Go Media
struct declared Nodes as single structs. Every full-media response
failed json.Unmarshal partway through - the update path turned that
into a rejected promise which skipped the MAL and Simkl syncs and all
table updates, while page loads silently continued with partially
decoded data (the reason the old tags/genres copy workaround existed).
- Media.AiringSchedule.Nodes is now []AiringScheduleNode and
Media.Relations is an exported []MediaRelation (previously an
unexported field silently dropped by encoding/json); title and
fuzzy-date sub-structs promoted to named types.
- Regenerate wailsjs models for the new shapes.
- Anime.svelte: handleSubmit and deleteEntries now wrap each service
in its own try/catch surfaced via setApiError/ErrorModal, so one
service failing can no longer skip the others; removed the obsolete
tags/genres copy workaround.
- AniListUpdateEntry/AniListDeleteEntry log HTTP status and response
body on failure for terminal diagnostics.
Bump productVersion to 1.6.2.
The AniListUpdateEntry mutation was mangled in 54c109a when the
standardized media field block was pasted in without the media { }
wrapper: media-level fields (idMal, title, ...) sat directly on
SaveMediaListEntry (which returns MediaList), the MediaList fields
(status, startedAt, ..., user) ended up at the Mutation root, and a
stray closing brace made the document a guaranteed 400. Because the
response status was discarded, the frontend received a zeroed
AniListGetSingleAnime and blanked the anime page after every submit,
making AniList appear logged out (and the change was never saved).
- Restore the mutation to match the tested bruno request: id/mediaId/
userId, standard media block inside media { }, MediaList fields
inside the selection, balanced braces.
- AniListUpdateEntry and AniListDeleteEntry now return an error on
403/non-200/unparseable responses (mirroring
GetAniListUserWatchingList) instead of silently returning zero
values.
- Anime.svelte guards against replacing the page data with an empty
response and raises the API error modal instead.
Bump productVersion to 1.6.1.
When the app starts it verifies all three services sequentially, which
could leave the other two login controls looking idle or trigger login
actions before their real state is known. Track which service is
currently being checked and reflect it in the header:
- Add a serviceLoggingIn store (plus setServiceLoggingIn and
isServiceLoggingIn helpers) to GlobalVariablesAndHelperFunctions.
- Have the loginTo* functions and the startup CheckIf* functions toggle
their service in the store (seed all three at startup, clear each as
it resolves).
- In Header, the login buttons show a spinner with 'Checking AniList' /
'Checking MAL' / 'Checking Simkl' and are disabled while that service
is being checked, reverting to the normal 'AniList Login' style label
once its state is known.
- In the avatar menu, the 'Login to X' row shows a spinner with the
matching 'Checking X' text while that service is logging in.
Two MAL login issues were caused by the refresh path being conflated
with the full browser OAuth flow:
1. A spurious 'It is now safe to close your browser tab' dialog was
shown after a *silent* background token refresh, even though the
browser was never opened. The dialog now belongs only to the
browser-callback handler (handleMyAnimeListCallback); the refresh
raises no dialog.
2. When both the access token and the refresh token were invalid, the
app reported MAL as logged in without a username. Now, if a refresh
fails (HttpClient error, non-2xx, or an empty access token), the
stale tokens are cleared and a fresh browser OAuth login is
automatically initiated instead of silently returning an empty user.
refreshMyAnimeListAuthorizationToken now returns a bool indicating
whether a fresh access token was actually obtained, letting
GetMyAnimeListLoggedInUser decide between retrying with the refreshed
token or falling back to a full re-login.
Ignore compiled binaries and packaging archives that are generated
during a build, without hiding tracked build source files:
- build/bin: the compiled application binary
- *.tar / *.tar.gz: packaging archives (e.g. Wails .ptmp temp dirs)
- /AniTrack: the root app binary (fix the previous './AniTrack'
pattern, which gitignore did not match)
Re-run the Wails binding generator so the frontend reflects the browse
Go types that were added in earlier commits (AniListBrowse plus the
Media / MediaList model refinements):
- App.d.ts / App.js: expose the new AniListBrowse() method
- models.ts: add the Media model, the anonymous tags element type,
and type MediaList.media as Media instead of a generic object
Reinstall the Go toolchain and rebuild wails against v2.15.0, then run
'go mod tidy' to update the dependency graph:
- github.com/wailsapp/wails/v2 v2.12.0 -> v2.15.0
- golang.org/x/crypto v0.52.0 -> v0.53.0
- golang.org/x/net v0.55.0 -> v0.56.0
- golang.org/x/sys v0.45.0 -> v0.46.0
- golang.org/x/term v0.43.0 -> v0.44.0
- golang.org/x/text v0.37.0 -> v0.39.0
The regenerated Wails runtime bindings (runtime.d.ts / runtime.js) are
included as they surface new APIs shipped in v2.15: the cross-platform
notification API (InitializeNotifications, SendNotification, etc.) and
the EventsOffAll event helper.
- Bump Go toolchain from 1.24.0 to 1.25.0
- Upgrade Wails from v2.10.1 to v2.12.0
- Upgrade tidwall/gjson from v1.18.0 to v1.19.0
- Upgrade labstack/echo from v4.13.3 to v4.15.2
- Upgrade labstack/gommon from v0.4.2 to v0.5.0
- Upgrade samber/lo from v1.49.1 to v1.53.0
- Upgrade gorilla/websocket to v1.5.3 (new transitive dep)
- Upgrade go-webview2 from v1.0.19 to v1.0.23
- Upgrade danieljoos/wincred from v1.2.2 to v1.2.3
- Upgrade godbus/dbus/v5 from v5.1.0 to v5.2.2
- Upgrade jchv/go-winloader to latest
- Upgrade mattn/go-isatty from v0.0.20 to v0.0.22
- Upgrade tidwall/match from v1.1.1 to v1.2.0
- Upgrade golang.org/x/crypto, net, sys, term to latest
- Add go-toast/v2 as new transitive dependency from Wails
- Fix tilde expansion: replace quoted '~' paths with $HOME so they
actually resolve to the user's home directory instead of being
treated literally
- Add existence checks before copying files so the script is
idempotent and skips already-installed resources
- Add progress/status echo messages for each installation step
so the user can see what is being done
The project's compiled binary (AniTrack) was not covered by existing
gitignore patterns. Only platform-specific extensions like .exe, .dll,
.so, and .dylib were ignored. Add the bare binary name to prevent the
locally-built executable from appearing as an untracked file.
Auto-generated by wails generate module. The FlexString custom type
produces unconventional namespace names in the generated TypeScript but
does not affect runtime behavior.