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 Jan 4, 2016
1 parent 0377a4f commit 9efea12
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 59 deletions.
91 changes: 61 additions & 30 deletions src/AutoRecordings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,57 @@ const unsigned int AutoRecordings::GetTimerIntIdFromStringId(const std::string &
return 0;
}

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

Logger::Log(LogLevel::ERROR, "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;
const 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_str(m, "name", timer.strTitle);

/* epg search data match string (regexp) */
Expand All @@ -161,14 +206,19 @@ PVR_ERROR AutoRecordings::SendAutorecAdd(const PVR_TIMER &timer)

if (m_conn.GetProtocol() >= 25)
{
htsmsg_add_u32(m, "removal", timer.iLifetime); // remove from disk
htsmsg_add_u32(m, "retention", DVR_RET_ONREMOVE); // remove from tvh database
htsmsg_add_u32(m, "removal", timer.iLifetime); // remove from disk
htsmsg_add_u32(m, "retention", DVR_RET_ONREMOVE); // remove from tvh database
htsmsg_add_s64(m, "channelId", timer.iClientChannelUid); // channelId is signed for >= htspv25, -1 = any
}
else
htsmsg_add_u32(m, "retention", timer.iLifetime); // remove from tvh database
{
htsmsg_add_u32(m, "retention", timer.iLifetime); // remove from tvh database

if (timer.iClientChannelUid >= 0)
htsmsg_add_u32(m, "channelId", timer.iClientChannelUid); // channelId is unsigned for < htspv25, not sending = any
}

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 @@ -182,9 +232,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 @@ -236,7 +283,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 @@ -245,39 +292,21 @@ PVR_ERROR AutoRecordings::SendAutorecAdd(const PVR_TIMER &timer)
/* Check for error */
if (htsmsg_get_u32(m, "success", &u32))
{
Logger::Log(LogLevel::ERROR, "malformed addAutorecEntry response: 'success' missing");
Logger::Log(LogLevel::ERROR, "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 @@ -457,6 +486,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(int intId) const;
PVR_ERROR SendAutorecAddOrUpdate(const PVR_TIMER &timer, bool update);

CHTSPConnection &m_conn;
tvheadend::entity::AutoRecordingsMap m_autoRecordings;
};
96 changes: 67 additions & 29 deletions src/TimeRecordings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,31 +113,79 @@ const unsigned int TimeRecordings::GetTimerIntIdFromStringId(const std::string &
return 0;
}

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

Logger::Log(LogLevel::ERROR, "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;
const 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!)
}

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)
{
htsmsg_add_u32(m, "removal", timer.iLifetime); // remove from disk
htsmsg_add_u32(m, "retention", DVR_RET_ONREMOVE); // remove from tvh database
htsmsg_add_u32(m, "removal", timer.iLifetime); // remove from disk
htsmsg_add_u32(m, "retention", DVR_RET_ONREMOVE); // remove from tvh database
htsmsg_add_s64(m, "channelId", timer.iClientChannelUid); // channelId is signed for >= htspv25
}
else
htsmsg_add_u32(m, "retention", timer.iLifetime); // remove from tvh database
{
htsmsg_add_u32(m, "retention", timer.iLifetime); // remove from tvh database
htsmsg_add_u32(m, "channelId", timer.iClientChannelUid); // channelId is unsigned for < htspv25
}

htsmsg_add_u32(m, "daysOfWeek", timer.iWeekdays);
htsmsg_add_u32(m, "priority", timer.iPriority);
Expand All @@ -152,7 +200,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 @@ -161,39 +209,21 @@ PVR_ERROR TimeRecordings::SendTimerecAdd(const PVR_TIMER &timer)
/* Check for error */
if (htsmsg_get_u32(m, "success", &u32))
{
Logger::Log(LogLevel::ERROR, "malformed addTimerecEntry response: 'success' missing");
Logger::Log(LogLevel::ERROR, "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 @@ -342,6 +372,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(int intId) const;
PVR_ERROR SendTimerecAddOrUpdate(const PVR_TIMER &timer, bool update);

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

0 comments on commit 9efea12

Please sign in to comment.