diff --git a/core/library_itch.gd b/core/library_itch.gd index 2876327..8251a12 100644 --- a/core/library_itch.gd +++ b/core/library_itch.gd @@ -143,13 +143,15 @@ func _load_library(caching_flags: int = Cache.FLAGS.LOAD | Cache.FLAGS.SAVE) -> ## boxart directory (user://boxart/local/). The built-in "local" BoxArtProvider ## picks those files up by -.png, so games show their real ## cover instead of the placeholder. Covers are only downloaded once (the task -## bails out if a layout file already exists). +## bails out if a layout file already exists). For games with an animated GIF +## cover, itch.io provides a stillCoverUrl (a static frame, served as PNG) which +## we prefer, since Godot has no GIF decoder. func _queue_boxart(items: Array) -> void: for i in items: var item: LibraryLaunchItem = i var game: Dictionary = item.metadata.get("game", {}) var title: String = game.get("title", "") - var cover_url: String = game.get("coverUrl", "") + var cover_url := _cover_url(game) if title.is_empty() or cover_url.is_empty(): continue if FileAccess.file_exists("/".join([_boxart_dir(), title + "-portrait.png"])): @@ -163,7 +165,7 @@ func _queue_boxart(items: Array) -> void: ## single image is reused for portrait, landscape, banner and logo. func _ensure_boxart(game: Dictionary) -> void: var title: String = game.get("title", "") - var cover_url: String = game.get("coverUrl", "") + var cover_url := _cover_url(game) if title.is_empty() or cover_url.is_empty(): return var dir := _boxart_dir() @@ -175,8 +177,8 @@ func _ensure_boxart(game: Dictionary) -> void: logger.warn("Unable to download cover art for '" + title + "'") return if not _is_raster_image(body): - # OGPU's local provider only loads png/jpg; animated gif covers (rare) - # can't be rendered, so skip them rather than write an unloadable file. + # OGPU's local provider only loads png/jpg. If itch.io didn't give us a + # still for an animated cover, skip rather than write an unloadable file. logger.warn("Skipping unsupported cover format for '" + title + "'") return @@ -194,6 +196,16 @@ func _boxart_dir() -> String: return ProjectSettings.globalize_path("user://boxart/local") +## itch.io exposes stillCoverUrl for games whose cover is an animated GIF: a +## static frame that the CDN serves as PNG. Prefer it over coverUrl so those +## games still get art (Godot can't decode GIFs at runtime). +func _cover_url(game: Dictionary) -> String: + var still: String = game.get("stillCoverUrl", "") + if not still.is_empty(): + return still + return game.get("coverUrl", "") + + ## Blocking HTTPS GET of a single cover image, for use on a background thread. func _download_cover(url: String) -> PackedByteArray: var parts := url.split("/") diff --git a/plugin.json b/plugin.json index b1be80d..662eb5a 100644 --- a/plugin.json +++ b/plugin.json @@ -1,7 +1,7 @@ { "plugin.id": "itch", "plugin.name": "itch.io", - "plugin.version": "0.1.4", + "plugin.version": "0.1.5", "plugin.min-api-version": "1.1.0", "plugin.link": "https://github.com/YOUR_USERNAME/OpenGamepadUI-itch", "plugin.source": "https://github.com/YOUR_USERNAME/OpenGamepadUI-itch",