fix: handle itch.zone serving PNG for .jpg URLs
itch.zone returns content-type: image/png for .jpg URLs. HTTPImageFetcher uses URL extension to pick the decoder, causing load_jpg_from_buffer to fail on PNG data. Added format detection fallback that checks Content-Type headers when the normal fetch fails for .jpg/.jpeg URLs. Bump to v0.1.16
This commit is contained in:
parent
ce30f647c8
commit
101bbd17cd
1 changed files with 73 additions and 1 deletions
|
|
@ -22,6 +22,7 @@ const LOG_URL_MAX_LEN := 80
|
|||
const SETTING_SECTION := "plugin.artprovider"
|
||||
const SETTING_ANIMATED_GIFS := "animated_gifs"
|
||||
const GIF_DEFAULT_FRAME_DELAY_MS := 100
|
||||
const CACHE_DIR := "images"
|
||||
|
||||
@export var use_caching: bool = true
|
||||
var http_image := HTTPImageFetcher.new()
|
||||
|
|
@ -118,6 +119,71 @@ func _is_gif_url(url: String) -> bool:
|
|||
return _sanitize_url(url).to_lower().ends_with(".gif")
|
||||
|
||||
|
||||
## Returns whether a URL points to a JPEG image.
|
||||
func _is_jpg_url(url: String) -> bool:
|
||||
var clean := _sanitize_url(url).to_lower()
|
||||
return clean.ends_with(".jpg") or clean.ends_with(".jpeg")
|
||||
|
||||
|
||||
## Removes and frees an HTTPRequest node.
|
||||
func _remove_http(http: HTTPRequest) -> void:
|
||||
remove_child(http)
|
||||
http.queue_free()
|
||||
|
||||
|
||||
## Downloads an image and detects the actual format from content-type headers.
|
||||
## Used as a fallback when HTTPImageFetcher fails due to extension mismatch.
|
||||
func _fetch_image_with_format_detection(url: String, cache_flags: int) -> Texture2D:
|
||||
var http := HTTPRequest.new()
|
||||
http.timeout = HTTP_TIMEOUT_MS / 1000.0
|
||||
add_child.call_deferred(http)
|
||||
await http.ready
|
||||
|
||||
if http.request(url) != OK:
|
||||
_remove_http(http)
|
||||
return null
|
||||
|
||||
var args: Array = await http.request_completed
|
||||
var result: int = args[0]
|
||||
var response_code: int = args[1]
|
||||
var headers: PackedStringArray = args[2]
|
||||
var body: PackedByteArray = args[3]
|
||||
_remove_http(http)
|
||||
|
||||
if result != HTTPRequest.RESULT_SUCCESS or response_code != 200:
|
||||
return null
|
||||
|
||||
# Detect actual format from Content-Type header.
|
||||
var content_type := ""
|
||||
for h in headers:
|
||||
if h.to_lower().begins_with("content-type:"):
|
||||
content_type = h.split(":", true, 1)[1].strip_edges().to_lower()
|
||||
break
|
||||
|
||||
var image := Image.new()
|
||||
var err: int = ERR_INVALID_DATA
|
||||
if content_type.find("png") != -1:
|
||||
err = image.load_png_from_buffer(body)
|
||||
elif content_type.find("jpeg") != -1 or content_type.find("jpg") != -1:
|
||||
err = image.load_jpg_from_buffer(body)
|
||||
elif content_type.find("webp") != -1:
|
||||
err = image.load_webp_from_buffer(body)
|
||||
else:
|
||||
# Unknown type — try PNG first, then JPEG.
|
||||
err = image.load_png_from_buffer(body)
|
||||
if err != OK:
|
||||
err = image.load_jpg_from_buffer(body)
|
||||
|
||||
if err != OK:
|
||||
logger.warn("Format detection failed for %s (content-type: %s)" % [url.left(LOG_URL_MAX_LEN), content_type])
|
||||
return null
|
||||
|
||||
var texture := ImageTexture.create_from_image(image)
|
||||
if cache_flags & Cache.FLAGS.SAVE:
|
||||
Cache.save_image(CACHE_DIR, url, texture)
|
||||
return texture
|
||||
|
||||
|
||||
func get_boxart(item: LibraryItem, kind: LAYOUT) -> Texture2D:
|
||||
if not kind in layout_map:
|
||||
logger.error("Unsupported boxart layout: {0}".format([kind]))
|
||||
|
|
@ -373,7 +439,13 @@ func _fetch_image(url: String, cache_flags: int) -> Texture2D:
|
|||
_last_animated_setting = animated
|
||||
logger.info("Animated GIF setting changed to %s — cache cleared" % str(animated))
|
||||
return await _fetch_gif_as_texture(url, cache_flags)
|
||||
return await http_image.fetch(url, cache_flags)
|
||||
# HTTPImageFetcher uses the URL extension to pick the decoder, but
|
||||
# itch.zone often serves PNG data for .jpg URLs. If the normal fetch
|
||||
# fails for a .jpg/.jpeg URL, retry by detecting the actual format.
|
||||
var texture := await http_image.fetch(url, cache_flags)
|
||||
if texture == null and _is_jpg_url(url):
|
||||
texture = await _fetch_image_with_format_detection(url, cache_flags)
|
||||
return texture
|
||||
|
||||
|
||||
## Downloads a GIF and converts it to a Godot texture. When animated GIFs
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue