Skip to content

Track a game from the game database; one folder, one game - #73

Merged
Omar-VF merged 1 commit into
Liquid-co:dev-publicfrom
ChakraFusion:pr/track-game-standalone
Oct 16, 2026
Merged

Omar-VF merged 1 commit into
Liquid-co:dev-publicfrom
ChakraFusion:pr/track-game-standalone

Conversation

@ChakraFusion

Copy link
Copy Markdown

Item 13 from #21, rebuilt on dev-public without save versions or the rest of the draft stack (#35 depends on them).

Why. A folder tracked by hand only gets the name typed for it: no App ID, so no cover art and no launching. And nothing stopped a second entry for a folder inside one already tracked. Tracking Escape From Duckov from the game database put a second game on …\TeamSoda\Duckov\Saves, inside the folder an entry called "Duckov" already tracked. The same files were then watched, snapshotted and synced twice, under two games.

What changes:

  • A "Track game" button beside "Track folder" on Home. It finds a game in the game database (the Ludusavi manifest index OpenSave already ships and downloads) in one of three ways:

    • by name;
    • by its program: the Steam install folder the program is in, or a folder above it named as the game's install folder, compared without spaces (the database writes "ProjectZomboid");
    • by a save folder: the game whose save location is that folder, holds it, or is held by it.

    The game is tracked with the database's name and App ID, its program, and a save location the database knows on this device.

  • "Track folder" recognises the folder the same way and tracks it with the game's name and App ID ("Recognised as …").

  • One folder, one game. TrackGame refuses a folder inside a tracked game's folder, or one holding it, and names that game. The exact same folder keeps its existing refusal, and moving a game's own folder is not affected.

  • Already tracked under another entry. If the game picked is already tracked here, by App ID or by a folder that is, holds or is held by one of its save locations, the dialog says so. Instead of tracking it twice, it offers to link that entry: the existing PATCH /api/games/{id} gives it the database's name, App ID and program.

Backend:

  • presets/gamedb.go:
    • a GameDB lookup over the manifest index, reusing the scanner's own template expansion, Proton prefixes, blocked roots and install-base candidates;
    • Search, IdentifyProgram and IdentifyFolder.
  • daemon/gamedb.go and two read-only routes: GET /api/gamedb/search?q= and GET /api/gamedb/identify?path=.
  • store.PathsNest: two folders one inside the other, but not the same folder. It sits beside PathsOverlap and compares paths the same way.

Left out on purpose, so this stands on dev-public alone. On my fork these build on other parts of the draft stack:

Translations: all new text goes through $t. I added the zh-CN strings myself, since the catalog test requires every key; @Janlhin, please correct them if anything reads oddly.

Tests:

  • TestGameDB_FindsGamesByNameFolderAndProgram: search, folder (same, inside, one level up), program by install-folder name, and no match for unrelated paths.
  • TestTrackGame_RefusesAFolderInsideAnother:
    • a folder holding a tracked game's is refused, and so is one inside it, each naming the game;
    • the same folder keeps the usual refusal;
    • an unrelated folder is tracked.
    • With the check removed it fails on both nested cases.
  • TestMarkTracked_NamesTheEntryAGameIsAlready: by folder, by App ID, and not for an unrelated game.
  • Suites: the full Go unit and e2e suites pass locally. Frontend: 309 tests pass and the build is clean.
  • Fork CI: green on the second attempt. The first failed one Windows shard on TestIgnored_ASaveFromTheCloudLeavesAnIgnoredFileAlone (failed twice before on branches without this change) and TestIgnore_AppliesToExtraLocationsToo (first time I've seen it; it tracks one plain folder per device and adds its extra location through /roots, which this PR doesn't touch, and both pass 10/10 locally with this branch). If the second shows up again, e2e: every failing test prints its daemons' logs #57's logs will say why.
  • Not checked by hand: I haven't clicked through the new dialog in the app on dev-public. The fork's version of it (with the parts left out above) is in my test builds, which I run on four PCs.

🤖 Generated with Claude Code

A folder tracked by hand got only the name typed for it: no App ID, so no
cover art and no launching. And nothing stopped a second entry for a folder
inside one already tracked: tracking Escape From Duckov from the game
database put a second game on ...\TeamSoda\Duckov\Saves, inside the folder
an entry named "Duckov" tracked, and the same files were watched,
snapshotted and synced twice.

- "Track game" beside "Track folder" on Home finds a game in the game
  database (the Ludusavi manifest index) by name, by its program (the Steam
  install folder it is in, or a folder above it named as the game's install
  folder, compared without spaces), or by a save folder (the game whose save
  location it is, holds, or is held by). It is tracked with the database's
  name, App ID, its program and a save location known on this device
  (presets/gamedb.go; GET /api/gamedb/search and /api/gamedb/identify).
- "Track folder" recognises the folder the same way ("Recognised as ...").
- TrackGame refuses a folder inside a tracked game's folder, or holding
  one, and names that game (store.PathsNest). The very same folder keeps
  its existing refusal.
- A game picked that is tracked already here, by App ID or by an
  overlapping folder, is offered to link that entry instead (the existing
  PATCH /api/games/{id}), not to track the same files twice.

New text goes through i18n, in en and zh-CN.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 15, 2026

Copy link
Copy Markdown

@ChakraFusion is attempting to deploy a commit to the sivadaboi's projects Team on Vercel.

A member of the Team first needs to authorize it.

@Janlhin

Janlhin commented Oct 16, 2026

Copy link
Copy Markdown

Hi ChakraFusion— the full i18n extraction for OpenSave is done: three catalogs (en / zh-Hans / zh-Hant, 1328 keys), every window UI extracted to keys, including the lib-layer dynamic text (time formats, activity descriptions, notifications, sort names, appearance options). npm test 310/310, clean build, and the two runtime crashes introduced along the way (TransfersPanel alias leftovers, a timeline crash on missing timestamps) are fixed and verified.

Feel free to take anything you need from the feat/i18n-full-coverage branch — it's self-contained and builds standalone. I'll be pushing PRs to upstream (dev-public) view by view; if anything overlaps with your work, ping me and let's coordinate.

@ChakraFusion

Copy link
Copy Markdown
Author

Thanks @Janlhin, that's a big piece of work, and good to know before more UI lands.

Where our work touches yours:

When your view-by-view PRs are up, I'll rebase onto them rather than ask you to adjust.

ChakraFusion added a commit to ChakraFusion/OpenSave that referenced this pull request Oct 16, 2026
The phase names, the "{done} of {total}" line and the time left were English
strings in lib/restoreprogress.js. They are restoreProgress.* keys now, the
minutes a plural, and restoreProgressText takes the caller's $t, so the line
in the game header follows a change of language mid-restore. As asked on Liquid-co#73.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ChakraFusion added a commit to ChakraFusion/OpenSave that referenced this pull request Oct 16, 2026
…(en + zh-CN)

How a device is reached, its measured speed and the tooltip on why that
matters were English strings in Devices.svelte. They are devices.link* keys
now, and linkLabel takes $t so the line follows a change of language. As
asked on Liquid-co#73.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ChakraFusion

Copy link
Copy Markdown
Author

Following up on the two I mentioned: both are done.

Both PRs add the keys to en.json and zh-CN.json. When your zh-Hans / zh-Hant split lands, I'll move them across on my side.

@Omar-VF
Omar-VF merged commit fd18901 into Liquid-co:dev-public Oct 16, 2026
10 of 11 checks passed
ChakraFusion added a commit to ChakraFusion/OpenSave that referenced this pull request Oct 16, 2026
The phase names, the "{done} of {total}" line and the time left were English
strings in lib/restoreprogress.js. They are restoreProgress.* keys now, the
minutes a plural, and restoreProgressText takes the caller's $t, so the line
in the game header follows a change of language mid-restore. As asked on Liquid-co#73.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Janlhin pushed a commit to Janlhin/OpenSave that referenced this pull request Oct 16, 2026
Review pass on the ported keys:
- unify save-folder term (存档文件夹 / 存檔資料夾) in noSavesYet
- unify program term (游戏程序 / 遊戲程式) with chooseProgram/programDialog
- align noSavesHere / noSavesYet phrasing (没有找到它的存档)
- theGame: 该游戏 -> 这款游戏 (more natural inline)
- already: 请改为将该条目关联到 -> 请把该条目关联到
- rename home.trackGameTitle -> home.trackGameHint (it is the button's
  hint text, not a title; the dialog title is home.findGame.title)
ChakraFusion added a commit to ChakraFusion/OpenSave that referenced this pull request Oct 16, 2026
…(en + zh-CN)

How a device is reached, its measured speed and the tooltip on why that
matters were English strings in Devices.svelte. They are devices.link* keys
now, and linkLabel takes $t so the line follows a change of language. As
asked on Liquid-co#73.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ChakraFusion added a commit to ChakraFusion/OpenSave that referenced this pull request Oct 17, 2026
…(en + zh-CN)

How a device is reached, its measured speed and the tooltip on why that
matters were English strings in Devices.svelte. They are devices.link* keys
now, and linkLabel takes $t so the line follows a change of language. As
asked on Liquid-co#73.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ChakraFusion added a commit to ChakraFusion/OpenSave that referenced this pull request Oct 17, 2026
…(en + zh-CN)

How a device is reached, its measured speed and the tooltip on why that
matters were English strings in Devices.svelte. They are devices.link* keys
now, and linkLabel takes $t so the line follows a change of language. As
asked on Liquid-co#73.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants