From 212f5a39ab394652c7a4b251bab63e02ac0e4e5c Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Thu, 22 Oct 2026 12:14:05 +0200 Subject: [PATCH 1/2] Don't use HEAD to check HTTP streams in InspectStreamType Some servers answer HEAD with 403 while serving GET normally (e.g. the Rai 3 DASH manifest on cdn.netrw.it). The HEAD-based FileExists() check then fails, the stream type stays unknown and the URL is handed to the FFmpeg demuxer instead of inputstream.adaptive, so playback fails. For HTTP URLs, rely on the GET used to sniff the content instead. --- src/iptvsimple/utilities/StreamUtils.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/iptvsimple/utilities/StreamUtils.cpp b/src/iptvsimple/utilities/StreamUtils.cpp index 09b7cc8f..ac4a566d 100644 --- a/src/iptvsimple/utilities/StreamUtils.cpp +++ b/src/iptvsimple/utilities/StreamUtils.cpp @@ -365,7 +365,9 @@ const StreamType StreamUtils::GetStreamType(const std::string& url, const std::s const StreamType StreamUtils::InspectStreamType(const std::string& url, CatchupMode catchupMode) { - if (!FileUtils::FileExists(url)) + // Some servers reject the HEAD request used by FileExists() but allow GET, + // so for HTTP rely on the read below to detect an unreachable stream. + if (!WebUtils::IsHttpUrl(url) && !FileUtils::FileExists(url)) return StreamType::OTHER_TYPE; int httpCode = 0; From bbe279b75d97a5bcf76dc7ebff8512c65fe95763 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Thu, 22 Oct 2026 14:17:28 +0200 Subject: [PATCH 2/2] Reuse the looked up stream type when setting stream properties GetChannelStreamProperties() looks up the stream type through the catchup controller, which caches it, and then SetAllStreamProperties() inspected the same URL again. For URLs without a recognisable extension (redirectors, token services) this meant an extra HTTP request on every channel switch, adding 1-2 s before playback could start. Pass the type the catchup controller found for the same URL and only inspect when it is unknown. --- src/IptvSimple.cpp | 3 ++- src/iptvsimple/CatchupController.cpp | 4 +++- src/iptvsimple/CatchupController.h | 6 ++++++ src/iptvsimple/utilities/StreamUtils.cpp | 4 +++- src/iptvsimple/utilities/StreamUtils.h | 2 +- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/IptvSimple.cpp b/src/IptvSimple.cpp index 02383e54..19426f95 100644 --- a/src/IptvSimple.cpp +++ b/src/IptvSimple.cpp @@ -240,7 +240,8 @@ PVR_ERROR IptvSimple::GetChannelStreamProperties(const kodi::addon::PVRChannel& streamURL = m_catchupController.ProcessStreamUrl(m_currentChannel); streamURL = StreamUtils::WebStreamExtractor(streamURL, m_currentChannel); - StreamUtils::SetAllStreamProperties(properties, m_currentChannel, streamURL, catchupUrl.empty(), catchupProperties, m_settings); + // The catchup controller already looked up the stream type of this URL + StreamUtils::SetAllStreamProperties(properties, m_currentChannel, streamURL, catchupUrl.empty(), catchupProperties, m_settings, m_catchupController.GetKnownStreamType(streamURL)); Logger::Log(LogLevel::LEVEL_INFO, "%s - Live %s URL: %s", __FUNCTION__, catchupUrl.empty() ? "Stream" : "Catchup", WebUtils::RedactUrl(streamURL).c_str()); diff --git a/src/iptvsimple/CatchupController.cpp b/src/iptvsimple/CatchupController.cpp index 39ec0ad8..21732bb9 100644 --- a/src/iptvsimple/CatchupController.cpp +++ b/src/iptvsimple/CatchupController.cpp @@ -246,7 +246,9 @@ void CatchupController::SetCatchupInputStreamProperties(bool playbackAsLive, con StreamType CatchupController::StreamTypeLookup(const Channel& channel, bool fromEpg /* false */) { - StreamType streamType = m_streamManager.StreamTypeLookup(channel, GetStreamTestUrl(channel, fromEpg), GetStreamKey(channel, fromEpg)); + m_lastStreamTestUrl = GetStreamTestUrl(channel, fromEpg); + StreamType streamType = m_streamManager.StreamTypeLookup(channel, m_lastStreamTestUrl, GetStreamKey(channel, fromEpg)); + m_lastStreamType = streamType; m_controlsLiveStream = StreamUtils::GetEffectiveInputStreamName(streamType, channel, m_settings) == "inputstream.ffmpegdirect" && channel.CatchupSupportsTimeshifting(); diff --git a/src/iptvsimple/CatchupController.h b/src/iptvsimple/CatchupController.h index 0b7969cc..e9d65a79 100644 --- a/src/iptvsimple/CatchupController.h +++ b/src/iptvsimple/CatchupController.h @@ -38,6 +38,10 @@ namespace iptvsimple std::string ProcessStreamUrl(const data::Channel& channel) const; bool ControlsLiveStream() const { return m_controlsLiveStream; } + StreamType GetKnownStreamType(const std::string& url) const + { + return url == m_lastStreamTestUrl ? m_lastStreamType : StreamType::OTHER_TYPE; + } void ResetCatchupState(); data::EpgEntry* GetEPGEntry(const iptvsimple::data::Channel& myChannel, time_t lookupTime); @@ -71,6 +75,8 @@ namespace iptvsimple std::string m_programmeCatchupId; bool m_controlsLiveStream = false; + std::string m_lastStreamTestUrl; + StreamType m_lastStreamType = StreamType::OTHER_TYPE; iptvsimple::Epg& m_epg; std::mutex* m_mutex = nullptr; diff --git a/src/iptvsimple/utilities/StreamUtils.cpp b/src/iptvsimple/utilities/StreamUtils.cpp index ac4a566d..c75ae0c8 100644 --- a/src/iptvsimple/utilities/StreamUtils.cpp +++ b/src/iptvsimple/utilities/StreamUtils.cpp @@ -47,7 +47,7 @@ bool HasInputstreamAdaptiveDrmConfig(const T& entry) } } // unnamed namespace -void StreamUtils::SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamURL, bool isChannelURL, std::map& catchupProperties, std::shared_ptr& settings) +void StreamUtils::SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamURL, bool isChannelURL, std::map& catchupProperties, std::shared_ptr& settings, StreamType knownStreamType) { // Check if the channel explicitly uses inputstream.adaptive, or has its DRM configuration // without another explicit inputstream. If so, the best behaviour for media services is: @@ -84,6 +84,8 @@ void StreamUtils::SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamUrl, bool isChannelURL, std::map& catchupProperties, std::shared_ptr& settings); + static void SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamUrl, bool isChannelURL, std::map& catchupProperties, std::shared_ptr& settings, StreamType knownStreamType = StreamType::OTHER_TYPE); static void SetAllStreamProperties(std::vector& properties, const iptvsimple::data::MediaEntry& mediaEntry, const std::string& streamUrl, std::shared_ptr& settings); static const StreamType GetStreamType(const std::string& url, const std::string& mimeType, bool isCatchupTSStream); static const StreamType InspectStreamType(const std::string& url, iptvsimple::CatchupMode catchupMode);