Skip to content

Commit

Permalink
Add support for Autorec property 'Broadcast type' (HTSPv39+), DVR ent…
Browse files Browse the repository at this point in the history
…ry property 'DVR configuration' (HTSPv40+), DVR entry property 'comment' (HTSPv42+).
  • Loading branch information
ksooo committed Sep 6, 2024
1 parent 4eb898a commit 7b238c0
Show file tree
Hide file tree
Showing 18 changed files with 726 additions and 44 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ set(HTS_SOURCES_TVHEADEND
src/tvheadend/AutoRecordings.h
src/tvheadend/ChannelTuningPredictor.h
src/tvheadend/ChannelTuningPredictor.cpp
src/tvheadend/CustomTimerProperties.h
src/tvheadend/CustomTimerProperties.cpp
src/tvheadend/HTSPConnection.h
src/tvheadend/HTSPConnection.cpp
src/tvheadend/HTSPDemuxer.h
Expand Down
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.3.0"
version="22.4.0"
name="Tvheadend HTSP Client"
provider-name="Adam Sutton, Sam Stenvall, Lars Op den Kamp, Kai Sommerfeld">
<requires>@ADDON_DEPENDS@</requires>
Expand Down
6 changes: 6 additions & 0 deletions pvr.hts/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
v22.4.0
- PVR Add-on API v9.1.0
- Add support for Autorec property "Broadcast type" (HTSPv39+)
- Add support for DVR entry property "DVR configuration" (HTSPv40+)
- Add support for DVR entry property "Comment" (HTSPv42+)

v22.3.0
- Add support for PVR Providers (HTSPv38+)

Expand Down
46 changes: 42 additions & 4 deletions pvr.hts/resources/language/resource.language.en_gb/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,13 @@ msgctxt "#30372"
msgid "Record if unique episode according EPG/XMLTV"
msgstr ""

#empty strings from id 30373 to 30374
#. Prevent duplicate episodes representation
#: src/Tvheadend.cpp
msgctxt "#30373"
msgid "Use DVR configuration"
msgstr ""

#empty string with id 30374

#. Recording lifetime representation
#: src/Tvheadend.cpp
Expand Down Expand Up @@ -441,7 +447,15 @@ msgctxt "#30456"
msgid "Subscription error"
msgstr ""

#empty strings from id 30457 to 30499
msgctxt "#30457"
msgid "DVR configuration"
msgstr ""

msgctxt "#30458"
msgid "Comment"
msgstr ""

#empty strings from id 30459 to 30499

msgctxt "#30500"
msgid "Streaming profile"
Expand All @@ -451,8 +465,6 @@ msgctxt "#30501"
msgid "Profile to use (empty = default)"
msgstr ""

#. Check streaming profile validity during startup
#: src/client.cpp
msgctxt "#30502"
msgid "Streaming profile %s is not available"
msgstr ""
Expand All @@ -478,3 +490,29 @@ msgstr ""
msgctxt "#30511"
msgid "Server based play status"
msgstr ""

#empty strings from id 30512 to 30599

msgctxt "#30600"
msgid "Broadcast type"
msgstr ""

msgctxt "#30601"
msgid "Any"
msgstr ""

msgctxt "#30602"
msgid "New / premiere / unknown"
msgstr ""

msgctxt "#30603"
msgid "Repeated"
msgstr ""

msgctxt "#30604"
msgid "New / premiere"
msgstr ""

msgctxt "#30605"
msgid "(Default profile)"
msgstr ""
113 changes: 107 additions & 6 deletions src/Tvheadend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "Tvheadend.h"

#include "tvheadend/CustomTimerProperties.h"
#include "tvheadend/HTSPConnection.h"
#include "tvheadend/HTSPDemuxer.h"
#include "tvheadend/HTSPMessage.h"
Expand All @@ -32,12 +33,14 @@ CTvheadend::CTvheadend(const kodi::addon::IInstanceInfo& instance)
: kodi::addon::CInstancePVRClient(instance),
m_settings(new InstanceSettings(*this)),
m_conn(new HTSPConnection(m_settings, *this)),
m_customTimerProps(
{CUSTOM_PROP_ID_DVR_CONFIGURATION, CUSTOM_PROP_ID_DVR_COMMENT}, *m_conn, m_dvrConfigs),
m_streamchange(false),
m_vfs(new HTSPVFS(m_settings, *m_conn)),
m_queue(static_cast<size_t>(-1)),
m_asyncState(m_settings->GetResponseTimeout()),
m_timeRecordings(*m_conn),
m_autoRecordings(m_settings, *m_conn),
m_timeRecordings(*m_conn, m_dvrConfigs),
m_autoRecordings(m_settings, *m_conn, m_dvrConfigs),
m_epgMaxDays(EpgMaxFutureDays()),
m_playingLiveStream(false),
m_playingRecording(nullptr)
Expand Down Expand Up @@ -167,6 +170,56 @@ std::string CTvheadend::GetImageURL(const char* str)
}
}

void CTvheadend::QueryAvailableDvrConfigurations(std::unique_lock<std::recursive_mutex>& lock)
{
/* Build message */
htsmsg_t* m = htsmsg_create_map();

/* Send */
m = m_conn->SendAndWait0(lock, "getDvrConfigs", m);

/* Validate */
if (!m)
return;

htsmsg_t* l = htsmsg_get_list(m, "dvrconfigs");

if (!l)
{
Logger::Log(LogLevel::LEVEL_ERROR, "malformed getDvrConfigs: 'dvrconfigs' missing");
htsmsg_destroy(m);
return;
}

/* Process */
Logger::Log(LogLevel::LEVEL_INFO, " Available DVR configurations:");

htsmsg_field_t* f = nullptr;
HTSMSG_FOREACH(f, l)
{
Profile profile;

const char* str = htsmsg_get_str(&f->hmf_msg, "uuid");
if (str)
profile.SetUuid(str);

str = htsmsg_get_str(&f->hmf_msg, "name");
if (str)
profile.SetName(str);

str = htsmsg_get_str(&f->hmf_msg, "comment");
if (str)
profile.SetComment(str);

Logger::Log(LogLevel::LEVEL_INFO, " Name: %s, Comment: %s", profile.GetName().c_str(),
profile.GetComment().c_str());

m_dvrConfigs.emplace_back(std::move(profile));
}

htsmsg_destroy(m);
}

void CTvheadend::QueryAvailableProfiles(std::unique_lock<std::recursive_mutex>& lock)
{
/* Build message */
Expand Down Expand Up @@ -840,16 +893,16 @@ struct TimerType : kodi::addon::PVRTimerType
unsigned int id,
unsigned int attributes,
const std::string& description,
const std::vector<kodi::addon::PVRTypeIntValue>& priorityValues =
std::vector<kodi::addon::PVRTypeIntValue>(),
const std::vector<kodi::addon::PVRTypeIntValue>& lifetimeValues =
std::vector<kodi::addon::PVRTypeIntValue>(),
const std::vector<kodi::addon::PVRSettingDefinition>& customSettingDefs,
const std::vector<kodi::addon::PVRTypeIntValue>& priorityValues,
const std::vector<kodi::addon::PVRTypeIntValue>& lifetimeValues,
const std::vector<kodi::addon::PVRTypeIntValue>& dupEpisodesValues =
std::vector<kodi::addon::PVRTypeIntValue>())
{
SetId(id);
SetAttributes(attributes);
SetDescription(description);
SetCustomSettingDefinitions(customSettingDefs);
SetPriorities(priorityValues, settings->GetDvrPriority());
SetLifetimes(lifetimeValues, LifetimeMapper::TvhToKodi(settings->GetDvrLifetime()));
SetPreventDuplicateEpisodes(dupEpisodesValues, settings->GetDvrDupdetect());
Expand Down Expand Up @@ -898,6 +951,7 @@ PVR_ERROR CTvheadend::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& type

/* PVR_Timer.iPreventDuplicateEpisodes values and presentation.*/
std::vector<kodi::addon::PVRTypeIntValue> deDupValues = {
{DVR_AUTOREC_RECORD_DVR_PROFILE, kodi::addon::GetLocalizedString(30373)},
{DVR_AUTOREC_RECORD_ALL, kodi::addon::GetLocalizedString(30356)},
{DVR_AUTOREC_RECORD_DIFFERENT_EPISODE_NUMBER, kodi::addon::GetLocalizedString(30357)},
{DVR_AUTOREC_RECORD_DIFFERENT_SUBTITLE, kodi::addon::GetLocalizedString(30358)},
Expand Down Expand Up @@ -951,6 +1005,10 @@ PVR_ERROR CTvheadend::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& type

/* Timer types definition. */

/* Custom setting definitions */
const std::vector<kodi::addon::PVRSettingDefinition> customSettingDefs{
m_customTimerProps.GetSettingDefinitions()};

/* One-shot manual (time and channel based) */
types.emplace_back(TimerType(
/* Settings */
Expand All @@ -961,6 +1019,8 @@ PVR_ERROR CTvheadend::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& type
TIMER_ONCE_MANUAL_ATTRIBS,
/* Let Kodi generate the description. */
"",
/* Custom settings definitions. */
customSettingDefs,
/* Values definitions for priorities. */
priorityValues,
/* Values definitions for lifetime. */
Expand All @@ -976,6 +1036,8 @@ PVR_ERROR CTvheadend::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& type
TIMER_ONCE_EPG_ATTRIBS,
/* Let Kodi generate the description. */
"",
/* Custom settings definitions. */
customSettingDefs,
/* Values definitions for priorities. */
priorityValues,
/* Values definitions for lifetime. */
Expand All @@ -991,6 +1053,8 @@ PVR_ERROR CTvheadend::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& type
TIMER_ONCE_MANUAL_ATTRIBS | PVR_TIMER_TYPE_IS_READONLY | PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES,
/* Description. */
kodi::addon::GetLocalizedString(30350), // "One Time (Scheduled by timer rule)"
/* Custom settings definitions. */
customSettingDefs,
/* Values definitions for priorities. */
priorityValues,
/* Values definitions for lifetime. */
Expand All @@ -1006,11 +1070,17 @@ PVR_ERROR CTvheadend::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& type
TIMER_ONCE_EPG_ATTRIBS | PVR_TIMER_TYPE_IS_READONLY | PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES,
/* Description. */
kodi::addon::GetLocalizedString(30350), // "One Time (Scheduled by timer rule)"
/* Custom settings definitions. */
customSettingDefs,
/* Values definitions for priorities. */
priorityValues,
/* Values definitions for lifetime. */
lifetimeValues));

/* Custom Timerec setting definitions */
const std::vector<kodi::addon::PVRSettingDefinition> customTimeRecSettingDefs{
m_timeRecordings.GetCustomSettingDefinitions()};

/* Repeating manual (time and channel based) - timerec */
types.emplace_back(TimerType(
/* Settings */
Expand All @@ -1025,11 +1095,17 @@ PVR_ERROR CTvheadend::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& type
PVR_TIMER_TYPE_SUPPORTS_LIFETIME | PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS,
/* Let Kodi generate the description. */
"",
/* Custom settings definitions. */
customTimeRecSettingDefs,
/* Values definitions for priorities. */
priorityValues,
/* Values definitions for lifetime. */
lifetimeValues));

/* Custom Autorec setting definitions */
const std::vector<kodi::addon::PVRSettingDefinition> customAutoRecSettingDefs{
m_autoRecordings.GetCustomSettingDefinitions()};

if (m_conn->GetProtocol() >= 29)
{
unsigned int TIMER_REPEATING_SERIESLINK_ATTRIBS =
Expand Down Expand Up @@ -1057,6 +1133,8 @@ PVR_ERROR CTvheadend::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& type
TIMER_REPEATING_SERIESLINK_ATTRIBS,
/* Description. */
kodi::addon::GetLocalizedString(30369), // "Timer rule (series link)"
/* Custom settings definitions. */
customAutoRecSettingDefs,
/* Values definitions for priorities. */
priorityValues,
/* Values definitions for lifetime. */
Expand Down Expand Up @@ -1089,6 +1167,8 @@ PVR_ERROR CTvheadend::GetTimerTypes(std::vector<kodi::addon::PVRTimerType>& type
TIMER_REPEATING_EPG_ATTRIBS,
/* Let Kodi generate the description. */
"",
/* Custom settings definitions. */
customAutoRecSettingDefs,
/* Values definitions for priorities. */
priorityValues,
/* Values definitions for lifetime. */
Expand Down Expand Up @@ -1148,6 +1228,10 @@ bool CTvheadend::CreateTimer(const Recording& tvhTmr, kodi::addon::PVRTimer& tmr
: tmr.GetTimerType() == TIMER_ONCE_CREATED_BY_AUTOREC
? m_autoRecordings.GetTimerIntIdFromStringId(tvhTmr.GetAutorecId())
: 0);

/* Custom props */
tmr.SetCustomProperties(m_customTimerProps.GetProperties(tvhTmr));

return true;
}

Expand Down Expand Up @@ -1231,6 +1315,9 @@ PVR_ERROR CTvheadend::AddTimer(const kodi::addon::PVRTimer& timer)
LifetimeMapper::KodiToTvh(timer.GetLifetime())); // remove from disk
htsmsg_add_u32(m, "priority", timer.GetPriority());

/* Custom props. */
m_customTimerProps.AppendPropertiesToHTSPMessage(timer.GetCustomProperties(), m);

/* Send and Wait */
{
std::unique_lock<std::recursive_mutex> lock(m_conn->Mutex());
Expand Down Expand Up @@ -1346,6 +1433,9 @@ PVR_ERROR CTvheadend::UpdateTimer(const kodi::addon::PVRTimer& timer)
LifetimeMapper::KodiToTvh(timer.GetLifetime())); // remove from disk
htsmsg_add_u32(m, "priority", timer.GetPriority());

/* Custom props. */
m_customTimerProps.AppendPropertiesToHTSPMessage(timer.GetCustomProperties(), m);

return SendDvrUpdate(m);
}
else if (timer.GetTimerType() == TIMER_REPEATING_MANUAL)
Expand Down Expand Up @@ -1539,6 +1629,9 @@ bool CTvheadend::Connected(std::unique_lock<std::recursive_mutex>& lock)
/* Query the server for available streaming profiles */
QueryAvailableProfiles(lock);

/* Query the server for available DVR configurations */
QueryAvailableDvrConfigurations(lock);

/* Show a notification if the profile is not available */
const std::string streamingProfile = m_settings->GetStreamingProfile();

Expand Down Expand Up @@ -2686,6 +2779,14 @@ void CTvheadend::ParseRecordingAddOrUpdate(htsmsg_t* msg, bool bAdd)
rec.SetRatingSource(str);
}

str = htsmsg_get_str(msg, "configId");
if (str)
rec.SetConfigUuid(str);

str = htsmsg_get_str(msg, "comment");
if (str)
rec.SetComment(str);

if (m_conn->GetProtocol() >= 32)
{
if (rec.GetDescription().empty() && !rec.GetSubtitle().empty())
Expand Down
Loading

0 comments on commit 7b238c0

Please sign in to comment.