Skip to content

Commit

Permalink
Merge pull request kodi-pvr#690 from ksooo/start-before-after
Browse files Browse the repository at this point in the history
Add support for Autorec properties "Start after" and "Start before"
  • Loading branch information
ksooo authored Nov 8, 2024
2 parents 54ef280 + 736f6a7 commit e8cefd2
Show file tree
Hide file tree
Showing 15 changed files with 122 additions and 236 deletions.
2 changes: 1 addition & 1 deletion pvr.hts/addon.xml.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon
id="pvr.hts"
version="22.5.0"
version="22.6.0"
name="Tvheadend HTSP Client"
provider-name="Adam Sutton, Sam Stenvall, Lars Op den Kamp, Kai Sommerfeld">
<requires>@ADDON_DEPENDS@</requires>
Expand Down
3 changes: 3 additions & 0 deletions pvr.hts/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
v22.6.0
- Add support for Autorec properties "Start after" and "Start before"

v22.5.0
- PVR Add-on API v9.2.0
- Add support for multiple recorded streams at a time (used by Kodi for thumbnail extraction)
Expand Down
24 changes: 0 additions & 24 deletions pvr.hts/resources/instance-settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -166,30 +166,6 @@

<category id="timer" label="30010" help="-1">
<group id="1" label="30050">
<setting id="autorec_approxtime" type="integer" label="30051" help="-1">
<level>0</level>
<default>0</default> <!-- Strict (start time + end time) -->
<constraints>
<options>
<option label="30052">0</option> <!-- Strict (start time + end time) -->
<option label="30053">1</option> <!-- Relaxed (start time +/- margin) -->
</options>
</constraints>
<control type="list" format="string" />
</setting>
<setting id="autorec_maxdiff" type="integer" label="30054" help="-1">
<level>0</level>
<default>15</default>
<constraints>
<minimum>0</minimum>
<step>5</step>
<maximum>120</maximum>
</constraints>
<dependencies>
<dependency type="enable" setting="autorec_approxtime">1</dependency>
</dependencies>
<control type="slider" format="integer" />
</setting>
<setting id="autorec_use_regex" type="boolean" label="30061" help="-1">
<level>0</level>
<default>false</default>
Expand Down
24 changes: 8 additions & 16 deletions pvr.hts/resources/language/resource.language.en_gb/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -88,22 +88,6 @@ msgctxt "#30050"
msgid "Auto recordings"
msgstr ""

msgctxt "#30051"
msgid "Start time window calculation"
msgstr ""

msgctxt "#30052"
msgid "Strict (start time + end time)"
msgstr ""

msgctxt "#30053"
msgid "Relaxed (start time +/- margin)"
msgstr ""

msgctxt "#30054"
msgid "Maximum start time margin (minutes)"
msgstr ""

msgctxt "#30055"
msgid "Default priority"
msgstr ""
Expand Down Expand Up @@ -516,3 +500,11 @@ msgstr ""
msgctxt "#30605"
msgid "(Default profile)"
msgstr ""

msgctxt "#30606"
msgid "Start after"
msgstr ""

msgctxt "#30607"
msgid "Start before"
msgstr ""
18 changes: 1 addition & 17 deletions src/Tvheadend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1113,19 +1113,11 @@ PVR_ERROR CTvheadend::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& type
{
unsigned int TIMER_REPEATING_SERIESLINK_ATTRIBS =
PVR_TIMER_TYPE_IS_REPEATING | PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE |
PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME |
PVR_TIMER_TYPE_SUPPORTS_START_ANYTIME | PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS |
PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS |
PVR_TIMER_TYPE_SUPPORTS_START_END_MARGIN | PVR_TIMER_TYPE_SUPPORTS_PRIORITY |
PVR_TIMER_TYPE_SUPPORTS_LIFETIME | PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS |
PVR_TIMER_TYPE_SUPPORTS_ANY_CHANNEL | PVR_TIMER_TYPE_REQUIRES_EPG_SERIESLINK_ON_CREATE;

if (!m_settings->GetAutorecApproxTime())
{
/* We need the end time to represent the end of the tvh starting window */
TIMER_REPEATING_SERIESLINK_ATTRIBS |= PVR_TIMER_TYPE_SUPPORTS_END_TIME;
TIMER_REPEATING_SERIESLINK_ATTRIBS |= PVR_TIMER_TYPE_SUPPORTS_END_ANYTIME;
}

/* Repeating epg based - series link autorec */
types.emplace_back(TimerType(
/* Settings */
Expand All @@ -1147,19 +1139,11 @@ PVR_ERROR CTvheadend::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& type
unsigned int TIMER_REPEATING_EPG_ATTRIBS =
PVR_TIMER_TYPE_IS_REPEATING | PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE |
PVR_TIMER_TYPE_SUPPORTS_TITLE_EPG_MATCH | PVR_TIMER_TYPE_SUPPORTS_CHANNELS |
PVR_TIMER_TYPE_SUPPORTS_START_TIME | PVR_TIMER_TYPE_SUPPORTS_START_ANYTIME |
PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS | PVR_TIMER_TYPE_SUPPORTS_START_END_MARGIN |
PVR_TIMER_TYPE_SUPPORTS_PRIORITY | PVR_TIMER_TYPE_SUPPORTS_LIFETIME |
PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS | PVR_TIMER_TYPE_SUPPORTS_ANY_CHANNEL |
PVR_TIMER_TYPE_SUPPORTS_FULLTEXT_EPG_MATCH | PVR_TIMER_TYPE_SUPPORTS_RECORD_ONLY_NEW_EPISODES;

if (!m_settings->GetAutorecApproxTime())
{
/* We need the end time to represent the end of the tvh starting window */
TIMER_REPEATING_EPG_ATTRIBS |= PVR_TIMER_TYPE_SUPPORTS_END_TIME;
TIMER_REPEATING_EPG_ATTRIBS |= PVR_TIMER_TYPE_SUPPORTS_END_ANYTIME;
}

/* Repeating epg based - autorec */
types.emplace_back(TimerType(
/* Settings */
Expand Down
81 changes: 2 additions & 79 deletions src/tvheadend/AutoRecordings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ AutoRecordings::AutoRecordings(const std::shared_ptr<InstanceSettings>& settings
Profiles& dvrConfigs)
: m_settings(settings),
m_conn(conn),
m_customTimerProps({CUSTOM_PROP_ID_DVR_CONFIGURATION, CUSTOM_PROP_ID_AUTOREC_BROADCASTTYPE,
m_customTimerProps({CUSTOM_PROP_ID_AUTOREC_START, CUSTOM_PROP_ID_AUTOREC_STARTWINDOW,
CUSTOM_PROP_ID_AUTOREC_BROADCASTTYPE, CUSTOM_PROP_ID_DVR_CONFIGURATION,
CUSTOM_PROP_ID_DVR_COMMENT},
conn,
dvrConfigs)
Expand Down Expand Up @@ -69,23 +70,6 @@ void AutoRecordings::GetAutorecTimers(std::vector<kodi::addon::PVRTimer>& timers
tmr.SetClientIndex(rec.second.GetId());
tmr.SetClientChannelUid((rec.second.GetChannel() > 0) ? rec.second.GetChannel()
: PVR_TIMER_ANY_CHANNEL);
tmr.SetStartTime(rec.second.GetStart());
tmr.SetEndTime(rec.second.GetStop());
if (tmr.GetStartTime() == 0)
tmr.SetStartAnyTime(true);
if (tmr.GetEndTime() == 0)
tmr.SetEndAnyTime(true);

if (!tmr.GetStartAnyTime() && tmr.GetEndAnyTime())
tmr.SetEndTime(tmr.GetStartTime() + 60 * 60); // Nominal 1 hour duration
if (tmr.GetStartAnyTime() && !tmr.GetEndAnyTime())
tmr.SetStartTime(tmr.GetEndTime() - 60 * 60); // Nominal 1 hour duration
if (tmr.GetStartAnyTime() && tmr.GetEndAnyTime())
{
tmr.SetStartTime(std::time(nullptr)); // now
tmr.SetEndTime(tmr.GetStartTime() + 60 * 60); // Nominal 1 hour duration
}

if (rec.second.GetName().empty()) // timers created on backend may not contain a name
tmr.SetTitle(rec.second.GetTitle());
else
Expand Down Expand Up @@ -211,66 +195,6 @@ PVR_ERROR AutoRecordings::SendAutorecAddOrUpdate(const kodi::addon::PVRTimer& ti
if (timer.GetDirectory() != "/")
htsmsg_add_str(m, "directory", timer.GetDirectory().c_str());


/* bAutorecApproxTime enabled: => start time in kodi = approximate start time in tvh */
/* => 'approximate' = starting window / 2 */
/* */
/* bAutorecApproxTime disabled: => start time in kodi = begin of starting window in tvh */
/* => end time in kodi = end of starting window in tvh */
if (m_settings->GetAutorecApproxTime())
{
/* Not sending causes server to set start and startWindow to any time */
if (timer.GetStartTime() > 0 && !timer.GetStartAnyTime())
{
time_t startTime = timer.GetStartTime();
struct tm* tm_start = std::localtime(&startTime);
int32_t startWindowBegin =
tm_start->tm_hour * 60 + tm_start->tm_min - m_settings->GetAutorecMaxDiff();
int32_t startWindowEnd =
tm_start->tm_hour * 60 + tm_start->tm_min + m_settings->GetAutorecMaxDiff();

/* Past midnight correction */
if (startWindowBegin < 0)
startWindowBegin += (24 * 60);
if (startWindowEnd > (24 * 60))
startWindowEnd -= (24 * 60);

htsmsg_add_s32(m, "start", startWindowBegin);
htsmsg_add_s32(m, "startWindow", startWindowEnd);
}
else
{
htsmsg_add_s32(m, "start", -1);
htsmsg_add_s32(m, "startWindow", -1);
}
}
else
{
if (timer.GetStartTime() > 0 && !timer.GetStartAnyTime())
{
/* Exact start time (minutes from midnight). */
time_t startTime = timer.GetStartTime();
struct tm* tm_start = std::localtime(&startTime);
htsmsg_add_s32(m, "start", tm_start->tm_hour * 60 + tm_start->tm_min);
}
else
htsmsg_add_s32(
m, "start",
25 * 60); // -1 or not sending causes server to set start and startWindow to any time

if (timer.GetEndTime() > 0 && !timer.GetEndAnyTime())
{
/* Exact stop time (minutes from midnight). */
time_t endTime = timer.GetEndTime();
struct tm* tm_stop = std::localtime(&endTime);
htsmsg_add_s32(m, "startWindow", tm_stop->tm_hour * 60 + tm_stop->tm_min);
}
else
htsmsg_add_s32(
m, "startWindow",
25 * 60); // -1 or not sending causes server to set start and startWindow to any time
}

/* series link */
if (timer.GetTimerType() == TIMER_REPEATING_SERIESLINK)
htsmsg_add_str(m, "serieslinkUri", timer.GetSeriesLink().c_str());
Expand Down Expand Up @@ -341,7 +265,6 @@ bool AutoRecordings::ParseAutorecAddOrUpdate(htsmsg_t* msg, bool bAdd)

/* Locate/create entry */
AutoRecording& rec = m_autoRecordings[std::string(str)];
rec.SetSettings(m_settings);
rec.SetStringId(std::string(str));
rec.SetDirty(false);

Expand Down
73 changes: 73 additions & 0 deletions src/tvheadend/CustomTimerProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ std::vector<kodi::addon::PVRSettingKeyValuePair> CustomTimerProperties::GetPrope
{
switch (propId)
{
case CUSTOM_PROP_ID_AUTOREC_START:
{
// Start
customProps.emplace_back(CUSTOM_PROP_ID_AUTOREC_START, autorec.GetStartWindowBegin());
break;
}
case CUSTOM_PROP_ID_AUTOREC_STARTWINDOW:
{
// Start window
customProps.emplace_back(CUSTOM_PROP_ID_AUTOREC_STARTWINDOW, autorec.GetStartWindowEnd());
break;
}
case CUSTOM_PROP_ID_AUTOREC_BROADCASTTYPE:
{
// Broadcast type
Expand Down Expand Up @@ -105,6 +117,28 @@ const std::vector<kodi::addon::PVRSettingDefinition> CustomTimerProperties::GetS
{
switch (propId)
{
case CUSTOM_PROP_ID_AUTOREC_START:
{
int defaultValue{AUTOREC_START_ANYTIME};
const std::vector<kodi::addon::PVRTypeIntValue> startValues{
GetPossibleValues(CUSTOM_PROP_ID_AUTOREC_START, defaultValue)};
ret.emplace_back(CreateSettingDefinition(CUSTOM_PROP_ID_AUTOREC_START,
30606, // Start after
startValues, defaultValue,
PVR_SETTING_READONLY_CONDITION_NONE));
break;
}
case CUSTOM_PROP_ID_AUTOREC_STARTWINDOW:
{
int defaultValue{AUTOREC_START_ANYTIME};
const std::vector<kodi::addon::PVRTypeIntValue> startWindowValues{
GetPossibleValues(CUSTOM_PROP_ID_AUTOREC_STARTWINDOW, defaultValue)};
ret.emplace_back(CreateSettingDefinition(CUSTOM_PROP_ID_AUTOREC_STARTWINDOW,
30607, // Start before
startWindowValues, defaultValue,
PVR_SETTING_READONLY_CONDITION_NONE));
break;
}
case CUSTOM_PROP_ID_AUTOREC_BROADCASTTYPE:
{
// Broadcast type
Expand Down Expand Up @@ -166,6 +200,33 @@ const std::vector<kodi::addon::PVRTypeIntValue> CustomTimerProperties::GetPossib
{
switch (propId)
{
case CUSTOM_PROP_ID_AUTOREC_START:
case CUSTOM_PROP_ID_AUTOREC_STARTWINDOW:
{
// Start, Start window

// Any : AUTOREC_START_ANYTIME (-1)
// 0:00 : 0
// 0:10 : 0 * 60 + 10
// ...
// 23:50 : 23 * 60 + 50
static std::vector<kodi::addon::PVRTypeIntValue> startValues{};
if (startValues.empty())
{
startValues.reserve(24 * 60 / 10 + 1);
startValues.emplace_back(
kodi::addon::PVRTypeIntValue(AUTOREC_START_ANYTIME,
kodi::addon::GetLocalizedString(30601))); // Any
for (int i = 0; i < 24 * 60; i += 10)
{
const std::string hours{std::to_string(i / 60)};
const std::string minutes{(i % 60) == 0 ? "00" : std::to_string(i % 60)};
startValues.emplace_back(kodi::addon::PVRTypeIntValue(i, hours + ":" + minutes));
}
}
defaultValue = AUTOREC_START_ANYTIME; // Any
return startValues;
}
case CUSTOM_PROP_ID_AUTOREC_BROADCASTTYPE:
{
// Broadcast type
Expand Down Expand Up @@ -241,6 +302,18 @@ void CustomTimerProperties::AppendPropertiesToHTSPMessage(
{
switch (prop.GetKey())
{
case CUSTOM_PROP_ID_AUTOREC_START:
{
// Start
htsmsg_add_s32(msg, "start", prop.GetIntValue());
break;
}
case CUSTOM_PROP_ID_AUTOREC_STARTWINDOW:
{
// Start window
htsmsg_add_s32(msg, "startWindow", prop.GetIntValue());
break;
}
case CUSTOM_PROP_ID_AUTOREC_BROADCASTTYPE:
{
// Broadcast type
Expand Down
2 changes: 2 additions & 0 deletions src/tvheadend/CustomTimerProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class RecordingBase;
constexpr unsigned int CUSTOM_PROP_ID_AUTOREC_BROADCASTTYPE{1};
constexpr unsigned int CUSTOM_PROP_ID_DVR_CONFIGURATION{2};
constexpr unsigned int CUSTOM_PROP_ID_DVR_COMMENT{3};
constexpr unsigned int CUSTOM_PROP_ID_AUTOREC_START{4};
constexpr unsigned int CUSTOM_PROP_ID_AUTOREC_STARTWINDOW{5};

class CustomTimerProperties
{
Expand Down
15 changes: 0 additions & 15 deletions src/tvheadend/InstanceSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,7 @@ const bool DEFAULT_ASYNC_EPG = true;
const bool DEFAULT_PRETUNER_ENABLED = false;
const int DEFAULT_TOTAL_TUNERS = 1; // total tuners > 1 => predictive tuning active
const int DEFAULT_PRETUNER_CLOSEDELAY = 10; // secs
const int DEFAULT_AUTOREC_MAXDIFF =
15; // mins. Maximum difference between real and approximate start time for auto recordings
const bool DEFAULT_AUTOREC_USE_REGEX = false;
const int DEFAULT_APPROX_TIME =
0; // don't use an approximate start time, use a fixed time instead for auto recordings
const std::string DEFAULT_STREAMING_PROFILE = "";
const bool DEFAULT_STREAMING_HTTP = false;
const int DEFAULT_DVR_PRIO = DVR_PRIO_NORMAL;
Expand Down Expand Up @@ -62,8 +58,6 @@ InstanceSettings::InstanceSettings(kodi::addon::IAddonInstance& instance)
m_bPretunerEnabled(DEFAULT_PRETUNER_ENABLED),
m_iTotalTuners(DEFAULT_TOTAL_TUNERS),
m_iPreTunerCloseDelay(DEFAULT_PRETUNER_CLOSEDELAY),
m_iAutorecApproxTime(DEFAULT_APPROX_TIME),
m_iAutorecMaxDiff(DEFAULT_AUTOREC_MAXDIFF),
m_bAutorecUseRegEx(DEFAULT_AUTOREC_USE_REGEX),
m_strStreamingProfile(DEFAULT_STREAMING_PROFILE),
m_bUseHTTPStreaming(DEFAULT_STREAMING_HTTP),
Expand Down Expand Up @@ -103,8 +97,6 @@ void InstanceSettings::ReadSettings()
m_bPretunerEnabled ? ReadIntSetting("pretuner_closedelay", DEFAULT_PRETUNER_CLOSEDELAY) : 0);

/* Auto recordings */
SetAutorecApproxTime(ReadIntSetting("autorec_approxtime", DEFAULT_APPROX_TIME));
SetAutorecMaxDiff(ReadIntSetting("autorec_maxdiff", DEFAULT_AUTOREC_MAXDIFF));
SetAutorecUseRegEx(ReadBoolSetting("autorec_use_regex", DEFAULT_AUTOREC_USE_REGEX));

/* Streaming */
Expand Down Expand Up @@ -176,13 +168,6 @@ ADDON_STATUS InstanceSettings::SetSetting(const std::string& key,
return ADDON_STATUS_OK;
}
/* Auto recordings */
else if (key == "autorec_approxtime")
return SetIntSetting(GetAutorecApproxTime(), value);
else if (key == "autorec_maxdiff")
{
SetAutorecMaxDiff(value.GetInt());
return ADDON_STATUS_OK;
}
else if (key == "autorec_use_regex")
{
SetAutorecUseRegEx(value.GetBoolean());
Expand Down
Loading

0 comments on commit e8cefd2

Please sign in to comment.