Skip to content

Commit

Permalink
Implement proper timerec and autorec update methods.
Browse files Browse the repository at this point in the history
  • Loading branch information
Glenn-1990 committed Dec 21, 2015
1 parent 0198212 commit 63f1cab
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 54 deletions.
86 changes: 58 additions & 28 deletions src/AutoRecordings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,62 @@ const unsigned int AutoRecordings::GetTimerIntIdFromStringId(const std::string &
return 0;
}

const std::string AutoRecordings::GetTimerStringIdFromIntId(const int intId) const
{
for (auto tit = m_autoRecordings.begin(); tit != m_autoRecordings.end(); ++tit)
{
if (tit->second.GetId() == intId)
return tit->second.GetStringId();
}

tvherror("Autorec: Unable to obtain string id for int id %s", intId);
return "";
}

PVR_ERROR AutoRecordings::SendAutorecAdd(const PVR_TIMER &timer)
{
return SendAutorecAddOrUpdate(timer, false);
}

PVR_ERROR AutoRecordings::SendAutorecUpdate(const PVR_TIMER &timer)
{
if (m_conn.GetProtocol() >= 25)
return SendAutorecAddOrUpdate(timer, true);

/* Note: there is no "updateAutorec" htsp method for htsp version < 25, thus delete + add. */
PVR_ERROR error = SendAutorecDelete(timer);

if (error == PVR_ERROR_NO_ERROR)
error = SendAutorecAdd(timer);

return error;
}

PVR_ERROR AutoRecordings::SendAutorecAddOrUpdate(const PVR_TIMER &timer, bool update)
{
uint32_t u32;
std::string method = update ? "updateAutorecEntry" : "addAutorecEntry";

/* Build message */
htsmsg_t *m = htsmsg_create_map();
if (update)
{
std::string strId = GetTimerStringIdFromIntId(timer.iClientIndex);
if (strId.empty())
{
htsmsg_destroy(m);
return PVR_ERROR_FAILED;
}

htsmsg_add_str(m, "id", strId.c_str()); // Autorec DVR Entry ID (string!)
htsmsg_add_s64(m, "channelId", timer.iClientChannelUid); // channelId is signed for update!, -1 = any
}
else
{
if (timer.iClientChannelUid >= 0)
htsmsg_add_u32(m, "channelId", timer.iClientChannelUid); // channelId is unsigned for add!, not sending = any
}

htsmsg_add_str(m, "name", timer.strTitle);

/* epg search data match string (regexp) */
Expand All @@ -165,8 +215,7 @@ PVR_ERROR AutoRecordings::SendAutorecAdd(const PVR_TIMER &timer)
else
htsmsg_add_u32(m, "retention", timer.iLifetime); // remove from tvh database


htsmsg_add_u32(m, "daysOfWeek", timer.iWeekdays);
htsmsg_add_u32(m, "daysOfWeek", timer.iWeekdays);

if (m_conn.GetProtocol() >= 20)
htsmsg_add_u32(m, "dupDetect", timer.iPreventDuplicateEpisodes);
Expand All @@ -180,9 +229,6 @@ PVR_ERROR AutoRecordings::SendAutorecAdd(const PVR_TIMER &timer)
if (strcmp(timer.strDirectory, "/") != 0)
htsmsg_add_str(m, "directory", timer.strDirectory);

/* Note: not sending any of the following three values will be interpreted by tvh as "any". */
if (timer.iClientChannelUid >= 0)
htsmsg_add_u32(m, "channelId", timer.iClientChannelUid);

/* bAutorecApproxTime enabled: => start time in kodi = approximate start time in tvh */
/* => 'approximate' = starting window / 2 */
Expand Down Expand Up @@ -234,7 +280,7 @@ PVR_ERROR AutoRecordings::SendAutorecAdd(const PVR_TIMER &timer)
/* Send and Wait */
{
CLockObject lock(m_conn.Mutex());
m = m_conn.SendAndWait("addAutorecEntry", m);
m = m_conn.SendAndWait(method.c_str(), m);
}

if (m == NULL)
Expand All @@ -243,39 +289,21 @@ PVR_ERROR AutoRecordings::SendAutorecAdd(const PVR_TIMER &timer)
/* Check for error */
if (htsmsg_get_u32(m, "success", &u32))
{
tvherror("malformed addAutorecEntry response: 'success' missing");
tvherror("malformed %s response: 'success' missing", method.c_str());
u32 = PVR_ERROR_FAILED;
}
htsmsg_destroy(m);

return u32 == 1 ? PVR_ERROR_NO_ERROR : PVR_ERROR_FAILED;
}

PVR_ERROR AutoRecordings::SendAutorecUpdate(const PVR_TIMER &timer)
{
/* Note: there is no "updateAutorec" htsp method, thus delete + add. */

PVR_ERROR error = SendAutorecDelete(timer);

if (error == PVR_ERROR_NO_ERROR)
error = SendAutorecAdd(timer);

return error;
}

PVR_ERROR AutoRecordings::SendAutorecDelete(const PVR_TIMER &timer)
{
uint32_t u32;

std::string strId;
for (auto tit = m_autoRecordings.begin(); tit != m_autoRecordings.end(); ++tit)
{
if (tit->second.GetId() == timer.iClientIndex)
{
strId = tit->second.GetStringId();
break;
}
}
std::string strId = GetTimerStringIdFromIntId(timer.iClientIndex);
if (strId.empty())
return PVR_ERROR_FAILED;

htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "id", strId.c_str()); // Autorec DVR Entry ID (string!)
Expand Down Expand Up @@ -455,6 +483,8 @@ bool AutoRecordings::ParseAutorecAddOrUpdate(htsmsg_t *msg, bool bAdd)
{
rec.SetChannel(u32);
}
else
rec.SetChannel(PVR_TIMER_ANY_CHANNEL); // an empty channel field = any channel

if (!htsmsg_get_u32(msg, "fulltext", &u32))
{
Expand Down
3 changes: 3 additions & 0 deletions src/AutoRecordings.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ class AutoRecordings
bool ParseAutorecDelete(htsmsg_t *msg);

private:
const std::string GetTimerStringIdFromIntId(const int intId) const;
PVR_ERROR SendAutorecAddOrUpdate(const PVR_TIMER &timer, bool update);

CHTSPConnection &m_conn;
tvheadend::entity::AutoRecordingsMap m_autoRecordings;
};
88 changes: 62 additions & 26 deletions src/TimeRecordings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,23 +111,69 @@ const unsigned int TimeRecordings::GetTimerIntIdFromStringId(const std::string &
return 0;
}

const std::string TimeRecordings::GetTimerStringIdFromIntId(const int intId) const
{
for (auto tit = m_timeRecordings.begin(); tit != m_timeRecordings.end(); ++tit)
{
if (tit->second.GetId() == intId)
return tit->second.GetStringId();
}

tvherror("Timerec: Unable to obtain string id for int id %s", intId);
return "";
}

PVR_ERROR TimeRecordings::SendTimerecAdd(const PVR_TIMER &timer)
{
return SendTimerecAddOrUpdate(timer, false);
}

PVR_ERROR TimeRecordings::SendTimerecUpdate(const PVR_TIMER &timer)
{
if (m_conn.GetProtocol() >= 25)
return SendTimerecAddOrUpdate(timer, true);

/* Note: there is no "updateTimerec" htsp method for htsp version < 25, thus delete + add. */
PVR_ERROR error = SendTimerecDelete(timer);

if (error == PVR_ERROR_NO_ERROR)
error = SendTimerecAdd(timer);

return error;
}

PVR_ERROR TimeRecordings::SendTimerecAddOrUpdate(const PVR_TIMER &timer, bool update)
{
uint32_t u32;
std::string method = update ? "updateTimerecEntry" : "addTimerecEntry";

/* Build message */
htsmsg_t *m = htsmsg_create_map();
if (update)
{
std::string strId = GetTimerStringIdFromIntId(timer.iClientIndex);
if (strId.empty())
{
htsmsg_destroy(m);
return PVR_ERROR_FAILED;
}

htsmsg_add_str(m, "id", strId.c_str()); // Autorec DVR Entry ID (string!)
htsmsg_add_s64(m, "channelId", timer.iClientChannelUid); // channelId is signed for update!
}
else
htsmsg_add_u32(m, "channelId", timer.iClientChannelUid); // channelId is unsigned for add!

char title[PVR_ADDON_NAME_STRING_LENGTH+6];
const char *titleExt = "%F-%R"; // timerec title should contain the pattern (e.g. %F-%R) for the generated recording files. Scary...
snprintf(title, sizeof(title), "%s-%s", timer.strTitle, titleExt);

/* Build message */
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "name", timer.strTitle);
htsmsg_add_str(m, "title", title);
struct tm *tm_start = localtime(&timer.startTime);
htsmsg_add_u32(m, "start", tm_start->tm_hour * 60 + tm_start->tm_min); // start time in minutes from midnight
struct tm *tm_stop = localtime(&timer.endTime);
htsmsg_add_u32(m, "stop", tm_stop->tm_hour * 60 + tm_stop->tm_min); // end time in minutes from midnight
htsmsg_add_u32(m, "channelId", timer.iClientChannelUid);

if (m_conn.GetProtocol() >= 25)
{
Expand All @@ -150,7 +196,7 @@ PVR_ERROR TimeRecordings::SendTimerecAdd(const PVR_TIMER &timer)
/* Send and Wait */
{
CLockObject lock(m_conn.Mutex());
m = m_conn.SendAndWait("addTimerecEntry", m);
m = m_conn.SendAndWait(method.c_str(), m);
}

if (m == NULL)
Expand All @@ -159,39 +205,21 @@ PVR_ERROR TimeRecordings::SendTimerecAdd(const PVR_TIMER &timer)
/* Check for error */
if (htsmsg_get_u32(m, "success", &u32))
{
tvherror("malformed addTimerecEntry response: 'success' missing");
tvherror("malformed %s response: 'success' missing", method.c_str());
u32 = PVR_ERROR_FAILED;
}
htsmsg_destroy(m);

return u32 == 1 ? PVR_ERROR_NO_ERROR : PVR_ERROR_FAILED;
}

PVR_ERROR TimeRecordings::SendTimerecUpdate(const PVR_TIMER &timer)
{
/* Note: there is no "updateTimerec" htsp method, thus delete + add. */

PVR_ERROR error = SendTimerecDelete(timer);

if (error == PVR_ERROR_NO_ERROR)
error = SendTimerecAdd(timer);

return error;
}

PVR_ERROR TimeRecordings::SendTimerecDelete(const PVR_TIMER &timer)
{
uint32_t u32;

std::string strId;
for (auto tit = m_timeRecordings.begin(); tit != m_timeRecordings.end(); ++tit)
{
if (tit->second.GetId() == timer.iClientIndex)
{
strId = tit->second.GetStringId();
break;
}
}
std::string strId = GetTimerStringIdFromIntId(timer.iClientIndex);
if (strId.empty())
return PVR_ERROR_FAILED;

htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "id", strId.c_str()); // Timerec DVR Entry ID (string!)
Expand Down Expand Up @@ -340,6 +368,14 @@ bool TimeRecordings::ParseTimerecAddOrUpdate(htsmsg_t *msg, bool bAdd)
{
rec.SetChannel(u32);
}
else
{
/* A timerec can also have an empty channel field,
* the user can delete a channel or even an automated bouquet update can do this
* let kodi know that no channel is assigned, in this way the user can assign a new channel to this timerec
* note: "any channel" will be interpreted as "no channel" for timerecs by kodi */
rec.SetChannel(PVR_TIMER_ANY_CHANNEL);
}

return true;
}
Expand Down
3 changes: 3 additions & 0 deletions src/TimeRecordings.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ class TimeRecordings
bool ParseTimerecDelete(htsmsg_t *msg);

private:
const std::string GetTimerStringIdFromIntId(const int intId) const;
PVR_ERROR SendTimerecAddOrUpdate(const PVR_TIMER &timer, bool update);

CHTSPConnection &m_conn;
tvheadend::entity::TimeRecordingsMap m_timeRecordings;
};

0 comments on commit 63f1cab

Please sign in to comment.