35#include "libmythbase/mythversion.h"
68 qRegisterMetaType< QFileInfo >();
69 qRegisterMetaType<V2ProgramGuide*>(
"V2ProgramGuide");
70 qRegisterMetaType<V2ProgramList*>(
"V2ProgramList");
71 qRegisterMetaType<V2Program*>(
"V2Program");
72 qRegisterMetaType<V2ChannelGroupList*>(
"V2ChannelGroupList");
73 qRegisterMetaType<V2ChannelGroup*>(
"V2ChannelGroup");
74 qRegisterMetaType<V2ChannelInfo*>(
"V2ChannelInfo");
75 qRegisterMetaType<V2RecordingInfo*>(
"V2RecordingInfo");
76 qRegisterMetaType<V2ArtworkInfoList*>(
"V2ArtworkInfoList");
77 qRegisterMetaType<V2ArtworkInfo*>(
"V2ArtworkInfo");
78 qRegisterMetaType<V2CastMemberList*>(
"V2CastMemberList");
79 qRegisterMetaType<V2CastMember*>(
"V2CastMember");
87 const QDateTime &rawEndTime,
94 if (!rawStartTime.isValid())
95 throw QString(
"StartTime is invalid" );
97 if (!rawEndTime.isValid())
98 throw QString(
"EndTime is invalid" );
100 QDateTime dtStartTime = rawStartTime.toUTC();
101 QDateTime dtEndTime = rawEndTime.toUTC();
103 if (dtEndTime < dtStartTime)
104 throw QString(
"EndTime is before StartTime");
106 nStartIndex = std::max(nStartIndex, 0);
115 uint nTotalAvailable = 0;
131 QString sWhere =
"program.chanid = :CHANID "
132 "AND program.endtime >= :STARTDATE "
133 "AND program.starttime < :ENDDATE "
134 "AND program.starttime >= :STARTDATELIMIT "
135 "AND program.manualid = 0";
138 QString sGroupBy =
"program.starttime, channel.channum,"
139 "channel.callsign, program.title";
142 QString sOrderBy =
"program.starttime";
144 bindings[
":STARTDATE" ] = dtStartTime;
145 bindings[
":STARTDATELIMIT"] = dtStartTime.addDays(-1);
146 bindings[
":ENDDATE" ] = dtEndTime;
164 ChannelInfoList::iterator chan_it;
165 for (chan_it = chanList.begin(); chan_it != chanList.end(); ++chan_it)
173 bindings[
":CHANID"] = (*chan_it).m_chanId;
179 for( progIt = progList.
begin(); progIt != progList.
end(); ++progIt)
188 pGuide->setStartTime ( dtStartTime );
189 pGuide->setEndTime ( dtEndTime );
190 pGuide->setDetails ( bDetails );
192 pGuide->setStartIndex ( nStartIndex );
193 pGuide->setCount ( chanList.size() );
194 pGuide->setTotalAvailable( nTotalAvailable );
197 pGuide->setVersion ( MYTH_BINARY_VERSION );
198 pGuide->setProtoVer ( MYTH_PROTO_VERSION );
209 const QDateTime& rawStartTime,
210 const QDateTime& rawEndTime,
212 const QString& sTitleFilter,
213 const QString& sCategoryFilter,
214 const QString& sPersonFilter,
215 const QString& sKeywordFilter,
218 const QString &sSort,
221 const QString& sCatType,
222 const QString& sGroupBy)
224 if (!rawStartTime.isNull() && !rawStartTime.isValid())
225 throw QString(
"StartTime is invalid" );
227 if (!rawEndTime.isNull() && !rawEndTime.isValid())
228 throw QString(
"EndTime is invalid" );
230 QDateTime dtStartTime = rawStartTime;
231 const QDateTime& dtEndTime = rawEndTime;
233 if (!rawEndTime.isNull() && dtEndTime < dtStartTime)
234 throw QString(
"EndTime is before StartTime");
237 if (!sGroupBy.isEmpty())
240 auto meta = QMetaEnum::fromType<ProgGroupBy::Type>();
244 throw QString(
"GroupBy is invalid" );
260 if (!sPersonFilter.isEmpty())
262 sSQL =
", people, credits "
263 "WHERE people.name LIKE :PersonFilter "
264 "AND credits.person = people.person "
265 "AND program.chanid = credits.chanid "
266 "AND program.starttime = credits.starttime AND ";
267 bindings[
":PersonFilter"] = QString(
"%%1%").arg(sPersonFilter);
276 sSQL =
"LEFT JOIN oldprogram ON oldprogram.oldtitle = program.title "
278 +
"oldprogram.oldtitle IS NULL AND ";
281 sSQL +=
"deleted IS NULL AND ";
284 sSQL +=
"visible > 0 AND ";
286 sSQL +=
"program.manualid = 0 ";
288 nChanId = std::max(nChanId, 0);
292 sSQL +=
"AND program.chanid = :ChanId ";
293 bindings[
":ChanId"] = nChanId;
296 if (dtStartTime.isNull())
297 dtStartTime = QDateTime::currentDateTimeUtc();
299 sSQL +=
" AND program.endtime >= :StartDate ";
300 bindings[
":StartDate"] = dtStartTime;
302 if (!dtEndTime.isNull())
304 sSQL +=
"AND program.starttime <= :EndDate ";
305 bindings[
":EndDate"] = dtEndTime;
308 if (!sTitleFilter.isEmpty())
310 sSQL +=
"AND program.title LIKE :Title ";
311 bindings[
":Title"] = QString(
"%%1%").arg(sTitleFilter);
314 if (!sCategoryFilter.isEmpty())
316 sSQL +=
"AND program.category LIKE :Category ";
317 bindings[
":Category"] = sCategoryFilter;
320 if (!sCatType.isEmpty())
322 sSQL +=
"AND program.category_type LIKE :CatType ";
323 bindings[
":CatType"] = sCatType;
326 if (!sKeywordFilter.isEmpty())
328 sSQL +=
"AND (program.title LIKE :Keyword1 "
329 "OR program.subtitle LIKE :Keyword2 "
330 "OR program.description LIKE :Keyword3) ";
332 QString filter = QString(
"%%1%").arg(sKeywordFilter);
333 bindings[
":Keyword1"] = filter;
334 bindings[
":Keyword2"] = filter;
335 bindings[
":Keyword3"] = filter;
338 if (sSort ==
"starttime")
339 sSQL +=
"ORDER BY program.starttime ";
340 else if (sSort ==
"title")
341 sSQL +=
"ORDER BY program.title ";
342 else if (sSort ==
"channel")
343 sSQL +=
"ORDER BY channel.channum ";
344 else if (sSort ==
"duration")
345 sSQL +=
"ORDER BY (program.endtime - program.starttime) ";
347 sSQL +=
"ORDER BY program.starttime, channel.channum + 0 ";
366 uint nTotalAvailable = 0;
368 (
uint)nStartIndex, (
uint)nCount, nTotalAvailable,
377 nCount = (int)progList.
size();
378 int nEndIndex = (int)progList.
size();
380 for(
int n = 0; n < nEndIndex; n++)
387 bool duplicate =
false;
389 auto *prior = progList[
back];
390 if (prior !=
nullptr) {
391 if (pInfo -> GetTitle() == prior -> GetTitle()) {
401 V2Program *pProgram = pPrograms->AddNewProgram();
408 pPrograms->setStartIndex ( nStartIndex );
409 pPrograms->setCount ( nCount );
410 pPrograms->setTotalAvailable( nTotalAvailable );
412 pPrograms->setVersion ( MYTH_BINARY_VERSION );
413 pPrograms->setProtoVer ( MYTH_PROTO_VERSION );
423 const QDateTime &rawStartTime )
427 throw QString(
"Channel ID is invalid" );
428 if (!rawStartTime.isValid())
429 throw QString(
"StartTime is invalid" );
431 QDateTime dtStartTime = rawStartTime.toUTC();
456 const QString &FileName )
462 if (FileName.isEmpty())
465 sFileName = FileName;
467 if (sFileName.isEmpty())
469 LOG(VB_UPNP, LOG_ERR,
470 QString(
"GetImageFile - ChanId %1 doesn't exist or isn't visible")
480 QString sFullFileName = storage.
FindFile( sFileName );
482 if (sFullFileName.isEmpty())
484 LOG(VB_UPNP, LOG_ERR,
485 QString(
"GetImageFile - Unable to find %1.").arg(sFileName));
494 if ((nWidth == 0) && (nHeight == 0))
498 return QFileInfo( sFullFileName );
501 LOG(VB_UPNP, LOG_ERR,
502 QString(
"GetImageFile - File Does not exist %1.").arg(sFullFileName));
508 QString sNewFileName = QString(
"%1.%2x%3.png" )
509 .arg( sFullFileName )
518 return QFileInfo( sNewFileName );
524 QString sChannelsDirectory = QFileInfo( sNewFileName ).absolutePath();
526 if (!QFileInfo( sChannelsDirectory ).isWritable())
528 LOG(VB_UPNP, LOG_ERR, QString(
"GetImageFile - no write access to: %1")
529 .arg( sChannelsDirectory ));
533 auto *pImage =
new QImage( sFullFileName );
537 LOG(VB_UPNP, LOG_ERR, QString(
"GetImageFile - can't create image: %1")
538 .arg( sFullFileName ));
542 float fAspect = (float)(pImage->width()) / pImage->height();
545 LOG(VB_UPNP, LOG_ERR, QString(
"GetImageFile - zero aspect"));
551 nWidth = (int)std::rint(nHeight * fAspect);
554 nHeight = (int)std::rint(nWidth / fAspect);
556 QImage img = pImage->scaled( nWidth, nHeight, Qt::IgnoreAspectRatio,
557 Qt::SmoothTransformation);
561 LOG(VB_UPNP, LOG_ERR, QString(
"SaveImageFile - unable to scale. "
562 "See if %1 is really an image.").arg( sFullFileName ));
567 if (!img.save( sNewFileName,
"PNG" ))
569 LOG(VB_UPNP, LOG_ERR, QString(
"SaveImageFile - failed, %1")
570 .arg( sNewFileName ));
577 return QFileInfo( sNewFileName );
589 ChannelGroupList::iterator it;
590 for (it = list.begin(); it < list.end(); ++it)
608 query.
prepare(
"SELECT DISTINCT category FROM program WHERE category != '' "
609 "ORDER BY category");
616 catList << query.
value(0).toString();
628 QStringList keywordList;
639 query.
prepare(
"SELECT DISTINCT phrase FROM keyword "
640 "WHERE searchtype = :TYPE "
642 query.
bindValue(
":TYPE",
static_cast<int>(iType));
649 keywordList << query.
value(0).toString();
662 bool bResult =
false;
665 throw QString(
"Channel ID is invalid" );
679 bool bResult =
false;
682 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)