std::string CPVRGUIActions::GetResumeLabel(const CFileItem &item) const { std::string resumeString; const CPVRRecordingPtr recording(CPVRItem(CFileItemPtr(new CFileItem(item))).GetRecording()); if (recording && !recording->IsDeleted()) { // First try to find the resume position on the back-end, if that fails use video database int positionInSeconds = recording->GetLastPlayedPosition(); // If the back-end does report a saved position it will be picked up by FileItem if (positionInSeconds < 0) { CVideoDatabase db; if (db.Open()) { CBookmark bookmark; std::string itemPath(recording->m_strFileNameAndPath); if (db.GetResumeBookMark(itemPath, bookmark) ) positionInSeconds = lrint(bookmark.timeInSeconds); db.Close(); } } // Suppress resume from 0 if (positionInSeconds > 0) resumeString = StringUtils::Format(g_localizeStrings.Get(12022).c_str(), StringUtils::SecondsToTimeString(positionInSeconds, TIME_FORMAT_HH_MM_SS).c_str()); } return resumeString; }
bool CPVRClients::OpenStream(const CPVRRecordingPtr &channel) { assert(channel.get()); bool bReturn(false); CloseStream(); /* try to open the recording stream on the client */ PVR_CLIENT client; if (GetConnectedClient(channel->m_iClientId, client) && client->OpenStream(channel)) { CSingleLock lock(m_critSection); CDateTime endTime = channel->RecordingTimeAsLocalTime() + CDateTimeSpan(0, 0, channel->GetDuration() / 60, channel->GetDuration() % 60); m_bIsRecordingInProgress = (endTime > CDateTime::GetCurrentDateTime()); if (m_bIsRecordingInProgress) CLog::Log(LOGNOTICE, "PVRClients - %s - recording is still in progress, end time = %s", __FUNCTION__, endTime.GetAsDBDateTime().c_str()); m_playingClientId = channel->m_iClientId; m_bIsPlayingRecording = true; m_strPlayingClientName = client->GetFriendlyName(); bReturn = true; } return bReturn; }
CFileItemPtr CPVRRecordings::GetByPath(const std::string &path) { CURL url(path); std::string fileName = url.GetFileName(); URIUtils::RemoveSlashAtEnd(fileName); CSingleLock lock(m_critSection); if (StringUtils::StartsWith(fileName, PVR_RECORDING_BASE_PATH "/")) { // Check directory name is for deleted recordings fileName.erase(0, sizeof(PVR_RECORDING_BASE_PATH)); bool bDeleted = StringUtils::StartsWith(fileName, PVR_RECORDING_DELETED_PATH "/"); for (PVR_RECORDINGMAP_CITR it = m_recordings.begin(); it != m_recordings.end(); it++) { CPVRRecordingPtr current = it->second; if (!URIUtils::PathEquals(path, current->m_strFileNameAndPath) || bDeleted != current->IsDeleted()) continue; CFileItemPtr fileItem(new CFileItem(current)); return fileItem; } } CFileItemPtr fileItem(new CFileItem); return fileItem; }
CFileItemPtr CPVRRecordings::GetByPath(const std::string &path) { CSingleLock lock(m_critSection); CPVRRecordingsPath recPath(path); if (recPath.IsValid()) { bool bDeleted = recPath.IsDeleted(); bool bRadio = recPath.IsRadio(); for (const auto recording : m_recordings) { CPVRRecordingPtr current = recording.second; // Omit recordings not matching criteria if (!URIUtils::PathEquals(path, current->m_strFileNameAndPath) || bDeleted != current->IsDeleted() || bRadio != current->IsRadio()) continue; CFileItemPtr fileItem(new CFileItem(current)); return fileItem; } } CFileItemPtr fileItem(new CFileItem); return fileItem; }
bool CPVRRecordings::SetRecordingsPlayCount(const CFileItemPtr &item, int count) { bool bResult = false; if (m_database.IsOpen()) { bResult = true; CLog::Log(LOGDEBUG, "CPVRRecordings - %s - item path %s", __FUNCTION__, item->GetPath().c_str()); CFileItemList items; if (item->m_bIsFolder) { XFILE::CDirectory::GetDirectory(item->GetPath(), 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; } if (!pItem->HasPVRRecordingInfoTag()) continue; const CPVRRecordingPtr recording = pItem->GetPVRRecordingInfoTag(); if (recording) { recording->SetPlayCount(count); // Clear resume bookmark if (count > 0) { m_database.ClearBookMarksOfFile(pItem->GetPath(), CBookmark::RESUME); recording->SetLastPlayedPosition(0); } m_database.SetPlayCount(*pItem, count); } } } return bResult; }
bool CPVRRecordings::GetDirectory(const std::string& strPath, CFileItemList &items) { CSingleLock lock(m_critSection); CPVRRecordingsPath recPath(strPath); if (recPath.IsValid()) { // Get the directory structure if in non-flatten mode // Deleted view is always flatten. So only for an active view std::string strDirectory(recPath.GetDirectoryPath()); if (!recPath.IsDeleted() && m_bGroupItems) GetSubDirectories(recPath, &items); // get all files of the currrent directory or recursively all files starting at the current directory if in flatten mode for (PVR_RECORDINGMAP_CITR it = m_recordings.begin(); it != m_recordings.end(); it++) { CPVRRecordingPtr current = it->second; // skip items that are not members of the target directory if (!IsDirectoryMember(strDirectory, current->m_strDirectory) || current->IsDeleted() != recPath.IsDeleted()) continue; if (m_database.IsOpen()) current->UpdateMetadata(m_database); CFileItemPtr pFileItem(new CFileItem(current)); pFileItem->SetLabel2(current->RecordingTimeAsLocalTime().GetAsLocalizedDateTime(true, false)); pFileItem->m_dateTime = current->RecordingTimeAsLocalTime(); pFileItem->SetPath(current->m_strFileNameAndPath); // Set art if (!current->m_strIconPath.empty()) { pFileItem->SetIconImage(current->m_strIconPath); pFileItem->SetArt("icon", current->m_strIconPath); } if (!current->m_strThumbnailPath.empty()) pFileItem->SetArt("thumb", current->m_strThumbnailPath); if (!current->m_strFanartPath.empty()) pFileItem->SetArt("fanart", current->m_strFanartPath); // Use the channel icon as a fallback when a thumbnail is not available pFileItem->SetArtFallback("thumb", "icon"); pFileItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, pFileItem->GetPVRRecordingInfoTag()->m_playCount > 0); items.Add(pFileItem); } return true; } return false; }
bool CPVRRecordings::Undelete(const CFileItem &item) { if (!item.IsDeletedPVRRecording()) { CLog::Log(LOGERROR, "CPVRRecordings - %s - cannot undelete file: no valid recording tag", __FUNCTION__); return false; } CPVRRecordingPtr tag = item.GetPVRRecordingInfoTag(); return tag->Undelete(); }
bool CPVRRecordings::RenameRecording(CFileItem &item, std::string &strNewName) { if (!item.IsUsablePVRRecording()) { CLog::Log(LOGERROR, "CPVRRecordings - %s - cannot rename file: no valid recording tag", __FUNCTION__); return false; } CPVRRecordingPtr tag = item.GetPVRRecordingInfoTag(); return tag->Rename(strNewName); }
void CPVRRecordings::GetAll(CFileItemList &items, bool bDeleted) { CSingleLock lock(m_critSection); for (PVR_RECORDINGMAP_CITR it = m_recordings.begin(); it != m_recordings.end(); it++) { CPVRRecordingPtr current = it->second; if (current->IsDeleted() != bDeleted) continue; if (m_database.IsOpen()) current->UpdateMetadata(m_database); CFileItemPtr pFileItem(new CFileItem(current)); pFileItem->SetLabel2(current->RecordingTimeAsLocalTime().GetAsLocalizedDateTime(true, false)); pFileItem->m_dateTime = current->RecordingTimeAsLocalTime(); pFileItem->SetPath(current->m_strFileNameAndPath); pFileItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, pFileItem->GetPVRRecordingInfoTag()->m_playCount > 0); items.Add(pFileItem); } }
void CPVRRecordings::GetSubDirectories(const CPVRRecordingsPath &recParentPath, CFileItemList *results) { // Only active recordings are fetched to provide sub directories. // Not applicable for deleted view which is supposed to be flattened. std::set<CFileItemPtr> unwatchedFolders; bool bRadio = recParentPath.IsRadio(); for (const auto recording : m_recordings) { CPVRRecordingPtr current = recording.second; if (current->IsDeleted()) continue; if (current->IsRadio() != bRadio) continue; const std::string strCurrent(recParentPath.GetUnescapedSubDirectoryPath(current->m_strDirectory)); if (strCurrent.empty()) continue; CPVRRecordingsPath recChildPath(recParentPath); recChildPath.AppendSegment(strCurrent); std::string strFilePath(recChildPath); CFileItemPtr pFileItem; if (m_database.IsOpen()) current->UpdateMetadata(m_database); if (!results->Contains(strFilePath)) { pFileItem.reset(new CFileItem(strCurrent, true)); pFileItem->SetPath(strFilePath); pFileItem->SetLabel(strCurrent); pFileItem->SetLabelPreformatted(true); pFileItem->m_dateTime = current->RecordingTimeAsLocalTime(); // Assume all folders are watched, we'll change the overlay later pFileItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_WATCHED, false); results->Add(pFileItem); } else { pFileItem = results->Get(strFilePath); if (pFileItem->m_dateTime<current->RecordingTimeAsLocalTime()) pFileItem->m_dateTime = current->RecordingTimeAsLocalTime(); } if (current->GetPlayCount() == 0) unwatchedFolders.insert(pFileItem); } // Change the watched overlay to unwatched for folders containing unwatched entries for (auto item : unwatchedFolders) item->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, false); }
void CPVRRecordings::UpdateFromClient(const CPVRRecordingPtr &tag) { CSingleLock lock(m_critSection); if (tag->IsDeleted()) m_bHasDeleted = true; CPVRRecordingPtr newTag = GetById(tag->m_iClientId, tag->m_strRecordingId); if (newTag) { newTag->Update(*tag); } else { newTag = CPVRRecordingPtr(new CPVRRecording); newTag->Update(*tag); if (newTag->BroadcastUid() != EPG_TAG_INVALID_UID) { const CPVRChannelPtr channel(newTag->Channel()); if (channel) { const EPG::CEpgInfoTagPtr epgTag = EPG::CEpgContainer::GetInstance().GetTagById(channel, newTag->BroadcastUid()); if (epgTag) epgTag->SetRecording(newTag); } } newTag->m_iRecordingId = ++m_iLastId; m_recordings.insert(std::make_pair(CPVRRecordingUid(newTag->m_iClientId, newTag->m_strRecordingId), newTag)); } }
void CPVRRecordings::UpdateFromClient(const CPVRRecordingPtr &tag) { CSingleLock lock(m_critSection); if (tag->IsDeleted()) { if (tag->IsRadio()) m_bDeletedRadioRecordings = true; else m_bDeletedTVRecordings = true; } CPVRRecordingPtr newTag = GetById(tag->m_iClientId, tag->m_strRecordingId); if (newTag) { newTag->Update(*tag); } else { newTag = CPVRRecordingPtr(new CPVRRecording); newTag->Update(*tag); newTag->m_iRecordingId = ++m_iLastId; m_recordings.insert(std::make_pair(CPVRRecordingUid(newTag->m_iClientId, newTag->m_strRecordingId), newTag)); if (newTag->IsRadio()) ++m_iRadioRecordings; else ++m_iTVRecordings; } }
void CPVRRecordings::UpdateFromClient(const CPVRRecordingPtr &tag) { CSingleLock lock(m_critSection); if (tag->IsDeleted()) m_bHasDeleted = true; CPVRRecordingPtr newTag = GetById(tag->m_iClientId, tag->m_strRecordingId); if (newTag) { newTag->Update(*tag); } else { newTag = CPVRRecordingPtr(new CPVRRecording); newTag->Update(*tag); if (newTag->EpgEvent() > 0) { EPG::CEpgInfoTagPtr epgTag = EPG::CEpgContainer::GetInstance().GetTagById(newTag->EpgEvent()); if (epgTag) epgTag->SetRecording(newTag); } newTag->m_iRecordingId = ++m_iLastId; m_recordings.insert(std::make_pair(CPVRRecordingUid(newTag->m_iClientId, newTag->m_strRecordingId), newTag)); } }
CFileItemPtr CPVRRecordings::GetByPath(const std::string &path) { CSingleLock lock(m_critSection); CPVRRecordingsPath recPath(path); if (recPath.IsValid()) { // Check directory name is for deleted recordings bool bDeleted = recPath.IsDeleted(); for (PVR_RECORDINGMAP_CITR it = m_recordings.begin(); it != m_recordings.end(); it++) { CPVRRecordingPtr current = it->second; if (!URIUtils::PathEquals(path, current->m_strFileNameAndPath) || bDeleted != current->IsDeleted()) continue; CFileItemPtr fileItem(new CFileItem(current)); return fileItem; } } CFileItemPtr fileItem(new CFileItem); return fileItem; }
void CPVRRecordings::GetSubDirectories(const std::string &strBase, CFileItemList *results) { // Only active recordings are fetched to provide sub directories. // Not applicable for deleted view which is supposed to be flattened. std::string strUseBase = TrimSlashes(strBase); std::set<CFileItemPtr> unwatchedFolders; for (PVR_RECORDINGMAP_CITR it = m_recordings.begin(); it != m_recordings.end(); it++) { CPVRRecordingPtr current = it->second; if (current->IsDeleted()) continue; const std::string strCurrent = GetDirectoryFromPath(current->m_strDirectory, strUseBase); if (strCurrent.empty()) continue; std::string strFilePath; if(strUseBase.empty()) strFilePath = StringUtils::Format("pvr://" PVR_RECORDING_BASE_PATH "/" PVR_RECORDING_ACTIVE_PATH "/%s/", strCurrent.c_str()); else strFilePath = StringUtils::Format("pvr://" PVR_RECORDING_BASE_PATH "/" PVR_RECORDING_ACTIVE_PATH "/%s/%s/", strUseBase.c_str(), strCurrent.c_str()); CFileItemPtr pFileItem; if (m_database.IsOpen()) current->UpdateMetadata(m_database); if (!results->Contains(strFilePath)) { pFileItem.reset(new CFileItem(strCurrent, true)); pFileItem->SetPath(strFilePath); pFileItem->SetLabel(strCurrent); pFileItem->SetLabelPreformated(true); pFileItem->m_dateTime = current->RecordingTimeAsLocalTime(); // Assume all folders are watched, we'll change the overlay later pFileItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_WATCHED, false); results->Add(pFileItem); } else { pFileItem=results->Get(strFilePath); if (pFileItem->m_dateTime<current->RecordingTimeAsLocalTime()) pFileItem->m_dateTime = current->RecordingTimeAsLocalTime(); } if (current->m_playCount == 0) unwatchedFolders.insert(pFileItem); } // Remove the watched overlay from folders containing unwatched entries for (std::set<CFileItemPtr>::iterator it = unwatchedFolders.begin(); it != unwatchedFolders.end(); ++it) (*it)->SetOverlayImage(CGUIListItem::ICON_OVERLAY_WATCHED, true); }
void CPVRRecordings::UpdateFromClient(const CPVRRecordingPtr &tag) { CSingleLock lock(m_critSection); if (tag->IsDeleted()) { if (tag->IsRadio()) m_bDeletedRadioRecordings = true; else m_bDeletedTVRecordings = true; } CPVRRecordingPtr newTag = GetById(tag->m_iClientId, tag->m_strRecordingId); if (newTag) { newTag->Update(*tag); } else { newTag = CPVRRecordingPtr(new CPVRRecording); newTag->Update(*tag); if (newTag->BroadcastUid() != EPG_TAG_INVALID_UID) { const CPVRChannelPtr channel(newTag->Channel()); if (channel) { const CPVREpgInfoTagPtr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(channel, newTag->BroadcastUid()); if (epgTag) epgTag->SetRecording(newTag); } } newTag->m_iRecordingId = ++m_iLastId; m_recordings.insert(std::make_pair(CPVRRecordingUid(newTag->m_iClientId, newTag->m_strRecordingId), newTag)); if (newTag->IsRadio()) ++m_iRadioRecordings; else ++m_iTVRecordings; } }
bool CPVRClients::OpenStream(const CPVRRecordingPtr &channel) { assert(channel.get()); bool bReturn(false); CloseStream(); /* try to open the recording stream on the client */ PVR_CLIENT client; if (GetConnectedClient(channel->m_iClientId, client) && client->OpenStream(channel)) { CSingleLock lock(m_critSection); m_playingClientId = channel->m_iClientId; m_bIsPlayingRecording = true; m_strPlayingClientName = client->GetFriendlyName(); bReturn = true; } return bReturn; }
bool CPVRGUIInfo::GetListItemAndPlayerBool(const CFileItem *item, const CGUIInfo &info, bool &bValue) const { switch (info.m_info) { case LISTITEM_ISRECORDING: if (item->IsPVRChannel()) { bValue = item->GetPVRChannelInfoTag()->IsRecording(); return true; } else if (item->IsEPG() || item->IsPVRTimer()) { const CPVRTimerInfoTagPtr timer = CPVRItem(item).GetTimerInfoTag(); if (timer) bValue = timer->IsRecording(); return true; } else if (item->IsPVRRecording()) { bValue = item->GetPVRRecordingInfoTag()->IsInProgress(); return true; } break; case LISTITEM_INPROGRESS: if (item->IsPVRChannel() || item->IsEPG()) { const CPVREpgInfoTagPtr epgTag = CPVRItem(item).GetEpgInfoTag(); if (epgTag) bValue = epgTag->IsActive(); return true; } break; case LISTITEM_HASTIMER: if (item->IsPVRChannel() || item->IsEPG()) { const CPVREpgInfoTagPtr epgTag = CPVRItem(item).GetEpgInfoTag(); if (epgTag) bValue = epgTag->HasTimer(); return true; } break; case LISTITEM_HASTIMERSCHEDULE: if (item->IsPVRChannel() || item->IsEPG() || item->IsPVRTimer()) { const CPVRTimerInfoTagPtr timer = CPVRItem(item).GetTimerInfoTag(); if (timer) bValue = timer->GetTimerRuleId() != PVR_TIMER_NO_PARENT; return true; } break; case LISTITEM_TIMERISACTIVE: if (item->IsPVRChannel() || item->IsEPG()) { const CPVRTimerInfoTagPtr timer = CPVRItem(item).GetTimerInfoTag(); if (timer) bValue = timer->IsActive(); break; } break; case LISTITEM_TIMERHASCONFLICT: if (item->IsPVRChannel() || item->IsEPG()) { const CPVRTimerInfoTagPtr timer = CPVRItem(item).GetTimerInfoTag(); if (timer) bValue = timer->HasConflict(); return true; } break; case LISTITEM_TIMERHASERROR: if (item->IsPVRChannel() || item->IsEPG()) { const CPVRTimerInfoTagPtr timer = CPVRItem(item).GetTimerInfoTag(); if (timer) bValue = (timer->IsBroken() && !timer->HasConflict()); return true; } break; case LISTITEM_HASRECORDING: if (item->IsPVRChannel() || item->IsEPG()) { const CPVREpgInfoTagPtr epgTag = CPVRItem(item).GetEpgInfoTag(); if (epgTag) bValue = epgTag->HasRecording(); return true; } break; case LISTITEM_HAS_EPG: if (item->IsPVRChannel() || item->IsEPG() || item->IsPVRTimer()) { const CPVREpgInfoTagPtr epgTag = CPVRItem(item).GetEpgInfoTag(); bValue = (epgTag != nullptr); return true; } break; case LISTITEM_ISENCRYPTED: if (item->IsPVRChannel() || item->IsEPG()) { const CPVRChannelPtr channel = CPVRItem(item).GetChannel(); if (channel) bValue = channel->IsEncrypted(); return true; } break; case MUSICPLAYER_CONTENT: case VIDEOPLAYER_CONTENT: if (item->IsPVRChannel()) { bValue = StringUtils::EqualsNoCase(info.GetData3(), "livetv"); return bValue; // if no match for this provider, other providers shall be asked. } break; case VIDEOPLAYER_HAS_INFO: if (item->IsPVRChannel()) { bValue = !item->GetPVRChannelInfoTag()->IsEmpty(); return true; } break; case VIDEOPLAYER_HAS_EPG: if (item->IsPVRChannel()) { bValue = (item->GetPVRChannelInfoTag()->GetEPGNow() != nullptr); return true; } break; case VIDEOPLAYER_CAN_RESUME_LIVE_TV: if (item->IsPVRRecording()) { const CPVRRecordingPtr recording = item->GetPVRRecordingInfoTag(); const CPVREpgInfoTagPtr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(recording->Channel(), recording->BroadcastUid()); bValue = (epgTag && epgTag->IsActive() && epgTag->Channel()); return true; } break; case PLAYER_IS_CHANNEL_PREVIEW_ACTIVE: if (item->IsPVRChannel()) { if (CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().IsPreviewAndShowInfo()) { bValue = true; } else { bValue = !m_videoInfo.valid; if (bValue && item->GetPVRChannelInfoTag()->IsRadio()) bValue = !m_audioInfo.valid; } return true; } break; } return false; }
bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem *item, const CGUIInfo &info, std::string &strValue) const { const CPVRTimerInfoTagPtr timer = item->GetPVRTimerInfoTag(); if (timer) { switch (info.m_info) { case LISTITEM_DATE: strValue = timer->Summary(); return true; case LISTITEM_STARTDATE: strValue = timer->StartAsLocalTime().GetAsLocalizedDate(true); return true; case LISTITEM_STARTTIME: strValue = timer->StartAsLocalTime().GetAsLocalizedTime("", false); return true; case LISTITEM_ENDDATE: strValue = timer->EndAsLocalTime().GetAsLocalizedDate(true); return true; case LISTITEM_ENDTIME: strValue = timer->EndAsLocalTime().GetAsLocalizedTime("", false); return true; case LISTITEM_TITLE: strValue = timer->Title(); return true; case LISTITEM_COMMENT: strValue = timer->GetStatus(); return true; case LISTITEM_TIMERTYPE: strValue = timer->GetTypeAsString(); return true; case LISTITEM_CHANNEL_NAME: strValue = timer->ChannelName(); return true; case LISTITEM_EPG_EVENT_TITLE: case LISTITEM_EPG_EVENT_ICON: case LISTITEM_GENRE: case LISTITEM_PLOT: case LISTITEM_PLOT_OUTLINE: case LISTITEM_DURATION: case LISTITEM_ORIGINALTITLE: case LISTITEM_YEAR: case LISTITEM_SEASON: case LISTITEM_EPISODE: case LISTITEM_EPISODENAME: case LISTITEM_DIRECTOR: case LISTITEM_CHANNEL_NUMBER: case LISTITEM_PREMIERED: break; // obtain value from channel/epg default: return false; } } const CPVRRecordingPtr recording(item->GetPVRRecordingInfoTag()); if (recording) { // Note: CPVRRecoding is derived from CVideoInfoTag. All base class properties will be handled // by CVideoGUIInfoProvider. Only properties introduced by CPVRRecording need to be handled here. switch (info.m_info) { case LISTITEM_DATE: strValue = recording->RecordingTimeAsLocalTime().GetAsLocalizedDateTime(false, false); return true; case LISTITEM_STARTDATE: strValue = recording->RecordingTimeAsLocalTime().GetAsLocalizedDate(true); return true; case VIDEOPLAYER_STARTTIME: case LISTITEM_STARTTIME: strValue = recording->RecordingTimeAsLocalTime().GetAsLocalizedTime("", false); return true; case LISTITEM_ENDDATE: strValue = recording->EndTimeAsLocalTime().GetAsLocalizedDate(true); return true; case VIDEOPLAYER_ENDTIME: case LISTITEM_ENDTIME: strValue = recording->EndTimeAsLocalTime().GetAsLocalizedTime("", false); return true; case LISTITEM_EXPIRATION_DATE: if (recording->HasExpirationTime()) { strValue = recording->ExpirationTimeAsLocalTime().GetAsLocalizedDate(false); return true; } break; case LISTITEM_EXPIRATION_TIME: if (recording->HasExpirationTime()) { strValue = recording->ExpirationTimeAsLocalTime().GetAsLocalizedTime("", false);; return true; } break; case VIDEOPLAYER_EPISODENAME: case LISTITEM_EPISODENAME: strValue = recording->EpisodeName(); return true; case VIDEOPLAYER_CHANNEL_NAME: case LISTITEM_CHANNEL_NAME: strValue = recording->m_strChannelName; return true; case VIDEOPLAYER_CHANNEL_NUMBER: case LISTITEM_CHANNEL_NUMBER: { const CPVRChannelPtr channel = recording->Channel(); if (channel) { strValue = channel->ChannelNumber().FormattedChannelNumber(); return true; } break; } case VIDEOPLAYER_CHANNEL_GROUP: { CSingleLock lock(m_critSection); strValue = recording->IsRadio() ? m_strPlayingRadioGroup : m_strPlayingTVGroup; return true; } } return false; } CPVREpgInfoTagPtr epgTag; CPVRChannelPtr channel; if (item->IsPVRChannel() || item->IsEPG() || item->IsPVRTimer()) { CPVRItem pvrItem(item); channel = pvrItem.GetChannel(); switch (info.m_info) { case VIDEOPLAYER_NEXT_TITLE: case VIDEOPLAYER_NEXT_GENRE: case VIDEOPLAYER_NEXT_PLOT: case VIDEOPLAYER_NEXT_PLOT_OUTLINE: case VIDEOPLAYER_NEXT_STARTTIME: case VIDEOPLAYER_NEXT_ENDTIME: case VIDEOPLAYER_NEXT_DURATION: case LISTITEM_NEXT_TITLE: case LISTITEM_NEXT_GENRE: case LISTITEM_NEXT_PLOT: case LISTITEM_NEXT_PLOT_OUTLINE: case LISTITEM_NEXT_STARTDATE: case LISTITEM_NEXT_STARTTIME: case LISTITEM_NEXT_ENDDATE: case LISTITEM_NEXT_ENDTIME: case LISTITEM_NEXT_DURATION: // next playing event epgTag = pvrItem.GetNextEpgInfoTag(); break; default: // now playing event epgTag = pvrItem.GetEpgInfoTag(); break; } switch (info.m_info) { // special handling for channels without epg or with radio rds data case PLAYER_TITLE: case VIDEOPLAYER_TITLE: case LISTITEM_TITLE: case VIDEOPLAYER_NEXT_TITLE: case LISTITEM_NEXT_TITLE: case LISTITEM_EPG_EVENT_TITLE: // Note: in difference to LISTITEM_TITLE, LISTITEM_EPG_EVENT_TITLE returns the title // associated with the epg event of a timer, if any, and not the title of the timer. if (epgTag) strValue = epgTag->Title(); if (strValue.empty() && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_HIDENOINFOAVAILABLE)) strValue = g_localizeStrings.Get(19055); // no information available return true; } } if (epgTag) { switch (info.m_info) { case VIDEOPLAYER_GENRE: case LISTITEM_GENRE: case VIDEOPLAYER_NEXT_GENRE: case LISTITEM_NEXT_GENRE: strValue = epgTag->GetGenresLabel(); return true; case VIDEOPLAYER_PLOT: case LISTITEM_PLOT: case VIDEOPLAYER_NEXT_PLOT: case LISTITEM_NEXT_PLOT: strValue = epgTag->Plot(); return true; case VIDEOPLAYER_PLOT_OUTLINE: case LISTITEM_PLOT_OUTLINE: case VIDEOPLAYER_NEXT_PLOT_OUTLINE: case LISTITEM_NEXT_PLOT_OUTLINE: strValue = epgTag->PlotOutline(); return true; case LISTITEM_DATE: strValue = epgTag->StartAsLocalTime().GetAsLocalizedDateTime(false, false); return true; case LISTITEM_STARTDATE: case LISTITEM_NEXT_STARTDATE: strValue = epgTag->StartAsLocalTime().GetAsLocalizedDate(true); return true; case VIDEOPLAYER_STARTTIME: case VIDEOPLAYER_NEXT_STARTTIME: case LISTITEM_STARTTIME: case LISTITEM_NEXT_STARTTIME: strValue = epgTag->StartAsLocalTime().GetAsLocalizedTime("", false); return true; case LISTITEM_ENDDATE: case LISTITEM_NEXT_ENDDATE: strValue = epgTag->EndAsLocalTime().GetAsLocalizedDate(true); return true; case VIDEOPLAYER_ENDTIME: case VIDEOPLAYER_NEXT_ENDTIME: case LISTITEM_ENDTIME: case LISTITEM_NEXT_ENDTIME: strValue = epgTag->EndAsLocalTime().GetAsLocalizedTime("", false); return true; // note: for some reason, there is no VIDEOPLAYER_DURATION case LISTITEM_DURATION: case VIDEOPLAYER_NEXT_DURATION: case LISTITEM_NEXT_DURATION: if (epgTag->GetDuration() > 0) { strValue = StringUtils::SecondsToTimeString(epgTag->GetDuration(), static_cast<TIME_FORMAT>(info.GetData4())); return true; } return false; case VIDEOPLAYER_IMDBNUMBER: case LISTITEM_IMDBNUMBER: strValue = epgTag->IMDBNumber(); return true; case VIDEOPLAYER_ORIGINALTITLE: case LISTITEM_ORIGINALTITLE: strValue = epgTag->OriginalTitle(); return true; case VIDEOPLAYER_YEAR: case LISTITEM_YEAR: if (epgTag->Year() > 0) { strValue = StringUtils::Format("%i", epgTag->Year()); return true; } return false; case VIDEOPLAYER_SEASON: case LISTITEM_SEASON: if (epgTag->SeriesNumber() > 0) { strValue = StringUtils::Format("%i", epgTag->SeriesNumber()); return true; } return false; case VIDEOPLAYER_EPISODE: case LISTITEM_EPISODE: if (epgTag->EpisodeNumber() > 0) { if (epgTag->SeriesNumber() == 0) // prefix episode with 'S' strValue = StringUtils::Format("S%i", epgTag->EpisodeNumber()); else strValue = StringUtils::Format("%i", epgTag->EpisodeNumber()); return true; } return false; case VIDEOPLAYER_EPISODENAME: case LISTITEM_EPISODENAME: strValue = epgTag->EpisodeName(); return true; case VIDEOPLAYER_CAST: case LISTITEM_CAST: strValue = epgTag->GetCastLabel(); return true; case VIDEOPLAYER_DIRECTOR: case LISTITEM_DIRECTOR: strValue = epgTag->GetDirectorsLabel(); return true; case VIDEOPLAYER_WRITER: case LISTITEM_WRITER: strValue = epgTag->GetWritersLabel(); return true; case LISTITEM_EPG_EVENT_ICON: strValue = epgTag->Icon(); return true; case VIDEOPLAYER_PARENTAL_RATING: case LISTITEM_PARENTALRATING: if (epgTag->ParentalRating() > 0) { strValue = StringUtils::Format("%i", epgTag->ParentalRating()); return true; } return false; case LISTITEM_PREMIERED: if (epgTag->FirstAiredAsLocalTime().IsValid()) { strValue = epgTag->FirstAiredAsLocalTime().GetAsLocalizedDate(true); return true; } return false; } } if (channel) { switch (info.m_info) { case MUSICPLAYER_CHANNEL_NAME: { const std::shared_ptr<CPVRRadioRDSInfoTag> rdsTag = channel->GetRadioRDSInfoTag(); if (rdsTag) { strValue = rdsTag->GetProgStation(); if (!strValue.empty()) return true; } // fall-thru is intended } case VIDEOPLAYER_CHANNEL_NAME: case LISTITEM_CHANNEL_NAME: strValue = channel->ChannelName(); return true; case MUSICPLAYER_CHANNEL_NUMBER: case VIDEOPLAYER_CHANNEL_NUMBER: case LISTITEM_CHANNEL_NUMBER: strValue = channel->ChannelNumber().FormattedChannelNumber(); return true; case MUSICPLAYER_CHANNEL_GROUP: case VIDEOPLAYER_CHANNEL_GROUP: { CSingleLock lock(m_critSection); strValue = channel->IsRadio() ? m_strPlayingRadioGroup : m_strPlayingTVGroup; return true; } } } return false; }
bool CPVRRecordings::ChangeRecordingsPlayCount(const CFileItemPtr &item, int count) { bool bResult = false; if (m_database.IsOpen()) { bResult = true; CLog::Log(LOGDEBUG, "CPVRRecordings - %s - item path %s", __FUNCTION__, item->GetPath().c_str()); CFileItemList items; if (item->m_bIsFolder) { XFILE::CDirectory::GetDirectory(item->GetPath(), 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() != "..") { ChangeRecordingsPlayCount(pItem, count); } continue; } if (!pItem->HasPVRRecordingInfoTag()) continue; const CPVRRecordingPtr recording = pItem->GetPVRRecordingInfoTag(); if (recording) { if (count == INCREMENT_PLAY_COUNT) recording->IncrementPlayCount(); else recording->SetPlayCount(count); // Clear resume bookmark if (recording->GetPlayCount() > 0) { m_database.ClearBookMarksOfFile(pItem->GetPath(), CBookmark::RESUME); recording->SetResumePoint(CBookmark()); } if (count == INCREMENT_PLAY_COUNT) m_database.IncrementPlayCount(*pItem); else m_database.SetPlayCount(*pItem, count); } } CServiceBroker::GetPVRManager().PublishEvent(RecordingsInvalidated); } return bResult; }
bool CPVRRecordings::GetDirectory(const std::string& strPath, CFileItemList &items) { CSingleLock lock(m_critSection); bool bGrouped = false; const CURL url(strPath); if (url.HasOption("view")) { const std::string view(url.GetOption("view")); if (view == "grouped") bGrouped = true; else if (view == "flat") bGrouped = false; else { CLog::Log(LOGERROR, "CPVRRecordings - %s - unsupported value '%s' for url parameter 'view'", __FUNCTION__, view.c_str()); return false; } } else { bGrouped = CSettings::GetInstance().GetBool(CSettings::SETTING_PVRRECORD_GROUPRECORDINGS); } CPVRRecordingsPath recPath(url.GetWithoutOptions()); if (recPath.IsValid()) { // Get the directory structure if in non-flatten mode // Deleted view is always flatten. So only for an active view std::string strDirectory(recPath.GetUnescapedDirectoryPath()); if (!recPath.IsDeleted() && bGrouped) GetSubDirectories(recPath, &items); // get all files of the currrent directory or recursively all files starting at the current directory if in flatten mode for (const auto recording : m_recordings) { CPVRRecordingPtr current = recording.second; // Omit recordings not matching criteria if (!IsDirectoryMember(strDirectory, current->m_strDirectory, bGrouped) || current->IsDeleted() != recPath.IsDeleted() || current->IsRadio() != recPath.IsRadio()) continue; if (m_database.IsOpen()) current->UpdateMetadata(m_database); CFileItemPtr pFileItem(new CFileItem(current)); pFileItem->SetLabel2(current->RecordingTimeAsLocalTime().GetAsLocalizedDateTime(true, false)); pFileItem->m_dateTime = current->RecordingTimeAsLocalTime(); pFileItem->SetPath(current->m_strFileNameAndPath); // Set art if (!current->m_strIconPath.empty()) { pFileItem->SetIconImage(current->m_strIconPath); pFileItem->SetArt("icon", current->m_strIconPath); } if (!current->m_strThumbnailPath.empty()) pFileItem->SetArt("thumb", current->m_strThumbnailPath); if (!current->m_strFanartPath.empty()) pFileItem->SetArt("fanart", current->m_strFanartPath); // Use the channel icon as a fallback when a thumbnail is not available pFileItem->SetArtFallback("thumb", "icon"); pFileItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, pFileItem->GetPVRRecordingInfoTag()->m_playCount > 0); items.Add(pFileItem); } } return recPath.IsValid(); }
bool CPVRRecordings::GetDirectory(const std::string& strPath, CFileItemList &items) { CSingleLock lock(m_critSection); CURL url(strPath); std::string strDirectoryPath = url.GetFileName(); URIUtils::RemoveSlashAtEnd(strDirectoryPath); if (StringUtils::StartsWith(strDirectoryPath, PVR_RECORDING_BASE_PATH)) { strDirectoryPath.erase(0, sizeof(PVR_RECORDING_BASE_PATH) - 1); // Check directory name is for deleted recordings bool bDeleted = StringUtils::StartsWith(strDirectoryPath, "/" PVR_RECORDING_DELETED_PATH); strDirectoryPath.erase(0, bDeleted ? sizeof(PVR_RECORDING_DELETED_PATH) : sizeof(PVR_RECORDING_ACTIVE_PATH)); // Get the directory structure if in non-flatten mode // Deleted view is always flatten. So only for an active view if (!bDeleted && m_bGroupItems) GetSubDirectories(strDirectoryPath, &items); // get all files of the currrent directory or recursively all files starting at the current directory if in flatten mode for (PVR_RECORDINGMAP_CITR it = m_recordings.begin(); it != m_recordings.end(); it++) { CPVRRecordingPtr current = it->second; // skip items that are not members of the target directory if (!IsDirectoryMember(strDirectoryPath, current->m_strDirectory) || current->IsDeleted() != bDeleted) continue; if (m_database.IsOpen()) current->UpdateMetadata(m_database); CFileItemPtr pFileItem(new CFileItem(current)); pFileItem->SetLabel2(current->RecordingTimeAsLocalTime().GetAsLocalizedDateTime(true, false)); pFileItem->m_dateTime = current->RecordingTimeAsLocalTime(); pFileItem->SetPath(current->m_strFileNameAndPath); // Set art if (!current->m_strIconPath.empty()) { pFileItem->SetIconImage(current->m_strIconPath); pFileItem->SetArt("icon", current->m_strIconPath); } if (!current->m_strThumbnailPath.empty()) pFileItem->SetArt("thumb", current->m_strThumbnailPath); if (!current->m_strFanartPath.empty()) pFileItem->SetArt("fanart", current->m_strFanartPath); // Use the channel icon as a fallback when a thumbnail is not available pFileItem->SetArtFallback("thumb", "icon"); pFileItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, pFileItem->GetPVRRecordingInfoTag()->m_playCount > 0); items.Add(pFileItem); } return true; } return false; }