Skip to content
This repository has been archived by the owner on Apr 15, 2023. It is now read-only.

pvr: Mark recordings 'watched' / 'unwatched' #508

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions xbmc/addons/include/xbmc_pvr_dll.h
Expand Up @@ -201,6 +201,14 @@ extern "C"
*/
PVR_ERROR RenameRecording(const PVR_RECORDING &recording);

/*!
* @brief Set the play count of a recording on the backend.
* @param recording The recording to change the play count.
* @param count Play count.
* @return PVR_ERROR_NO_ERROR if the recording's play count has been set successfully.
*/
PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING &recording, int count);

//@}
/** @name PVR timer methods */
//@{
Expand Down Expand Up @@ -406,6 +414,7 @@ extern "C"
pClient->GetRecordings = GetRecordings;
pClient->DeleteRecording = DeleteRecording;
pClient->RenameRecording = RenameRecording;
pClient->SetRecordingPlayCount = SetRecordingPlayCount;

pClient->GetTimersAmount = GetTimersAmount;
pClient->GetTimers = GetTimers;
Expand Down
3 changes: 3 additions & 0 deletions xbmc/addons/include/xbmc_pvr_types.h
Expand Up @@ -158,6 +158,7 @@ extern "C" {
bool bHandlesInputStream; /*!< @brief (optional) true if this add-on provides an input stream. false if XBMC handles the stream. */
bool bHandlesDemuxing; /*!< @brief (optional) true if this add-on demultiplexes packets. */
bool bSupportsRecordingFolders; /*!< @brief (optional) true if the backend supports timers / recordings in folders. */
bool bSupportsRecordingPlayCount; /*!< @brief (optional) true if the backend supports play count for recordings. */
} ATTRIBUTE_PACKED PVR_ADDON_CAPABILITIES;

/*!
Expand Down Expand Up @@ -310,6 +311,7 @@ extern "C" {
int iLifetime; /*!< @brief (optional) life time in days of this recording */
int iGenreType; /*!< @brief (optional) genre type */
int iGenreSubType; /*!< @brief (optional) genre sub type */
bool iPlayCount; /*!< @brief (optional) play count of this recording on the client */
} ATTRIBUTE_PACKED PVR_RECORDING;

/*!
Expand Down Expand Up @@ -358,6 +360,7 @@ extern "C" {
PVR_ERROR (__cdecl* GetRecordings)(PVR_HANDLE handle);
PVR_ERROR (__cdecl* DeleteRecording)(const PVR_RECORDING &recording);
PVR_ERROR (__cdecl* RenameRecording)(const PVR_RECORDING &recording);
PVR_ERROR (__cdecl* SetRecordingPlayCount)(const PVR_RECORDING &recording, int count);
//@}

/** @name PVR timer methods */
Expand Down
52 changes: 40 additions & 12 deletions xbmc/pvr/addons/PVRClient.cpp
Expand Up @@ -85,18 +85,19 @@ void CPVRClient::ResetProperties(void)

void CPVRClient::ResetAddonCapabilities(void)
{
m_addonCapabilities.bSupportsChannelSettings = false;
m_addonCapabilities.bSupportsTimeshift = false;
m_addonCapabilities.bSupportsEPG = false;
m_addonCapabilities.bSupportsTV = false;
m_addonCapabilities.bSupportsRadio = false;
m_addonCapabilities.bSupportsRecordings = false;
m_addonCapabilities.bSupportsTimers = false;
m_addonCapabilities.bSupportsChannelGroups = false;
m_addonCapabilities.bSupportsChannelScan = false;
m_addonCapabilities.bHandlesInputStream = false;
m_addonCapabilities.bHandlesDemuxing = false;
m_addonCapabilities.bSupportsRecordingFolders = false;
m_addonCapabilities.bSupportsChannelSettings = false;
m_addonCapabilities.bSupportsTimeshift = false;
m_addonCapabilities.bSupportsEPG = false;
m_addonCapabilities.bSupportsTV = false;
m_addonCapabilities.bSupportsRadio = false;
m_addonCapabilities.bSupportsRecordings = false;
m_addonCapabilities.bSupportsTimers = false;
m_addonCapabilities.bSupportsChannelGroups = false;
m_addonCapabilities.bSupportsChannelScan = false;
m_addonCapabilities.bHandlesInputStream = false;
m_addonCapabilities.bHandlesDemuxing = false;
m_addonCapabilities.bSupportsRecordingFolders = false;
m_addonCapabilities.bSupportsRecordingPlayCount = false;
}

bool CPVRClient::Create(int iClientId)
Expand Down Expand Up @@ -632,6 +633,33 @@ PVR_ERROR CPVRClient::RenameRecording(const CPVRRecording &recording)
return retVal;
}

PVR_ERROR CPVRClient::SetRecordingPlayCount(const CPVRRecording &recording, int count)
{
PVR_ERROR retVal = PVR_ERROR_UNKNOWN;
if (!m_bReadyToUse)
return retVal;

if (!m_addonCapabilities.bSupportsRecordingPlayCount)
return PVR_ERROR_NOT_IMPLEMENTED;

try
{
PVR_RECORDING tag;
PVRWriteClientRecordingInfo(recording, tag);

retVal = m_pStruct->SetRecordingPlayCount(tag, count);

LogError(retVal, __FUNCTION__);
}
catch (exception &e)
{
CLog::Log(LOGERROR, "PVRClient - %s - exception '%s' caught while trying to call SetRecordingPlayCount() on addon '%s'. please contact the developer of this addon: %s",
__FUNCTION__, e.what(), GetFriendlyName().c_str(), Author().c_str());
}

return retVal;
}

int CPVRClient::GetTimersAmount(void)
{
int iReturn = -1;
Expand Down
8 changes: 8 additions & 0 deletions xbmc/pvr/addons/PVRClient.h
Expand Up @@ -256,6 +256,14 @@ namespace PVR
*/
PVR_ERROR RenameRecording(const CPVRRecording &recording);

/*!
* @brief Set the play count of a recording on the backend.
* @param recording The recording to set the play count.
* @param count Play count.
* @return PVR_ERROR_NO_ERROR if the recording's play count has been set successfully.
*/
PVR_ERROR SetRecordingPlayCount(const CPVRRecording &recording, int count);

//@}
/** @name PVR timer methods */
//@{
Expand Down
12 changes: 12 additions & 0 deletions xbmc/pvr/addons/PVRClients.cpp
Expand Up @@ -798,6 +798,18 @@ bool CPVRClients::DeleteRecording(const CPVRRecording &recording, PVR_ERROR *err
return *error == PVR_ERROR_NO_ERROR;
}

bool CPVRClients::SetRecordingPlayCount(const CPVRRecording &recording, int count, PVR_ERROR *error)
{
*error = PVR_ERROR_UNKNOWN;
boost::shared_ptr<CPVRClient> client;
if (GetConnectedClient(recording.m_iClientId, client) && client->GetAddonCapabilities().bSupportsRecordingPlayCount)
*error = client->SetRecordingPlayCount(recording, count);
else
CLog::Log(LOGERROR, "PVR - %s - client %d does not support setting recording's play count",__FUNCTION__, recording.m_iClientId);

return *error == PVR_ERROR_NO_ERROR;
}

bool CPVRClients::IsRecordingOnPlayingChannel(void) const
{
CPVRChannel currentChannel;
Expand Down
9 changes: 9 additions & 0 deletions xbmc/pvr/addons/PVRClients.h
Expand Up @@ -464,6 +464,15 @@ namespace PVR
*/
bool DeleteRecording(const CPVRRecording &recording, PVR_ERROR *error);

/*!
* @brief Set play count of a recording on the backend.
* @param recording The recording to set the play count.
* @param count Play count.
* @param error An error if it occured.
* @return True if the recording's play count was set successfully, false otherwise.
*/
bool SetRecordingPlayCount(const CPVRRecording &recording, int count, PVR_ERROR *error);

/*!
* @brief Check whether there is an active recording on the current channel.
* @return True if there is, false otherwise.
Expand Down
19 changes: 18 additions & 1 deletion xbmc/pvr/recordings/PVRRecording.cpp
Expand Up @@ -53,6 +53,7 @@ CPVRRecording::CPVRRecording(const PVR_RECORDING &recording, unsigned int iClien
m_strStreamURL = recording.strStreamURL;
m_strChannelName = recording.strChannelName;
m_genre = StringUtils::Split(CEpg::ConvertGenreIdToString(recording.iGenreType, recording.iGenreSubType), g_advancedSettings.m_videoItemSeparator);
m_iRecPlayCount = recording.iPlayCount;
}

bool CPVRRecording::operator ==(const CPVRRecording& right) const
Expand All @@ -70,7 +71,8 @@ bool CPVRRecording::operator ==(const CPVRRecording& right) const
m_iLifetime == right.m_iLifetime &&
m_strDirectory == right.m_strDirectory &&
m_strFileNameAndPath == right.m_strFileNameAndPath &&
m_strTitle == right.m_strTitle);
m_strTitle == right.m_strTitle &&
m_iRecPlayCount == right.m_iRecPlayCount);
}

bool CPVRRecording::operator !=(const CPVRRecording& right) const
Expand All @@ -88,6 +90,7 @@ void CPVRRecording::Reset(void)
m_iPriority = -1;
m_iLifetime = -1;
m_strFileNameAndPath = StringUtils::EmptyString;
m_iRecPlayCount = 0;

m_recordingTime.Reset();
CVideoInfoTag::Reset();
Expand Down Expand Up @@ -126,6 +129,19 @@ bool CPVRRecording::Rename(const CStdString &strNewName)
return true;
}

bool CPVRRecording::SetPlayCount(int count)
{
PVR_ERROR error;
m_iRecPlayCount = count;
if (!g_PVRClients->SetRecordingPlayCount(*this, count, &error))
{
DisplayError(error);
return false;
}

return true;
}

void CPVRRecording::DisplayError(PVR_ERROR err) const
{
if (err == PVR_ERROR_SERVER_ERROR)
Expand Down Expand Up @@ -155,6 +171,7 @@ void CPVRRecording::Update(const CPVRRecording &tag)
m_strStreamURL = tag.m_strStreamURL;
m_strChannelName = tag.m_strChannelName;
m_genre = tag.m_genre;
m_iRecPlayCount = tag.m_iRecPlayCount;

CStdString strShow;
strShow.Format("%s - ", g_localizeStrings.Get(20364).c_str());
Expand Down
8 changes: 8 additions & 0 deletions xbmc/pvr/recordings/PVRRecording.h
Expand Up @@ -53,6 +53,7 @@ namespace PVR
int m_iLifetime; /*!< lifetime of this recording */
CStdString m_strStreamURL; /*!< stream URL. if empty use pvr client */
CStdString m_strDirectory; /*!< directory of this recording on the client */
bool m_iRecPlayCount; /*!< play count of this recording on the client */

CPVRRecording(void);
CPVRRecording(const PVR_RECORDING &recording, unsigned int iClientId);
Expand Down Expand Up @@ -85,6 +86,13 @@ namespace PVR
*/
bool Rename(const CStdString &strNewName);

/*!
* @brief Set this recording's play count on the client (if supported).
* @param count play count.
* @return True if play count was set successfully, false otherwise.
*/
bool SetPlayCount(int count);

/*!
* @brief Update this tag with the contents of the given tag.
* @param tag The new tag info.
Expand Down
90 changes: 88 additions & 2 deletions xbmc/pvr/recordings/PVRRecordings.cpp
Expand Up @@ -106,9 +106,18 @@ void CPVRRecordings::GetContents(const CStdString &strDirectory, CFileItemList *
pFileItem->SetLabel2(current->RecordingTimeAsLocalTime().GetAsLocalizedDateTime(true, false));
pFileItem->m_dateTime = current->RecordingTimeAsLocalTime();
pFileItem->SetPath(current->m_strFileNameAndPath);
CVideoDatabase db;
if (db.Open())

// Set the play count either directly from client (if supported) or from video db
if (g_PVRClients->GetAddonCapabilities(pFileItem->GetPVRRecordingInfoTag()->m_iClientId).bSupportsRecordingPlayCount)
{
pFileItem->GetPVRRecordingInfoTag()->m_playCount=pFileItem->GetPVRRecordingInfoTag()->m_iRecPlayCount;
}
else
{
CVideoDatabase db;
if (db.Open())
pFileItem->GetPVRRecordingInfoTag()->m_playCount=db.GetPlayCount(*pFileItem);
}
pFileItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, pFileItem->GetPVRRecordingInfoTag()->m_playCount > 0);

results->Add(pFileItem);
Expand All @@ -119,6 +128,8 @@ void CPVRRecordings::GetSubDirectories(const CStdString &strBase, CFileItemList
{
CStdString strUseBase = TrimSlashes(strBase);

std::set<CStdString> unwatchedFolders;

for (unsigned int iRecordingPtr = 0; iRecordingPtr < size(); iRecordingPtr++)
{
CPVRRecording *current = at(iRecordingPtr);
Expand All @@ -140,6 +151,20 @@ void CPVRRecordings::GetSubDirectories(const CStdString &strBase, CFileItemList
pFileItem->SetLabel(strCurrent);
pFileItem->SetLabelPreformated(true);
pFileItem->m_dateTime = current->RecordingTimeAsLocalTime();

// Initialize folder overlay from play count (either directly from client or from video database)
CVideoDatabase db;
bool supportsPlayCount = g_PVRClients->GetAddonCapabilities(current->m_iClientId).bSupportsRecordingPlayCount;
if ((supportsPlayCount && current->m_iRecPlayCount > 0) ||
(!supportsPlayCount && db.Open() && db.GetPlayCount(*pFileItem) > 0))
{
pFileItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_WATCHED, false);
}
else
{
unwatchedFolders.insert(strFilePath);
}

results->Add(pFileItem);
}
else
Expand All @@ -148,6 +173,17 @@ void CPVRRecordings::GetSubDirectories(const CStdString &strBase, CFileItemList
pFileItem=results->Get(strFilePath);
if (pFileItem->m_dateTime<current->RecordingTimeAsLocalTime())
pFileItem->m_dateTime = current->RecordingTimeAsLocalTime();

// Unset folder overlay if recording is unwatched
if (unwatchedFolders.find(strFilePath) == unwatchedFolders.end()) {
CVideoDatabase db;
bool supportsPlayCount = g_PVRClients->GetAddonCapabilities(current->m_iClientId).bSupportsRecordingPlayCount;
if ((supportsPlayCount && current->m_iRecPlayCount == 0) || (!supportsPlayCount && db.Open() && db.GetPlayCount(*pFileItem) == 0))
{
pFileItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, false);
unwatchedFolders.insert(strFilePath);
}
}
}
}

Expand Down Expand Up @@ -257,6 +293,56 @@ bool CPVRRecordings::RenameRecording(CFileItem &item, CStdString &strNewName)
return tag->Rename(strNewName);
}

bool CPVRRecordings::SetRecordingsPlayCount(const CFileItemPtr &item, int count)
{
bool bResult = false;

CVideoDatabase database;
if (database.Open())
{
bResult = true;

CLog::Log(LOGDEBUG, "CPVRRecordings - %s - item path %s", __FUNCTION__, item->GetPath().c_str());
CFileItemList items;
if (item->m_bIsFolder)
{
CStdString strPath = item->GetPath();
CDirectory::GetDirectory(strPath, items);
}
else
items.Add(item);

CLog::Log(LOGDEBUG, "CPVRRecordings - %s - will set watched for %d items", __FUNCTION__, items.Size());
for (int i=0;i<items.Size();++i)
{
CLog::Log(LOGDEBUG, "CPVRRecordings - %s - setting watched for item %d", __FUNCTION__, i);

CFileItemPtr pItem=items[i];
if (pItem->m_bIsFolder)
{
CLog::Log(LOGDEBUG, "CPVRRecordings - %s - path %s is a folder, will call recursively", __FUNCTION__, pItem->GetPath().c_str());
if (pItem->GetLabel() != "..")
{
SetRecordingsPlayCount(pItem, count);
}
continue;
}

pItem->GetPVRRecordingInfoTag()->SetPlayCount(count);

// Clear resume bookmark
if (count > 0)
database.ClearBookMarksOfFile(pItem->GetPath(), CBookmark::RESUME);

database.SetPlayCount(*pItem, count);
}

database.Close();
}

return bResult;
}

bool CPVRRecordings::GetDirectory(const CStdString& strPath, CFileItemList &items)
{
bool bSuccess(false);
Expand Down
1 change: 1 addition & 0 deletions xbmc/pvr/recordings/PVRRecordings.h
Expand Up @@ -63,6 +63,7 @@ namespace PVR
int GetRecordings(CFileItemList* results);
bool DeleteRecording(const CFileItem &item);
bool RenameRecording(CFileItem &item, CStdString &strNewName);
bool SetRecordingsPlayCount(const CFileItemPtr &item, int count);

bool GetDirectory(const CStdString& strPath, CFileItemList &items);
CPVRRecording *GetByPath(const CStdString &path);
Expand Down