35#include "libmythbase/mythversion.h"
69 qRegisterMetaType< QFileInfo >();
70 qRegisterMetaType<V2ProgramGuide*>(
"V2ProgramGuide");
71 qRegisterMetaType<V2ProgramList*>(
"V2ProgramList");
72 qRegisterMetaType<V2Program*>(
"V2Program");
73 qRegisterMetaType<V2ChannelGroupList*>(
"V2ChannelGroupList");
74 qRegisterMetaType<V2ChannelGroup*>(
"V2ChannelGroup");
75 qRegisterMetaType<V2ChannelInfo*>(
"V2ChannelInfo");
76 qRegisterMetaType<V2RecordingInfo*>(
"V2RecordingInfo");
77 qRegisterMetaType<V2ArtworkInfoList*>(
"V2ArtworkInfoList");
78 qRegisterMetaType<V2ArtworkInfo*>(
"V2ArtworkInfo");
79 qRegisterMetaType<V2CastMemberList*>(
"V2CastMemberList");
80 qRegisterMetaType<V2CastMember*>(
"V2CastMember");
88 const QDateTime &rawEndTime,
95 if (!rawStartTime.isValid())
96 throw QString(
"StartTime is invalid" );
98 if (!rawEndTime.isValid())
99 throw QString(
"EndTime is invalid" );
101 QDateTime dtStartTime = rawStartTime.toUTC();
102 QDateTime dtEndTime = rawEndTime.toUTC();
104 if (dtEndTime < dtStartTime)
105 throw QString(
"EndTime is before StartTime");
107 nStartIndex = std::max(nStartIndex, 0);
116 uint nTotalAvailable = 0;
132 QString sWhere =
"program.chanid = :CHANID "
133 "AND program.endtime >= :STARTDATE "
134 "AND program.starttime < :ENDDATE "
135 "AND program.starttime >= :STARTDATELIMIT "
136 "AND program.manualid = 0";
139 QString sGroupBy =
"program.starttime, channel.channum,"
140 "channel.callsign, program.title";
143 QString sOrderBy =
"program.starttime";
145 bindings[
":STARTDATE" ] = dtStartTime;
146 bindings[
":STARTDATELIMIT"] = dtStartTime.addDays(-1);
147 bindings[
":ENDDATE" ] = dtEndTime;
165 ChannelInfoList::iterator chan_it;
166 for (chan_it = chanList.begin(); chan_it != chanList.end(); ++chan_it)
174 bindings[
":CHANID"] = (*chan_it).m_chanId;
180 for( progIt = progList.
begin(); progIt != progList.
end(); ++progIt)
189 pGuide->setStartTime ( dtStartTime );
190 pGuide->setEndTime ( dtEndTime );
191 pGuide->setDetails ( bDetails );
193 pGuide->setStartIndex ( nStartIndex );
194 pGuide->setCount ( chanList.size() );
195 pGuide->setTotalAvailable( nTotalAvailable );
198 pGuide->setVersion ( MYTH_BINARY_VERSION );
199 pGuide->setProtoVer ( MYTH_PROTO_VERSION );
210 const QDateTime& rawStartTime,
211 const QDateTime& rawEndTime,
213 const QString& sTitleFilter,
214 const QString& sCategoryFilter,
215 const QString& sPersonFilter,
216 const QString& sKeywordFilter,
219 const QString &sSort,
222 const QString& sCatType,
223 const QString& sGroupBy)
225 if (!rawStartTime.isNull() && !rawStartTime.isValid())
226 throw QString(
"StartTime is invalid" );
228 if (!rawEndTime.isNull() && !rawEndTime.isValid())
229 throw QString(
"EndTime is invalid" );
231 QDateTime dtStartTime = rawStartTime;
232 const QDateTime& dtEndTime = rawEndTime;
234 if (!rawEndTime.isNull() && dtEndTime < dtStartTime)
235 throw QString(
"EndTime is before StartTime");
238 if (!sGroupBy.isEmpty())
241 auto meta = QMetaEnum::fromType<ProgGroupBy::Type>();
245 throw QString(
"GroupBy is invalid" );
261 if (!sPersonFilter.isEmpty())
263 sSQL =
", people, credits "
264 "WHERE people.name LIKE :PersonFilter "
265 "AND credits.person = people.person "
266 "AND program.chanid = credits.chanid "
267 "AND program.starttime = credits.starttime AND ";
268 bindings[
":PersonFilter"] = QString(
"%%1%").arg(sPersonFilter);
277 sSQL =
"LEFT JOIN oldprogram ON oldprogram.oldtitle = program.title "
279 +
"oldprogram.oldtitle IS NULL AND ";
282 sSQL +=
"deleted IS NULL AND ";
285 sSQL +=
"visible > 0 AND ";
287 sSQL +=
"program.manualid = 0 ";
289 nChanId = std::max(nChanId, 0);
293 sSQL +=
"AND program.chanid = :ChanId ";
294 bindings[
":ChanId"] = nChanId;
297 if (dtStartTime.isNull())
298 dtStartTime = QDateTime::currentDateTimeUtc();
300 sSQL +=
" AND program.endtime >= :StartDate ";
301 bindings[
":StartDate"] = dtStartTime;
303 if (!dtEndTime.isNull())
305 sSQL +=
"AND program.starttime <= :EndDate ";
306 bindings[
":EndDate"] = dtEndTime;
309 if (!sTitleFilter.isEmpty())
311 sSQL +=
"AND program.title LIKE :Title ";
312 bindings[
":Title"] = QString(
"%%1%").arg(sTitleFilter);
315 if (!sCategoryFilter.isEmpty())
317 sSQL +=
"AND program.category LIKE :Category ";
318 bindings[
":Category"] = sCategoryFilter;
321 if (!sCatType.isEmpty())
323 sSQL +=
"AND program.category_type LIKE :CatType ";
324 bindings[
":CatType"] = sCatType;
327 if (!sKeywordFilter.isEmpty())
329 sSQL +=
"AND (program.title LIKE :Keyword1 "
330 "OR program.subtitle LIKE :Keyword2 "
331 "OR program.description LIKE :Keyword3) ";
333 QString filter = QString(
"%%1%").arg(sKeywordFilter);
334 bindings[
":Keyword1"] = filter;
335 bindings[
":Keyword2"] = filter;
336 bindings[
":Keyword3"] = filter;
339 if (sSort ==
"starttime")
340 sSQL +=
"ORDER BY program.starttime ";
341 else if (sSort ==
"title")
342 sSQL +=
"ORDER BY program.title ";
343 else if (sSort ==
"channel")
344 sSQL +=
"ORDER BY channel.channum ";
345 else if (sSort ==
"duration")
346 sSQL +=
"ORDER BY (program.endtime - program.starttime) ";
348 sSQL +=
"ORDER BY program.starttime, channel.channum + 0 ";
367 uint nTotalAvailable = 0;
369 (
uint)nStartIndex, (
uint)nCount, nTotalAvailable,
378 nCount = (int)progList.
size();
379 int nEndIndex = (int)progList.
size();
381 for(
int n = 0; n < nEndIndex; n++)
388 bool duplicate =
false;
390 auto *prior = progList[
back];
391 if (prior !=
nullptr) {
392 if (pInfo -> GetTitle() == prior -> GetTitle()) {
402 V2Program *pProgram = pPrograms->AddNewProgram();
409 pPrograms->setStartIndex ( nStartIndex );
410 pPrograms->setCount ( nCount );
411 pPrograms->setTotalAvailable( nTotalAvailable );
413 pPrograms->setVersion ( MYTH_BINARY_VERSION );
414 pPrograms->setProtoVer ( MYTH_PROTO_VERSION );
424 const QDateTime &rawStartTime )
428 throw QString(
"Channel ID is invalid" );
429 if (!rawStartTime.isValid())
430 throw QString(
"StartTime is invalid" );
432 QDateTime dtStartTime = rawStartTime.toUTC();
457 const QString &FileName )
463 if (FileName.isEmpty())
466 sFileName = FileName;
468 if (sFileName.isEmpty())
470 LOG(VB_UPNP, LOG_ERR,
471 QString(
"GetImageFile - ChanId %1 doesn't exist or isn't visible")
481 QString sFullFileName = storage.
FindFile( sFileName );
483 if (sFullFileName.isEmpty())
485 LOG(VB_UPNP, LOG_ERR,
486 QString(
"GetImageFile - Unable to find %1.").arg(sFileName));
495 if ((nWidth == 0) && (nHeight == 0))
499 return QFileInfo( sFullFileName );
502 LOG(VB_UPNP, LOG_ERR,
503 QString(
"GetImageFile - File Does not exist %1.").arg(sFullFileName));
509 QString sNewFileName = QString(
"%1.%2x%3.png" )
510 .arg( sFullFileName )
519 return QFileInfo( sNewFileName );
525 QString sChannelsDirectory = QFileInfo( sNewFileName ).absolutePath();
527 if (!QFileInfo( sChannelsDirectory ).isWritable())
529 LOG(VB_UPNP, LOG_ERR, QString(
"GetImageFile - no write access to: %1")
530 .arg( sChannelsDirectory ));
534 auto *pImage =
new QImage( sFullFileName );
538 LOG(VB_UPNP, LOG_ERR, QString(
"GetImageFile - can't create image: %1")
539 .arg( sFullFileName ));
543 float fAspect = (float)(pImage->width()) / pImage->height();
546 LOG(VB_UPNP, LOG_ERR, QString(
"GetImageFile - zero aspect"));
552 nWidth = (int)std::rint(nHeight * fAspect);
555 nHeight = (int)std::rint(nWidth / fAspect);
557 QImage img = pImage->scaled( nWidth, nHeight, Qt::IgnoreAspectRatio,
558 Qt::SmoothTransformation);
562 LOG(VB_UPNP, LOG_ERR, QString(
"SaveImageFile - unable to scale. "
563 "See if %1 is really an image.").arg( sFullFileName ));
568 if (!img.save( sNewFileName,
"PNG" ))
570 LOG(VB_UPNP, LOG_ERR, QString(
"SaveImageFile - failed, %1")
571 .arg( sNewFileName ));
578 return QFileInfo( sNewFileName );
590 ChannelGroupList::iterator it;
591 for (it = list.begin(); it < list.end(); ++it)
609 query.
prepare(
"SELECT DISTINCT category FROM program WHERE category != '' "
610 "ORDER BY category");
617 catList << query.
value(0).toString();
629 QStringList keywordList;
640 query.
prepare(
"SELECT DISTINCT phrase FROM keyword "
641 "WHERE searchtype = :TYPE "
643 query.
bindValue(
":TYPE",
static_cast<int>(iType));
650 keywordList << query.
value(0).toString();
663 bool bResult =
false;
666 throw QString(
"Channel ID is invalid" );
680 bool bResult =
false;
683 throw QString(
"Channel ID is invalid" );
std::vector< ChannelGroupItem > ChannelGroupList
std::vector< ChannelInfo > ChannelInfoList
typename List::iterator iterator
Used to expire recordings to make space for new recordings.
static bool RemoveChannelGroup(const QString &groupName)
static bool AddChannel(uint chanid, int changrpid)
static ChannelGroupList GetChannelGroups(bool includeEmpty=true)
static bool DeleteChannel(uint chanid, int changrpid)
static int AddChannelGroup(const QString &groupName)
static bool UpdateChannelGroup(const QString &oldName, const QString &newName)
static QString GetIcon(uint chanid)
@ kChanGroupByCallsignAndChannum
static ChannelInfoList LoadChannels(uint startIndex, uint count, uint &totalAvailable, bool ignoreHidden=true, OrderBy orderBy=kChanOrderByChanNum, GroupBy groupBy=kChanGroupByChanid, uint sourceID=0, uint channelGroupID=0, bool liveTVOnly=false, const QString &callsign="", const QString &channum="", bool ignoreUntunable=true)
Load channels from database into a list of ChannelInfo objects.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
QVariant value(int i) const
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
MythScheduler * GetScheduler(void)
Holds information on recordings and videos.
bool GetAllPending(RecList &retList, int recRuleId=0) const
QString FindFile(const QString &filename)
V2Program * AddNewProgram()
static V2ChannelGroupList * GetChannelGroupList(bool IncludeEmpty)
static QFileInfo GetChannelIcon(int ChanId, int Width, int Height, const QString &FileName)
static bool UpdateChannelGroup(const QString &OldName, const QString &NewName)
static V2ProgramGuide * GetProgramGuide(const QDateTime &StartTime, const QDateTime &EndTime, bool Details, int ChannelGroupId, int StartIndex, int Count, bool WithInvisible)
static bool RemoveChannelGroup(const QString &Name)
static int AddChannelGroup(const QString &Name)
static V2ProgramList * GetProgramList(int StartIndex, int Count, const QDateTime &StartTime, const QDateTime &EndTime, int ChanId, const QString &TitleFilter, const QString &CategoryFilter, const QString &PersonFilter, const QString &KeywordFilter, bool OnlyNew, bool Details, const QString &Sort, bool Descending, bool WithInvisible, const QString &CatType, const QString &GroupBy)
static QStringList GetStoredSearches(const QString &Type)
static void RegisterCustomTypes()
static QStringList GetCategoryList()
static bool RemoveFromChannelGroup(int ChannelGroupId, int ChanId)
static bool AddToChannelGroup(int ChannelGroupId, int ChanId)
static V2Program * GetProgramDetails(int ChanId, const QDateTime &StartTime)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QMap< QString, QVariant > MSqlBindings
typedef for a map of string -> string bindings for generic queries.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
ProgramInfo * LoadProgramFromProgram(const uint chanid, const QDateTime &starttime)
bool LoadFromProgram(ProgramList &destination, const QString &where, const QString &groupBy, const QString &orderBy, const MSqlBindings &bindings, const ProgramList &schedList)
RecSearchType searchTypeFromString(const QString &type)
Q_GLOBAL_STATIC_WITH_ARGS(MythHTTPMetaService, s_service,(GUIDE_HANDLE, V2Guide::staticMetaObject, &V2Guide::RegisterCustomTypes)) void V2Guide
void V2FillChannelGroup(V2ChannelGroup *pGroup, const ChannelGroupItem &pGroupItem)
void V2FillProgramInfo(V2Program *pProgram, ProgramInfo *pInfo, bool bIncChannel, bool bDetails, bool bIncCast, bool bIncArtwork, bool bIncRecording)
bool V2FillChannelInfo(V2ChannelInfo *pChannel, uint nChanID, bool bDetails)