Combine two screenshots side-by-side for banner layout
All checks were successful
Build plugin / build (push) Successful in 1m8s

This commit is contained in:
Jose Falanga 2026-08-17 01:51:54 -03:00
parent 8e0e5bfedf
commit 4efe3a9110

View file

@ -64,14 +64,27 @@ func get_boxart(item: LibraryItem, kind: LAYOUT) -> Texture2D:
_save_enriched_meta(game_id, meta) _save_enriched_meta(game_id, meta)
var screenshots: Array = meta.get("screenshots", []) var screenshots: Array = meta.get("screenshots", [])
var url := _url_for_layout(kind, cover_url, screenshots)
if url.is_empty():
return null
var cache_flags := Cache.FLAGS.NONE var cache_flags := Cache.FLAGS.NONE
if use_caching: if use_caching:
cache_flags = Cache.FLAGS.LOAD | Cache.FLAGS.SAVE cache_flags = Cache.FLAGS.LOAD | Cache.FLAGS.SAVE
# Banner: combine two screenshots side-by-side when available.
if kind == LAYOUT.BANNER and screenshots.size() >= 2:
logger.debug("Fetching itch.io banner (2 screenshots) for: " + item.name)
var tex_a := await http_image.fetch(screenshots[0], cache_flags)
var tex_b := await http_image.fetch(screenshots[1], cache_flags)
if tex_a != null and tex_b != null:
return _combine_side_by_side(tex_a, tex_b)
# Fall through to single-image path if either failed.
if tex_a != null:
return tex_a
if tex_b != null:
return tex_b
var url := _url_for_layout(kind, cover_url, screenshots)
if url.is_empty():
return null
logger.debug("Fetching itch.io box art for: " + item.name) logger.debug("Fetching itch.io box art for: " + item.name)
var texture: Texture2D = await http_image.fetch(url, cache_flags) var texture: Texture2D = await http_image.fetch(url, cache_flags)
if texture == null: if texture == null:
@ -97,8 +110,7 @@ func _url_for_layout(kind: LAYOUT, cover_url: String, screenshots: Array) -> Str
LAYOUT.GRID_LANDSCAPE: LAYOUT.GRID_LANDSCAPE:
return screenshots[0] if not screenshots.is_empty() else cover_url return screenshots[0] if not screenshots.is_empty() else cover_url
LAYOUT.BANNER: LAYOUT.BANNER:
if screenshots.size() > 1: # Single screenshot fallback (two-screenshot case handled in get_boxart).
return screenshots[1]
return screenshots[0] if not screenshots.is_empty() else cover_url return screenshots[0] if not screenshots.is_empty() else cover_url
return "" return ""
@ -110,6 +122,30 @@ func _cover_url(game: Dictionary) -> String:
return game.get("coverUrl", "") return game.get("coverUrl", "")
## Combines two textures side-by-side into a single banner image.
## Both images are scaled to the same height, then placed left and right.
func _combine_side_by_side(a: Texture2D, b: Texture2D) -> Texture2D:
var img_a := a.get_image()
var img_b := b.get_image()
if img_a == null or img_b == null:
return a
# Scale both to the same height (use the taller one).
var target_h: int = max(img_a.get_height(), img_b.get_height())
if img_a.get_height() != target_h:
var scale: float = float(target_h) / float(img_a.get_height())
img_a.resize(int(img_a.get_width() * scale), target_h, Image.INTERPOLATE_BILINEAR)
if img_b.get_height() != target_h:
var scale: float = float(target_h) / float(img_b.get_height())
img_b.resize(int(img_b.get_width() * scale), target_h, Image.INTERPOLATE_BILINEAR)
var combined := Image.create(img_a.get_width() + img_b.get_width(), target_h, false, img_a.get_format())
combined.blit_rect(img_a, Rect2i(0, 0, img_a.get_width(), target_h), Vector2i.ZERO)
combined.blit_rect(img_b, Rect2i(0, 0, img_b.get_width(), target_h), Vector2i(img_a.get_width(), 0))
return ImageTexture.create_from_image(combined)
## Scrapes the itch.io game page for screenshots. The itch.io API does not ## Scrapes the itch.io game page for screenshots. The itch.io API does not
## expose screenshots, so the page HTML is the only source. ## expose screenshots, so the page HTML is the only source.
func _fetch_game_page_metadata(game: Dictionary) -> Dictionary: func _fetch_game_page_metadata(game: Dictionary) -> Dictionary: