The cs-fix pass (758a9cab) typed ImageUtils::validateURL()'s URL and
StreamSorter::formatTitle()'s title as non-nullable strings, but both
come from nullable columns (streams.stream_icon / stream_display_name,
streams_series.title / cover, …). get_live_streams passed a channel's
NULL stream_icon straight in, so one channel without an icon turned the
line's entire live list into a TypeError page — and the same for any of
the ~100 validateURL() callers (series covers, backdrops, episode
images, admin and reseller views) and a title-less stream or series.
Both now take null as '' (unit-tested). player_api also no longer hands
filterLoaded() a null when the categories cache file is missing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y4P9p5BXijMoGXd31tN6Zp
StreamService::process() runs the stream icon through
ImageUtils::downloadImage() when "download images" is on, and an empty icon
arrives there as null. The `string` type the cs-fix pass (758a9cab) put on
the parameter made that a TypeError, so saving a new stream with no icon
answered an empty page and created nothing. Series, movies, episodes, radios
and created channels hand it optional covers and backdrops the same way.
downloadImage() now takes null and hands back whatever it cannot download
unchanged, null included. Found by the new E2E stream test.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WDhDajBPziJwjWZcXnh6R