Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Control access to recordings and timers #260

Merged
merged 2 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pvr.nextpvr/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.nextpvr"
version="21.0.3"
version="21.1.0"
name="NextPVR PVR Client"
provider-name="Graeme Blackley">
<requires>@ADDON_DEPENDS@
Expand Down
5 changes: 5 additions & 0 deletions pvr.nextpvr/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
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
- de_de, es_es, fi_fi, it_it, ru_ru
Expand Down
67 changes: 41 additions & 26 deletions pvr.nextpvr/resources/instance-settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@
<default>2</default>
<constraints>
<options>
<option label="Real Time">2</option>
<option label="Timeshift">4</option>
<option label="Transcoded">3</option>
<option label="30210">2</option>
<option label="30211">4</option>
<option label="30212">3</option>
</options>
</constraints>
<control format="string" type="spinner"/>
Expand Down Expand Up @@ -203,6 +203,13 @@
<default>false</default>
<control type="toggle"/>
</setting>
<setting help="30694" id="genrestring" label="30194" type="boolean">
<level>1</level>
<default>false</default>
<control type="toggle"/>
</setting>
</group>
<group id="13">
<setting help="30680" id="flattenrecording" label="30180" type="boolean">
<level>2</level>
<default>false</default>
Expand All @@ -228,23 +235,16 @@
<default>Default</default>
<constraints>
<options>
<option>No</option>
<option>Default</option>
<option>Span</option>
<option label="106">No</option>
<option label="571">Default</option>
<option label="30213">Span</option>
</options>
<allowempty>false</allowempty>
</constraints>
<control type="list" format="string">
<heading>30198</heading>
</control>
</setting>
<setting help="30694" id="genrestring" label="30194" type="boolean">
<level>1</level>
<default>false</default>
<control type="toggle"/>
</setting>
</group>
<group id="13">
<setting help="30699" id="ignorepadding" label="30199" type="boolean">
<level>2</level>
<default>true</default>
Expand Down Expand Up @@ -279,6 +279,21 @@
<default>false</default>
<control type="toggle"/>
</setting>
<setting id="accesscontrol" type="integer" label="30209" help="30709">
<level>3</level>
<default>7</default>
<constraints>
<options>
<option label="30214">7</option>
<option label="30215">3</option>
<option label="30216">1</option>
<option label="30217">0</option>
</options>
</constraints>
<control type="list" format="string">
<heading>30709</heading>
</control>
</setting>
<setting help="30688" id="showradio" label="30188" type="boolean">
<level>0</level>
<default>true</default>
Expand All @@ -292,19 +307,19 @@
</group>
<group id="15">
<setting id="heartbeat" type="integer" label="30207" help="30707">
<level>2</level>
<default>0</default>
<constraints>
<options>
<option label="13278">0</option>
<option label="30208">1</option>
<option label="33036">2</option>
<option label="1223">3</option>
</options>
</constraints>
<control type="list" format="string">
<heading>32009</heading>
</control>
<level>2</level>
<default>0</default>
<constraints>
<options>
<option label="13278">0</option>
<option label="30208">1</option>
<option label="33036">2</option>
<option label="1223">3</option>
</options>
</constraints>
<control type="list" format="string">
<heading>32009</heading>
</control>
</setting>
</group>
</category>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,50 @@ msgctxt "#30707"
msgid "Interval to check for backend changes made outside this Kodi client"
msgstr ""


msgctxt "#30208"
msgid "Every 5 minutes"
msgstr ""

msgctxt "#30209"
msgid "Recording and timer control"
msgstr ""

msgctxt "#30709"
msgid "Manage user rights for recordings and timers"
msgstr ""

msgctxt "#30210"
msgid "Real Time"
msgstr ""

msgctxt "#30211"
msgid "Timeshift"
msgstr ""

msgctxt "#30212"
msgid "Transcoded"
msgstr ""

msgctxt "#30213"
msgid "Spann"
msgstr ""

msgctxt "#30214"
msgid "Full access to recordings and timers"
msgstr ""

msgctxt "#30215"
msgid "Play and delete recordings with no timers"
msgstr ""

msgctxt "#30216"
msgid "Play recordings with no timers"
msgstr ""

msgctxt "#30217"
msgid "Live TV only"
msgstr ""

msgctxt "#30218"
msgid "Repeating (all episodes)"
msgstr ""
8 changes: 7 additions & 1 deletion src/InstanceSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ void InstanceSettings::ReadFromAddon()

m_ignorePadding = ReadBoolSetting("ignorepadding", true);

m_resolution = ReadStringSetting("resolution", "720");
m_resolution = ReadStringSetting("resolution", "720");

m_accessLevel = ReadIntSetting("accesscontrol", ACCESS_RECORDINGS | ACCESS_RECORDINGS_DELETE | ACCESS_RECORDINGS_DELETE);

m_showRadio = ReadBoolSetting("showradio", true);

Expand Down Expand Up @@ -134,6 +136,8 @@ void InstanceSettings::ReadFromAddon()
else if (m_heartbeat == eHeartbeat::None)
m_heartbeatInterval = std::numeric_limits<time_t>::max();

if (m_accessLevel == ACCESS_NONE)
m_heartbeatInterval = std::numeric_limits<time_t>::max();

/* Log the current settings for debugging purposes */
kodi::Log(ADDON_LOG_DEBUG, "settings: host='%s', port=%i, instance=%d, mac=%4.4s...", m_hostname.c_str(), m_port, m_instanceNumber, m_hostMACAddress.c_str());
Expand Down Expand Up @@ -295,6 +299,8 @@ ADDON_STATUS InstanceSettings::SetValue(const std::string& settingName, const ko
return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_PIN, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
else if (settingName == "remoteaccess")
return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_remoteAccess, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
else if (settingName == "accesscontrol")
return SetSetting<int, ADDON_STATUS>(settingName, settingValue, m_accessLevel, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
else if (settingName == "showradio")
return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_showRadio, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
else if (settingName == "backendresume")
Expand Down
6 changes: 6 additions & 0 deletions src/InstanceSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ namespace NextPVR
constexpr eStreamingMethod DEFAULT_LIVE_STREAM = RealTime;
constexpr time_t DEFAULT_HEARTBEAT = 60;

const int ACCESS_NONE = 0;
const int ACCESS_RECORDINGS = (1 << 0);
const int ACCESS_RECORDINGS_DELETE = (1 << 1);
const int ACCESS_TIMERS = (1 << 2);

class ATTR_DLL_LOCAL InstanceSettings
{
public:
Expand Down Expand Up @@ -84,6 +89,7 @@ namespace NextPVR
enum eHeartbeat m_heartbeat;
time_t m_heartbeatInterval;
bool m_instancePriority = true;
int m_accessLevel = ACCESS_RECORDINGS | ACCESS_RECORDINGS_DELETE | ACCESS_RECORDINGS_DELETE;

//Channel
bool m_showRadio = true;
Expand Down
97 changes: 82 additions & 15 deletions src/Timers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -390,6 +394,7 @@ PVR_ERROR Timers::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& 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;
Expand Down Expand Up @@ -532,7 +537,7 @@ PVR_ERROR Timers::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& types)
types.emplace_back(*t);
delete t;

/* Repeating epg based Parent*/
/* Repeating epg based Parent timeslot */
t = new TimerType(
/* Type id. */
TIMER_REPEATING_EPG,
Expand All @@ -545,6 +550,21 @@ PVR_ERROR Timers::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& 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. */
Expand Down Expand Up @@ -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;
Expand All @@ -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");
Expand Down Expand Up @@ -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<int>(timer.GetStartTime()),
static_cast<int>(timer.GetEndTime()),
Expand Down Expand Up @@ -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");
Expand Down
7 changes: 4 additions & 3 deletions src/Timers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
Loading