Skip to content

Commit 19a9813

Browse files
authored
Merge pull request #831 from phunkyfish/catchup-id-live-urls
Catchup id live urls
2 parents 1b3f277 + c7231ac commit 19a9813

File tree

6 files changed

+84
-8
lines changed

6 files changed

+84
-8
lines changed

pvr.iptvsimple/addon.xml.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<addon
33
id="pvr.iptvsimple"
4-
version="21.7.2"
4+
version="21.8.0"
55
name="IPTV Simple Client"
66
provider-name="nightik and Ross Nicholson">
77
<requires>@ADDON_DEPENDS@

pvr.iptvsimple/changelog.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
v2.8.0
2+
- Support catchup-id for live URLs where possible
3+
- Support the Y, m, d, H, M, S specifiers for live URLs, useful for plugins and debugging
4+
- Enable Play from EPG in Live TV mode setting for Catchup VOD
5+
- Only set connection-timeout for connection manager if it's not NFS
6+
- Support the duration specifier for live URLs, useful for plugins and debugging
7+
- Support the all specifier for live URLs, useful for plugins and debugging
8+
- Fix timezone shift not applied for start time for live URLs
9+
110
v21.7.2
211
- Only reset the catchup state if not playing a timeshifted EPG tag
312

src/IptvSimple.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ PVR_ERROR IptvSimple::GetEPGTagStreamProperties(const kodi::addon::PVREPGTag& ta
308308
Logger::Log(LEVEL_DEBUG, "%s - GetPlayEpgAsLive is %s", __FUNCTION__, m_settings->CatchupPlayEpgAsLive() ? "enabled" : "disabled");
309309

310310
std::map<std::string, std::string> catchupProperties;
311-
if (m_settings->CatchupPlayEpgAsLive() && m_currentChannel.CatchupSupportsTimeshifting())
311+
if (m_settings->CatchupPlayEpgAsLive() && (m_currentChannel.CatchupSupportsTimeshifting() || m_currentChannel.GetCatchupMode() == CatchupMode::VOD))
312312
{
313313
m_catchupController.ProcessEPGTagForTimeshiftedPlayback(tag, m_currentChannel, catchupProperties);
314314
}

src/iptvsimple/CatchupController.cpp

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ void CatchupController::ProcessChannelForPlayback(const Channel& channel, std::m
3838
// Anything from here is live!
3939
m_playbackIsVideo = false; // TODO: possible time jitter on UI as this will effect get stream times
4040

41+
//Always get the live EPG entry
42+
EpgEntry* liveEpgEntry = GetLiveEPGEntry(channel);
43+
4144
if (!m_fromTimeshiftedEpgTagCall)
4245
{
43-
EpgEntry* liveEpgEntry = GetLiveEPGEntry(channel);
4446
if (m_controlsLiveStream && liveEpgEntry && !m_settings->CatchupOnlyOnFinishedProgrammes())
4547
{
4648
// Live timeshifting support with EPG entry
@@ -55,6 +57,13 @@ void CatchupController::ProcessChannelForPlayback(const Channel& channel, std::m
5557
m_programmeCatchupId.clear();
5658
m_catchupStartTime = 0;
5759
m_catchupEndTime = 0;
60+
61+
// Not from timeshifted EPG so safe to set the catchup ID here
62+
if (!m_controlsLiveStream && liveEpgEntry)
63+
{
64+
m_programmeCatchupId = liveEpgEntry->GetCatchupId();
65+
UpdateProgrammeFrom(*liveEpgEntry, channel.GetTvgShift());
66+
}
5867
}
5968
}
6069

@@ -132,6 +141,9 @@ void CatchupController::ProcessEPGTagForTimeshiftedPlayback(const kodi::addon::P
132141

133142
m_timeshiftBufferStartTime = 0;
134143
m_timeshiftBufferOffset = 0;
144+
145+
if (m_settings->CatchupPlayEpgAsLive())
146+
catchupProperties.insert({PVR_STREAM_PROPERTY_EPGPLAYBACKASLIVE, "true"});
135147
}
136148

137149
m_fromTimeshiftedEpgTagCall = true;
@@ -393,9 +405,11 @@ std::string FormatDateTime(time_t timeStart, time_t duration, const std::string
393405
return formattedUrl;
394406
}
395407

396-
std::string FormatDateTimeNowOnly(const std::string &urlFormatString, int timezoneShiftSecs)
408+
std::string FormatDateTimeNowOnly(const std::string &urlFormatString, int timezoneShiftSecs, int timeStart, int duration)
397409
{
398410
std::string formattedUrl = urlFormatString;
411+
412+
timeStart -= timezoneShiftSecs;
399413
const time_t timeNow = std::time(0) - timezoneShiftSecs;
400414
std::tm dateTimeNow = SafeLocaltime(timeNow);
401415

@@ -406,6 +420,46 @@ std::string FormatDateTimeNowOnly(const std::string &urlFormatString, int timezo
406420
FormatTime("now", &dateTimeNow, formattedUrl, true);
407421
FormatTime("timestamp", &dateTimeNow, formattedUrl, true);
408422

423+
// If we have the start time for a programme also process those specifiers
424+
// These can be useful for plugins that don't call ffmpegdirect and instead
425+
// play EPG as live for catchup="vod"
426+
if (timeStart > 0)
427+
{
428+
std::tm dateTimeStart = SafeLocaltime(timeStart);
429+
430+
const time_t timeEnd = timeStart + duration;
431+
std::tm dateTimeEnd = SafeLocaltime(timeEnd);
432+
433+
FormatTime('Y', &dateTimeStart, formattedUrl);
434+
FormatTime('m', &dateTimeStart, formattedUrl);
435+
FormatTime('d', &dateTimeStart, formattedUrl);
436+
FormatTime('H', &dateTimeStart, formattedUrl);
437+
FormatTime('M', &dateTimeStart, formattedUrl);
438+
FormatTime('S', &dateTimeStart, formattedUrl);
439+
FormatUtc("{utc}", timeStart, formattedUrl);
440+
FormatUtc("${start}", timeStart, formattedUrl);
441+
FormatUtc("{utcend}", timeStart + duration, formattedUrl);
442+
FormatUtc("${end}", timeStart + duration, formattedUrl);
443+
FormatUtc("{lutc}", timeNow, formattedUrl);
444+
FormatUtc("${now}", timeNow, formattedUrl);
445+
FormatUtc("${timestamp}", timeNow, formattedUrl);
446+
FormatUtc("${duration}", duration, formattedUrl);
447+
FormatUtc("{duration}", duration, formattedUrl);
448+
FormatUnits("duration", duration, formattedUrl);
449+
FormatUtc("${offset}", timeNow - timeStart, formattedUrl);
450+
FormatUnits("offset", timeNow - timeStart, formattedUrl);
451+
452+
FormatTime("utc", &dateTimeStart, formattedUrl, false);
453+
FormatTime("start", &dateTimeStart, formattedUrl, true);
454+
455+
FormatTime("utcend", &dateTimeEnd, formattedUrl, false);
456+
FormatTime("end", &dateTimeEnd, formattedUrl, true);
457+
458+
FormatTime("lutc", &dateTimeNow, formattedUrl, false);
459+
FormatTime("now", &dateTimeNow, formattedUrl, true);
460+
FormatTime("timestamp", &dateTimeNow, formattedUrl, true);
461+
}
462+
409463
Logger::Log(LEVEL_DEBUG, "%s - \"%s\"", __FUNCTION__, WebUtils::RedactUrl(formattedUrl).c_str());
410464

411465
return formattedUrl;
@@ -440,7 +494,7 @@ std::string BuildEpgTagUrl(time_t startTime, time_t duration, const Channel& cha
440494
if ((startTime > 0 && offset < (timeNow - 5)) || (channel.IgnoreCatchupDays() && !programmeCatchupId.empty()))
441495
startTimeUrl = FormatDateTime(offset - timezoneShiftSecs, duration, channel.GetCatchupSource());
442496
else
443-
startTimeUrl = FormatDateTimeNowOnly(channel.GetStreamURL(), timezoneShiftSecs);
497+
startTimeUrl = FormatDateTimeNowOnly(channel.GetStreamURL(), timezoneShiftSecs, startTime, duration);
444498

445499
static const std::regex CATCHUP_ID_REGEX("\\{catchup-id\\}");
446500
if (!programmeCatchupId.empty())
@@ -490,7 +544,13 @@ std::string CatchupController::GetCatchupUrl(const Channel& channel) const
490544
std::string CatchupController::ProcessStreamUrl(const Channel& channel) const
491545
{
492546
//We only process current time timestamps specifiers in this case
493-
return FormatDateTimeNowOnly(channel.GetStreamURL(), m_epg.GetEPGTimezoneShiftSecs(channel) + channel.GetCatchupCorrectionSecs());
547+
std::string processedUrl = FormatDateTimeNowOnly(channel.GetStreamURL(), m_epg.GetEPGTimezoneShiftSecs(channel) + channel.GetCatchupCorrectionSecs(), m_programmeStartTime, m_programmeEndTime - m_programmeStartTime);
548+
549+
static const std::regex CATCHUP_ID_REGEX("\\{catchup-id\\}");
550+
if (!m_programmeCatchupId.empty())
551+
processedUrl = std::regex_replace(processedUrl, CATCHUP_ID_REGEX, m_programmeCatchupId);
552+
553+
return processedUrl;
494554
}
495555

496556
std::string CatchupController::GetStreamTestUrl(const Channel& channel, bool fromEpg) const

src/iptvsimple/utilities/WebUtils.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ bool WebUtils::IsHttpUrl(const std::string& url)
116116
return StringUtils::StartsWith(url, HTTP_PREFIX) || StringUtils::StartsWith(url, HTTPS_PREFIX);
117117
}
118118

119+
bool WebUtils::IsNfsUrl(const std::string& url)
120+
{
121+
return StringUtils::StartsWith(url, NFS_PREFIX);
122+
}
123+
119124
std::string WebUtils::RedactUrl(const std::string& url)
120125
{
121126
std::string redactedUrl = url;
@@ -145,8 +150,8 @@ bool WebUtils::Check(const std::string& strURL, int connectionTimeoutSecs, bool
145150
return false;
146151
}
147152

148-
fileHandle.CURLAddOption(ADDON_CURL_OPTION_PROTOCOL, "connection-timeout",
149-
std::to_string(connectionTimeoutSecs));
153+
if (!IsNfsUrl(strURL))
154+
fileHandle.CURLAddOption(ADDON_CURL_OPTION_PROTOCOL, "connection-timeout", std::to_string(connectionTimeoutSecs));
150155

151156
if (!fileHandle.CURLOpen(ADDON_READ_NO_CACHE))
152157
{

src/iptvsimple/utilities/WebUtils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ namespace iptvsimple
1515
{
1616
static const std::string HTTP_PREFIX = "http://";
1717
static const std::string HTTPS_PREFIX = "https://";
18+
static const std::string NFS_PREFIX = "nfs://";
1819
static const std::string UDP_MULTICAST_PREFIX = "udp://@";
1920
static const std::string RTP_MULTICAST_PREFIX = "rtp://@";
2021

@@ -26,6 +27,7 @@ namespace iptvsimple
2627
static bool IsEncoded(const std::string& value);
2728
static std::string ReadFileContentsStartOnly(const std::string& url, int* httpCode);
2829
static bool IsHttpUrl(const std::string& url);
30+
static bool IsNfsUrl(const std::string& url);
2931
static std::string RedactUrl(const std::string& url);
3032
static bool Check(const std::string& url, int connectionTimeoutSecs, bool isLocalPath = false);
3133
};

0 commit comments

Comments
 (0)