static int GetTotalSeconds(const CDateTimeSpan& ts) { int hours = ts.GetHours() + ts.GetDays() * 24; int minutes = ts.GetMinutes() + hours * 60; return ts.GetSeconds() + minutes * 60; }
bool CCMythDirectory::GetGuideForChannel(const CStdString& base, CFileItemList &items, int channelNumber) { cmyth_database_t database = m_session->GetDatabase(); if (!database) { CLog::Log(LOGERROR, "%s - Could not get database", __FUNCTION__); return false; } time_t now; time(&now); // this sets how many seconds of EPG from now we should grab time_t end = now + (1 * 24 * 60 * 60); cmyth_program_t *program = NULL; int count = m_dll->mysql_get_guide(database, &program, now, end); CLog::Log(LOGDEBUG, "%s - %i entries of guide data", __FUNCTION__, count); if (count <= 0) return false; for (int i = 0; i < count; i++) { if (program[i].channum == channelNumber) { CStdString path; path.Format("%s%s", base.c_str(), program[i].title); CDateTime starttime(program[i].starttime); CDateTime endtime(program[i].endtime); CStdString title; title.Format("%s - %s", starttime.GetAsLocalizedTime("HH:mm", false), program[i].title); CFileItemPtr item(new CFileItem(title, false)); item->SetLabel(title); item->m_dateTime = starttime; CVideoInfoTag* tag = item->GetVideoInfoTag(); tag->m_strAlbum = GetValue(program[i].callsign); tag->m_strShowTitle = GetValue(program[i].title); tag->m_strPlotOutline = GetValue(program[i].subtitle); tag->m_strPlot = GetValue(program[i].description); tag->m_strGenre = GetValue(program[i].category); if(tag->m_strPlot.Left(tag->m_strPlotOutline.length()) != tag->m_strPlotOutline && !tag->m_strPlotOutline.IsEmpty()) tag->m_strPlot = tag->m_strPlotOutline + '\n' + tag->m_strPlot; tag->m_strOriginalTitle = tag->m_strShowTitle; tag->m_strTitle = tag->m_strAlbum; if(tag->m_strShowTitle.length() > 0) tag->m_strTitle += " : " + tag->m_strShowTitle; CDateTimeSpan runtime = endtime - starttime; StringUtils::SecondsToTimeString( runtime.GetSeconds() + runtime.GetMinutes() * 60 + runtime.GetHours() * 3600, tag->m_strRuntime); tag->m_iSeason = 0; /* set this so xbmc knows it's a tv show */ tag->m_iEpisode = 0; tag->m_strStatus = program[i].rec_status; items.Add(item); } } // Sort by date only. items.AddSortMethod(SORT_METHOD_DATE, 552 /* Date */, LABEL_MASKS("%L", "%J", "%L", "")); m_dll->ref_release(program); return true; }
bool CMythDirectory::GetGuideForChannel(const CStdString& base, CFileItemList &items, int channelNumber) { cmyth_database_t database = m_session->GetDatabase(); if (!database) { CLog::Log(LOGERROR, "%s - Could not get database", __FUNCTION__); return false; } time_t now; time(&now); time_t end = now + (24 * 60 * 60); // How many seconds of EPG from now we should grab, 24 hours in seconds cmyth_program_t *program = NULL; // TODO: See if there is a way to just get the entries for the chosen channel rather than ALL int count = m_dll->mysql_get_guide(database, &program, now, end); CLog::Log(LOGDEBUG, "%s - %i entries in guide data", __FUNCTION__, count); if (count <= 0) return false; for (int i = 0; i < count; i++) { if (program[i].channum == channelNumber) { CFileItemPtr item(new CFileItem("", false)); // No path for guide entries /* * Set the FileItem meta data. */ CStdString title = program[i].title; // e.g. Mythbusters CStdString subtitle = program[i].subtitle; // e.g. The Pirate Special CDateTime localstart; if (program[i].starttime) localstart = CTimeUtils::GetLocalTime(program[i].starttime); item->m_strTitle.Format("%s - %s", localstart.GetAsLocalizedTime("HH:mm", false), title); // e.g. 20:30 - Mythbusters if (!subtitle.IsEmpty()) item->m_strTitle += " - \"" + subtitle + "\""; // e.g. 20:30 - Mythbusters - "The Pirate Special" item->m_dateTime = localstart; /* * Set the VideoInfoTag meta data so it matches the FileItem meta data where possible. */ CVideoInfoTag* tag = item->GetVideoInfoTag(); tag->m_strTitle = title; if (!subtitle.IsEmpty()) tag->m_strTitle += " - \"" + subtitle + "\""; // e.g. Mythbusters - "The Pirate Special" tag->m_strShowTitle = title; tag->m_strOriginalTitle = title; tag->m_strPlotOutline = subtitle; tag->m_strPlot = program[i].description; // TODO: Strip out the subtitle from the description if it is present at the start? // TODO: Do we need to add the subtitle to the start of the plot if not already as it used to? Seems strange, should be handled by skin? tag->m_genre = StringUtils::Split(program[i].category, g_advancedSettings.m_videoItemSeparator); // e.g. Sports tag->m_strAlbum = program[i].callsign; // e.g. TV3 CDateTime start(program[i].starttime); CDateTime end(program[i].endtime); CDateTimeSpan runtime = end - start; tag->m_strRuntime = StringUtils::SecondsToTimeString(runtime.GetSeconds() + runtime.GetMinutes() * 60 + runtime.GetHours() * 3600); tag->m_iSeason = 0; // So XBMC treats the content as an episode and displays tag information. tag->m_iEpisode = 0; items.Add(item); } } /* * Items are sorted as added to the list (in ascending date order). Specifying sorting by date can * result in the guide being shown in the wrong order for skins that sort by date in descending * order by default with no option to change to ascending, e.g. Confluence. */ items.AddSortMethod(SORT_METHOD_NONE, 552 /* Date */, LABEL_MASKS("%K", "%J")); // Still leave the date label m_dll->ref_release(program); return true; }
void CGUIEPGGridContainerModel::Refresh(const std::unique_ptr<CFileItemList> &items, const CDateTime &gridStart, const CDateTime &gridEnd, int iRulerUnit, int iBlocksPerPage, float fBlockSize) { Reset(); //////////////////////////////////////////////////////////////////////// // Create programme & channel items m_programmeItems.reserve(items->Size()); CFileItemPtr fileItem; int iLastChannelID = -1; ItemsPtr itemsPointer; itemsPointer.start = 0; CPVRChannelPtr channel; int j = 0; for (int i = 0; i < items->Size(); ++i) { fileItem = items->Get(i); if (!fileItem->HasEPGInfoTag() || !fileItem->GetEPGInfoTag()->HasPVRChannel()) continue; m_programmeItems.emplace_back(fileItem); channel = fileItem->GetEPGInfoTag()->ChannelTag(); int iCurrentChannelID = channel->ChannelID(); if (iCurrentChannelID != iLastChannelID) { if (j > 0) { itemsPointer.stop = j - 1; m_epgItemsPtr.emplace_back(itemsPointer); itemsPointer.start = j; } iLastChannelID = iCurrentChannelID; m_channelItems.emplace_back(CFileItemPtr(new CFileItem(channel))); } ++j; } if (!m_programmeItems.empty()) { itemsPointer.stop = m_programmeItems.size() - 1; m_epgItemsPtr.emplace_back(itemsPointer); } /* check for invalid start and end time */ if (gridStart >= gridEnd) { // default to start "now minus 30 minutes" and end "start plus one page". m_gridStart = CDateTime::GetCurrentDateTime().GetAsUTCDateTime() - CDateTimeSpan(0, 0, 30, 0); m_gridEnd = m_gridStart + CDateTimeSpan(0, 0, iBlocksPerPage * MINSPERBLOCK, 0); } else { m_gridStart = CDateTime(gridStart.GetYear(), gridStart.GetMonth(), gridStart.GetDay(), gridStart.GetHour(), gridStart.GetMinute() >= 30 ? 30 : 0, 0); m_gridEnd = CDateTime(gridEnd.GetYear(), gridEnd.GetMonth(), gridEnd.GetDay(), gridEnd.GetHour(), gridEnd.GetMinute() >= 30 ? 30 : 0, 0); } //////////////////////////////////////////////////////////////////////// // Create ruler items CDateTime ruler; ruler.SetFromUTCDateTime(m_gridStart); CDateTime rulerEnd; rulerEnd.SetFromUTCDateTime(m_gridEnd); CFileItemPtr rulerItem(new CFileItem(ruler.GetAsLocalizedDate(true))); rulerItem->SetProperty("DateLabel", true); m_rulerItems.emplace_back(rulerItem); const CDateTimeSpan unit(0, 0, iRulerUnit * MINSPERBLOCK, 0); for (; ruler < rulerEnd; ruler += unit) { rulerItem.reset(new CFileItem(ruler.GetAsLocalizedTime("", false))); rulerItem->SetLabel2(ruler.GetAsLocalizedDate(true)); m_rulerItems.emplace_back(rulerItem); } FreeItemsMemory(); //////////////////////////////////////////////////////////////////////// // Create epg grid const CDateTimeSpan blockDuration(0, 0, MINSPERBLOCK, 0); const CDateTimeSpan gridDuration(m_gridEnd - m_gridStart); m_blocks = (gridDuration.GetDays() * 24 * 60 + gridDuration.GetHours() * 60 + gridDuration.GetMinutes()) / MINSPERBLOCK; if (m_blocks >= MAXBLOCKS) m_blocks = MAXBLOCKS; m_gridIndex.reserve(m_channelItems.size()); const std::vector<GridItemsPtr> blocks(m_blocks); for (size_t channel = 0; channel < m_channelItems.size(); ++channel) { m_gridIndex.emplace_back(blocks); CDateTime gridCursor(m_gridStart); //reset cursor for new channel unsigned long progIdx = m_epgItemsPtr[channel].start; unsigned long lastIdx = m_epgItemsPtr[channel].stop; int iEpgId = m_programmeItems[progIdx]->GetEPGInfoTag()->EpgID(); int itemSize = 1; // size of the programme in blocks int savedBlock = 0; CFileItemPtr item; CEpgInfoTagPtr tag; for (int block = 0; block < m_blocks; ++block) { while (progIdx <= lastIdx) { item = m_programmeItems[progIdx]; tag = item->GetEPGInfoTag(); if (tag->EpgID() != iEpgId || gridCursor < tag->StartAsUTC() || m_gridEnd <= tag->StartAsUTC()) break; if (gridCursor < tag->EndAsUTC()) { m_gridIndex[channel][block].item = item; m_gridIndex[channel][block].progIndex = progIdx; break; } progIdx++; } gridCursor += blockDuration; if (block == 0) continue; const CFileItemPtr prevItem(m_gridIndex[channel][block - 1].item); const CFileItemPtr currItem(m_gridIndex[channel][block].item); if (block == m_blocks - 1 || prevItem != currItem) { // special handling for last block. int blockDelta = -1; int sizeDelta = 0; if (block == m_blocks - 1 && prevItem == currItem) { itemSize++; blockDelta = 0; sizeDelta = 1; } if (prevItem) { m_gridIndex[channel][savedBlock].item->SetProperty("GenreType", prevItem->GetEPGInfoTag()->GenreType()); } else { CEpgInfoTagPtr gapTag(CEpgInfoTag::CreateDefaultTag()); gapTag->SetPVRChannel(m_channelItems[channel]->GetPVRChannelInfoTag()); CFileItemPtr gapItem(new CFileItem(gapTag)); for (int i = block + blockDelta; i >= block - itemSize + sizeDelta; --i) { m_gridIndex[channel][i].item = gapItem; } } float fItemWidth = itemSize * fBlockSize; m_gridIndex[channel][savedBlock].originWidth = fItemWidth; m_gridIndex[channel][savedBlock].width = fItemWidth; itemSize = 1; savedBlock = block; // special handling for last block. if (block == m_blocks - 1 && prevItem != currItem) { if (currItem) { m_gridIndex[channel][savedBlock].item->SetProperty("GenreType", currItem->GetEPGInfoTag()->GenreType()); } else { CEpgInfoTagPtr gapTag(CEpgInfoTag::CreateDefaultTag()); gapTag->SetPVRChannel(m_channelItems[channel]->GetPVRChannelInfoTag()); CFileItemPtr gapItem(new CFileItem(gapTag)); m_gridIndex[channel][block].item = gapItem; } m_gridIndex[channel][savedBlock].originWidth = fBlockSize; // size always 1 block here m_gridIndex[channel][savedBlock].width = fBlockSize; } } else { itemSize++; } } } }