From 4ddadee9783cd2d3f70f7d3826f7a87b1e4cda43 Mon Sep 17 00:00:00 2001 From: Martin Vallevand Date: Sat, 27 Apr 2024 10:19:39 -0400 Subject: [PATCH] Add backend timer rules NextPVR allows timeslot and also episode timers, pvr.nextpvr didn't support all episode single channel timers. Legacy backend code was defaulting the daily timeslot recording to an all episode recording. Added logic for backend type 2 and type 3 timers to handle these situations. --- pvr.nextpvr/changelog.txt | 2 + .../resource.language.en_gb/strings.po | 4 + src/Timers.cpp | 97 ++++++++++++++++--- src/Timers.h | 7 +- 4 files changed, 92 insertions(+), 18 deletions(-) diff --git a/pvr.nextpvr/changelog.txt b/pvr.nextpvr/changelog.txt index 1d596095..195aec94 100644 --- a/pvr.nextpvr/changelog.txt +++ b/pvr.nextpvr/changelog.txt @@ -1,5 +1,7 @@ v21.0.4 - Allow control of recording and timers access +- Support all episode single channel recordings +- Force Daily recordings to daily timeslot recordings v21.0.3 - Translations updates from Weblate diff --git a/pvr.nextpvr/resources/language/resource.language.en_gb/strings.po b/pvr.nextpvr/resources/language/resource.language.en_gb/strings.po index 2c91c0ec..02049f21 100644 --- a/pvr.nextpvr/resources/language/resource.language.en_gb/strings.po +++ b/pvr.nextpvr/resources/language/resource.language.en_gb/strings.po @@ -437,3 +437,7 @@ msgstr "" msgctxt "#30217" msgid "Live TV only" msgstr "" + +msgctxt "#30218" +msgid "Repeating (all episodes)" +msgstr "" diff --git a/src/Timers.cpp b/src/Timers.cpp index eb7feb0f..2ae9c5f7 100644 --- a/src/Timers.cpp +++ b/src/Timers.cpp @@ -117,6 +117,10 @@ PVR_ERROR Timers::GetTimers(kodi::addon::PVRTimersResultSet& results) tag.SetEndTime(TIMER_DATE_MIN); tag.SetStartAnyTime(true); tag.SetEndAnyTime(true); + if (recordingType == 2) + { + tag.SetTimerType(TIMER_REPEATING_EPG_ALL_EPISODES); + } } else { @@ -390,6 +394,7 @@ PVR_ERROR Timers::GetTimerTypes(std::vector& types) static const int MSG_REPEATING_CHILD = 30144; static const int MSG_REPEATING_KEYWORD = 30145; static const int MSG_REPEATING_ADVANCED = 30171; + static const int MSG_REPEATING_ALL_EPISODES = 30218; static const int MSG_KEEPALL = 30150; static const int MSG_KEEP1 = 30151; @@ -532,7 +537,7 @@ PVR_ERROR Timers::GetTimerTypes(std::vector& types) types.emplace_back(*t); delete t; - /* Repeating epg based Parent*/ + /* Repeating epg based Parent timeslot */ t = new TimerType( /* Type id. */ TIMER_REPEATING_EPG, @@ -545,6 +550,21 @@ PVR_ERROR Timers::GetTimerTypes(std::vector& types) types.emplace_back(*t); delete t; + /* Repeating epg based all episode*/ + t = new TimerType( + /* Type id. */ + TIMER_REPEATING_EPG_ALL_EPISODES, + /* Attributes. */ + TIMER_EPG_ATTRIBS | TIMER_REPEATING_EPG_ATTRIBS & ~(PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS), + /* Description. */ + GetTimerDescription(MSG_REPEATING_ALL_EPISODES), // "Repeating (All episodes)" + /* Values definitions for attributes. */ + recordingLimitValues, m_defaultLimit, showTypeValues, m_defaultShowType, recordingGroupValues, 0); + types.emplace_back(*t); + delete t; + + + /* Read-only one-shot for timers generated by timerec */ t = new TimerType( /* Type id. */ @@ -669,6 +689,7 @@ PVR_ERROR Timers::AddTimer(const kodi::addon::PVRTimer& timer) const std::string encodedName = UriEncode(timer.GetTitle()); const std::string encodedKeyword = UriEncode(timer.GetEPGSearchString()); const std::string days = GetDayString(timer.GetWeekdays()); + const std::string directory = UriEncode(m_settings->m_recordingDirectories[timer.GetRecordingGroup()]); int epgOid = 0; @@ -689,7 +710,18 @@ PVR_ERROR Timers::AddTimer(const kodi::addon::PVRTimer& timer) marginEnd = m_settings->m_defaultPostPadding; } - switch (timer.GetTimerType()) + int timerType = timer.GetTimerType(); + size_t countDays = std::count(days.begin(), days.end(), ':'); + if (timerType == TIMER_REPEATING_EPG) + { + if (countDays > 1 && countDays < 7) + { + // Backend doesn't support mixed days change to type 2 any episode + timerType = TIMER_REPEATING_EPG_ALL_EPISODES; + } + } + + switch (timerType) { case TIMER_ONCE_MANUAL: kodi::Log(ADDON_LOG_DEBUG, "TIMER_ONCE_MANUAL"); @@ -735,7 +767,7 @@ PVR_ERROR Timers::AddTimer(const kodi::addon::PVRTimer& timer) if (timer.GetEPGSearchString() == TYPE_7_TITLE) { kodi::Log(ADDON_LOG_DEBUG, "TIMER_REPEATING_EPG ANY CHANNEL - TYPE 7"); - request = kodi::tools::StringUtils::Format("recording.recurring.save&type=7&recurring_id=%d&start_time=%d&end_time=%d&keep=%d&pre_padding=%d&post_padding=%d&day_mask=%s&directory_id=%s%s", + request = kodi::tools::StringUtils::Format("recording.recurring.save&recurring_type=7&recurring_id=%d&start_time=%d&end_time=%d&keep=%d&pre_padding=%d&post_padding=%d&day_mask=%s&directory_id=%s%s", timer.GetClientIndex(), static_cast(timer.GetStartTime()), static_cast(timer.GetEndTime()), @@ -769,21 +801,56 @@ PVR_ERROR Timers::AddTimer(const kodi::addon::PVRTimer& timer) else { kodi::Log(ADDON_LOG_DEBUG, "TIMER_REPEATING_EPG"); - // build recurring recording request - request = kodi::tools::StringUtils::Format("recording.recurring.save&recurring_id=%d&channel_id=%d&event_id=%d&keep=%d&pre_padding=%d&post_padding=%d&day_mask=%s&directory_id=%s&only_new=%s%s", - timer.GetClientIndex(), - timer.GetClientChannelUid(), - epgOid, - timer.GetMaxRecordings(), - marginStart, - marginEnd, - days.c_str(), - directory.c_str(), - preventDuplicates, - enabled.c_str() + if (countDays == 7) + { + // build recurring type 3 request for a daily request not automatic timeslot + request = kodi::tools::StringUtils::Format("recording.recurring.save&recurring_type=3&recurring_id=%d&channel_id=%d&event_id=%d&keep=%d&pre_padding=%d&post_padding=%d&directory_id=%s&only_new=%s%s", + timer.GetClientIndex(), + timer.GetClientChannelUid(), + epgOid, + timer.GetMaxRecordings(), + marginStart, + marginEnd, + directory.c_str(), + preventDuplicates, + enabled.c_str() + ); + } + else + { + // NextPVR saves DAY, WEEKEND and WEEKDAY as timeslot recordings + request = kodi::tools::StringUtils::Format("recording.recurring.save&recurring_id=%d&channel_id=%d&event_id=%d&keep=%d&pre_padding=%d&post_padding=%d&day_mask=%s&directory_id=%s&only_new=%s%s", + timer.GetClientIndex(), + timer.GetClientChannelUid(), + epgOid, + timer.GetMaxRecordings(), + marginStart, + marginEnd, + days.c_str(), + directory.c_str(), + preventDuplicates, + enabled.c_str() ); + } } break; + case TIMER_REPEATING_EPG_ALL_EPISODES: + // NextPVR doesn't support daymask but pass it anyway. + kodi::Log(ADDON_LOG_DEBUG, "TIMER_REPEATING_EPG_ALL_EPISODES"); + // build recurring type 2 request + request = kodi::tools::StringUtils::Format("recording.recurring.save&recurring_type=2&recurring_id=%d&channel_id=%d&event_id=%d&keep=%d&pre_padding=%d&post_padding=%d&day_mask=%s&directory_id=%s&only_new=%s%s", + timer.GetClientIndex(), + timer.GetClientChannelUid(), + epgOid, + timer.GetMaxRecordings(), + marginStart, + marginEnd, + days.c_str(), + directory.c_str(), + preventDuplicates, + enabled.c_str() + ); + break; case TIMER_REPEATING_MANUAL: kodi::Log(ADDON_LOG_DEBUG, "TIMER_REPEATING_MANUAL"); diff --git a/src/Timers.h b/src/Timers.h index 89ff4138..72ad6bfd 100644 --- a/src/Timers.h +++ b/src/Timers.h @@ -33,9 +33,10 @@ namespace NextPVR constexpr unsigned int TIMER_REPEATING_MIN = TIMER_MANUAL_MAX + 1; constexpr unsigned int TIMER_REPEATING_MANUAL = TIMER_REPEATING_MIN; constexpr unsigned int TIMER_REPEATING_EPG = TIMER_REPEATING_MIN + 1; - constexpr unsigned int TIMER_REPEATING_KEYWORD = TIMER_REPEATING_MIN + 2; - constexpr unsigned int TIMER_REPEATING_ADVANCED = TIMER_REPEATING_MIN + 3; - constexpr unsigned int TIMER_REPEATING_MAX = TIMER_REPEATING_MIN + 3; + constexpr unsigned int TIMER_REPEATING_EPG_ALL_EPISODES = TIMER_REPEATING_MIN + 2; + constexpr unsigned int TIMER_REPEATING_KEYWORD = TIMER_REPEATING_MIN + 3; + constexpr unsigned int TIMER_REPEATING_ADVANCED = TIMER_REPEATING_MIN + 4; + constexpr unsigned int TIMER_REPEATING_MAX = TIMER_REPEATING_MIN + 4; class ATTR_DLL_LOCAL Timers {