Merge games from the profile's itch.io collections into the library (deduped against owned games) so bookmarked free games show up

This commit is contained in:
Jose Falanga 2026-08-06 18:52:55 -03:00
parent 9cd4cb32e3
commit e9f25d104b
3 changed files with 106 additions and 23 deletions

View file

@ -66,6 +66,33 @@ func _on_install_progressed(_id: String, _current: int, _total: int) -> void:
pass
## Builds a LibraryLaunchItem for a game, or null when the entry isn't an
## actual game (itch.io also hosts tools, assets, soundtracks, comics, ...).
func _make_item(game: Dictionary, caves_by_game_id: Dictionary) -> Variant:
if game.is_empty():
return null
if game.get("classification", "game") != "game":
return null
var game_id: int = game.get("id", 0)
var cave: Dictionary = caves_by_game_id.get(game_id, {})
var item := LibraryLaunchItem.new()
item.provider_app_id = cave.get("id", "")
item.name = game.get("title", "Unknown itch.io game")
item.tags = ["itch"]
item.categories = ["Game"]
item.installed = not cave.is_empty()
item.metadata = {"game": game}
if not cave.is_empty():
var install_folder: String = cave.get("installInfo", {}).get("installFolder", "")
var exe := _find_executable(install_folder)
item.command = exe
item.args = []
item.cwd = install_folder
return item
## Builds the full itch.io library: owned games merged with install state
## from Fetch.Caves. Uses the standard Cache system so we don't hammer
## butlerd (and, transitively, the itch.io API) on every library refresh.
@ -87,6 +114,7 @@ func _load_library(caching_flags: int = Cache.FLAGS.LOAD | Cache.FLAGS.SAVE) ->
logger.info("Fetching itch.io library...")
var owned: Array = await itch.get_owned_games()
var caves: Array = await itch.get_caves()
var collection_games: Array = await itch.get_collection_games()
var caves_by_game_id := {}
for c in caves:
@ -95,34 +123,27 @@ func _load_library(caching_flags: int = Cache.FLAGS.LOAD | Cache.FLAGS.SAVE) ->
caves_by_game_id[game_id] = cave
var items := [] as Array[LibraryLaunchItem]
var seen_game_ids := {}
for o in owned:
var owned_entry: Dictionary = o
var game: Dictionary = owned_entry.get("game", {})
if game.is_empty():
continue
# Only surface actual games (itch.io also hosts tools, assets,
# soundtracks, comics, etc. under the same ownership API).
if game.get("classification", "game") != "game":
var item := _make_item(game, caves_by_game_id)
if item == null:
continue
seen_game_ids[game.get("id", 0)] = true
items.append(item)
# Collection games aren't necessarily owned (e.g. a free game the user
# bookmarked), so merge them in too, deduped against owned games.
for g in collection_games:
var game: Dictionary = g
var game_id: int = game.get("id", 0)
var cave: Dictionary = caves_by_game_id.get(game_id, {})
var item := LibraryLaunchItem.new()
item.provider_app_id = cave.get("id", "")
item.name = game.get("title", "Unknown itch.io game")
item.tags = ["itch"]
item.categories = ["Game"]
item.installed = not cave.is_empty()
item.metadata = {"game": game}
if not cave.is_empty():
var install_folder: String = cave.get("installInfo", {}).get("installFolder", "")
var exe := _find_executable(install_folder)
item.command = exe
item.args = []
item.cwd = install_folder
if game_id in seen_game_ids:
continue
var item := _make_item(game, caves_by_game_id)
if item == null:
continue
seen_game_ids[game_id] = true
items.append(item)
if caching_flags & Cache.FLAGS.SAVE: