30 #include <QImageWriter> 56 const QString &sFileName )
58 QString sGroup = sStorageGroup;
62 LOG(VB_UPNP, LOG_WARNING,
63 "GetFile - StorageGroup missing... using 'Default'");
67 if (sFileName.isEmpty())
69 QString sMsg (
"GetFile - FileName missing." );
81 QString sFullFileName = storage.
FindFile( sFileName );
83 if (sFullFileName.isEmpty())
86 QString(
"GetFile - Unable to find %1.").arg(sFileName));
95 if (QFile::exists( sFullFileName ))
97 return QFileInfo( sFullFileName );
100 LOG(VB_UPNP, LOG_ERR,
101 QString(
"GetFile - File Does not exist %1.").arg(sFullFileName));
111 const QString &sFileName,
115 QString sGroup = sStorageGroup;
117 if (sGroup.isEmpty())
119 LOG(VB_UPNP, LOG_WARNING,
120 "GetImageFile - StorageGroup missing... using 'Default'");
124 if (sFileName.isEmpty())
126 QString sMsg (
"GetImageFile - FileName missing." );
138 QString sFullFileName = storage.
FindFile( sFileName );
140 if (sFullFileName.isEmpty())
142 LOG(VB_UPNP, LOG_WARNING,
143 QString(
"GetImageFile - Unable to find %1.").arg(sFileName));
152 if (!QFile::exists( sFullFileName ))
154 LOG(VB_UPNP, LOG_WARNING,
155 QString(
"GetImageFile - File Does not exist %1.").arg(sFullFileName));
162 if ((nWidth == 0) && (nHeight == 0))
163 return QFileInfo( sFullFileName );
168 QString sNewFileName = QString(
"%1.%2x%3.jpg" )
169 .arg( sFullFileName )
177 if (QFile::exists( sNewFileName ))
178 return QFileInfo( sNewFileName );
184 QImage *pImage =
new QImage( sFullFileName );
186 if (!pImage || pImage->isNull())
189 float fAspect = (float)(pImage->width()) / pImage->height();
192 nWidth = (int)rint(nHeight * fAspect);
195 nHeight = (int)rint(nWidth / fAspect);
197 QImage img = pImage->scaled( nWidth, nHeight, Qt::KeepAspectRatio,
198 Qt::SmoothTransformation);
200 QByteArray fname = sNewFileName.toLatin1();
201 img.save( fname.constData(),
"JPG", 60 );
205 return QFileInfo( sNewFileName );
215 if (sStorageGroup.isEmpty())
217 QString sMsg(
"GetDirList - StorageGroup missing.");
218 LOG(VB_UPNP, LOG_ERR, sMsg);
235 if (sStorageGroup.isEmpty())
237 QString sMsg(
"GetFileList - StorageGroup missing.");
238 LOG(VB_UPNP, LOG_ERR, sMsg);
253 const QString &sInetref,
266 if (sType.toLower() ==
"coverart")
271 else if (sType.toLower() ==
"fanart")
276 else if (sType.toLower() ==
"banner")
282 if (!map.contains(
type))
285 QUrl url(map.value(
type).url);
286 QString sFileName = url.path();
288 if (sFileName.isEmpty())
291 return GetImageFile( sgroup, sFileName, nWidth, nHeight);
300 const QDateTime &recstarttsRaw)
302 if ((RecordedId <= 0) &&
303 (chanid <= 0 || !recstarttsRaw.isValid()))
304 throw QString(
"Recorded ID or Channel ID and StartTime appears invalid.");
311 pginfo =
ProgramInfo(chanid, recstarttsRaw.toUTC());
331 int nId,
int nWidth,
int nHeight )
333 LOG(VB_UPNP, LOG_INFO, QString(
"GetVideoArtwork ID = %1").arg(nId));
335 QString sgroup =
"Coverart";
336 QString column =
"coverfile";
338 if (sType.toLower() ==
"coverart")
341 column =
"coverfile";
343 else if (sType.toLower() ==
"fanart")
348 else if (sType.toLower() ==
"banner")
353 else if (sType.toLower() ==
"screenshot")
355 sgroup =
"Screenshots";
356 column =
"screenshot";
365 QString querystr = QString(
"SELECT %1 FROM videometadata WHERE " 366 "intid = :ITEMID").arg(column);
377 QString sFileName = query.
value(0).toString();
379 if (sFileName.isEmpty())
382 return GetImageFile( sgroup, sFileName, nWidth, nHeight );
401 LOG(VB_GENERAL, LOG_DEBUG, QString(
"GetAlbumArt: %1").arg(sFullFileName));
408 QString sNewFileName = QString(
"/tmp/%1.%2x%3.jpg" )
409 .arg( QFileInfo(sFullFileName).fileName() )
417 if (QFile::exists( sNewFileName ))
418 return QFileInfo( sNewFileName );
426 if (sFullFileName.startsWith(
"myth://"))
428 RemoteFile rf(sFullFileName,
false,
false, 0);
432 img.loadFromData(data);
435 img.load(sFullFileName);
442 if ((nWidth == 0) && (nHeight == 0))
444 if (!sFullFileName.startsWith(
"myth://"))
446 QFileInfo fi(sFullFileName);
447 if (fi.suffix().toLower() ==
"jpg")
451 else if (nWidth > img.width() && nHeight > img.height())
461 float fAspect = (float)(img.width()) / img.height();
463 if ( nWidth == 0 || nWidth > img.width() )
464 nWidth = (
int)rint(nHeight * fAspect);
466 if ( nHeight == 0 || nHeight > img.height() )
467 nHeight = (
int)rint(nWidth / fAspect);
469 img = img.scaled( nWidth, nHeight, Qt::KeepAspectRatio,
470 Qt::SmoothTransformation);
473 QString fname = sNewFileName.toLatin1().constData();
476 if (!img.save( fname,
"JPG" ))
479 return QFileInfo( sNewFileName );
488 const QDateTime &recstarttsRaw,
492 const QString &sFormat )
494 if ((nRecordedId <= 0) &&
495 (nChanId <= 0 || !recstarttsRaw.isValid()))
496 throw QString(
"Recorded ID or Channel ID and StartTime appears invalid.");
498 if (!sFormat.isEmpty()
499 && !QImageWriter::supportedImageFormats().contains(sFormat.toLower().toLocal8Bit()))
501 throw QString(
"GetPreviewImage: Specified 'Format' is not supported.");
513 pginfo =
ProgramInfo(nChanId, recstarttsRaw.toUTC());
517 LOG(VB_GENERAL, LOG_ERR,
518 QString(
"GetPreviewImage: No recording for '%1'")
526 QString(
"GetPreviewImage: Wrong Host '%1' request from '%2'")
530 LOG(VB_UPNP, LOG_ERR, sMsg);
535 QString sImageFormat = sFormat;
536 if (sImageFormat.isEmpty())
537 sImageFormat =
"PNG";
545 QString sPreviewFileName;
550 sPreviewFileName = QString(
"%1.png").arg(sFileName);
554 sPreviewFileName = QString(
"%1.%2.png").arg(sFileName).arg(nSecsIn);
557 if (!QFile::exists( sPreviewFileName ))
562 if (!pginfo.
IsLocal() && sFileName.startsWith(
"/"))
574 bool ok = previewgen->
Run();
582 bool bDefaultPixmap = (nWidth == 0) && (nHeight == 0);
584 QString sNewFileName;
587 sNewFileName = sPreviewFileName;
590 sNewFileName = QString(
"%1.%2.%3x%4.%5" )
593 .arg( nWidth == 0 ? -1 : nWidth )
594 .arg( nHeight == 0 ? -1 : nHeight )
595 .arg( sImageFormat.toLower() );
601 if (QFile::exists( sNewFileName ))
603 if (QFileInfo(sPreviewFileName).lastModified() <=
604 QFileInfo(sNewFileName).lastModified())
605 return QFileInfo( sNewFileName );
608 QImage image = QImage(sPreviewFileName);
616 image = image.scaledToHeight(nHeight, Qt::SmoothTransformation);
617 else if ( nHeight <= 0 )
618 image = image.scaledToWidth(nWidth, Qt::SmoothTransformation);
620 image = image.scaled(nWidth, nHeight, Qt::IgnoreAspectRatio,
621 Qt::SmoothTransformation);
623 image.save(sNewFileName, sImageFormat.toUpper().toLocal8Bit());
629 LOG(VB_GENERAL, LOG_ERR,
"Unable to change permissions on " 630 "preview image. Backends and frontends " 631 "running under different users will be " 632 "unable to access it");
636 if (QFile::exists( sNewFileName ))
637 return QFileInfo( sNewFileName );
646 bool ok = previewgen->
Run();
653 return QFileInfo( sNewFileName );
662 const QDateTime &recstarttsRaw )
664 if ((nRecordedId <= 0) &&
665 (nChanId <= 0 || !recstarttsRaw.isValid()))
666 throw QString(
"Recorded ID or Channel ID and StartTime appears invalid.");
677 pginfo =
ProgramInfo(nChanId, recstarttsRaw.toUTC());
681 LOG(VB_UPNP, LOG_ERR, QString(
"GetRecording - for '%1' failed")
692 QString(
"GetRecording: Wrong Host '%1' request from '%2'.")
696 LOG(VB_UPNP, LOG_ERR, sMsg);
707 if (QFile::exists( sFileName ))
708 return QFileInfo( sFileName );
729 query.
prepare(
"SELECT CONCAT_WS('/', music_directories.path, " 730 "music_songs.filename) AS filename FROM music_songs " 731 "LEFT JOIN music_directories ON " 732 "music_songs.directory_id=" 733 "music_directories.directory_id " 734 "WHERE music_songs.song_id = :KEY");
746 sFileName = query.
value(0).toString();
750 if (sFileName.isEmpty())
753 return GetFile(
"Music", sFileName );
772 query.
prepare(
"SELECT filename FROM videometadata WHERE intid = :KEY" );
782 sFileName = query.
value(0).toString();
785 if (sFileName.isEmpty())
788 if (!QFile::exists( sFileName ))
789 return GetFile(
"Videos", sFileName );
791 return QFileInfo( sFileName );
799 const QString &sFileName )
801 if ((sFileName.isEmpty()) ||
802 (sFileName.contains(
"/../")) ||
803 (sFileName.startsWith(
"../")))
805 LOG(VB_GENERAL, LOG_ERR,
806 QString(
"ERROR checking for file, filename '%1' " 807 "fails sanity checks").arg(sFileName));
811 QString storageGroup =
"Default";
813 if (!sStorageGroup.isEmpty())
814 storageGroup = sStorageGroup;
818 QString fullname = sgroup.
FindFile(sFileName);
833 QFileInfo finfo(sURL);
834 QString filename = finfo.fileName();
839 if (outDir.isEmpty())
841 LOG(VB_GENERAL, LOG_ERR,
842 QString(
"Unable to determine directory " 843 "to write to in %1 write command").arg(sURL));
847 if ((filename.contains(
"/../")) ||
848 (filename.startsWith(
"../")))
850 LOG(VB_GENERAL, LOG_ERR,
851 QString(
"ERROR: %1 write filename '%2' does not " 852 "pass sanity checks.") .arg(sURL).arg(filename));
856 outFile = outDir +
"/" + filename;
869 const QString &sFileName,
870 const QString &sHostName,
878 QString sGroup = sStorageGroup;
880 if (sGroup.isEmpty())
882 LOG(VB_UPNP, LOG_WARNING,
883 "AddLiveStream - StorageGroup missing... using 'Default'");
887 if (sFileName.isEmpty())
889 QString sMsg (
"AddLiveStream - FileName missing." );
891 LOG(VB_UPNP, LOG_ERR, sMsg);
900 QString sFullFileName;
904 sFullFileName = storage.
FindFile( sFileName );
906 if (sFullFileName.isEmpty())
908 LOG(VB_UPNP, LOG_ERR,
909 QString(
"AddLiveStream - Unable to find %1.").arg(sFileName));
921 HTTPLiveStream(sFullFileName, nWidth, nHeight, nBitrate, nAudioBitrate,
922 nMaxSegments, 0, 0, nSampleRate);
926 LOG(VB_UPNP, LOG_ERR,
927 "AddLiveStream - Unable to create HTTPLiveStream.");
966 LOG( VB_UPNP, LOG_ERR,
967 QString(
"GetLiveStream - for stream id %1 failed").arg( nId ));
974 LOG( VB_UPNP, LOG_ERR,
975 QString(
"HLS::GetLiveStreamInfo - for stream id %1 failed")
1000 const QDateTime &recstarttsRaw,
1008 if ((nRecordedId <= 0) &&
1009 (nChanId <= 0 || !recstarttsRaw.isValid()))
1010 throw QString(
"Recorded ID or Channel ID and StartTime appears invalid.");
1018 if (nRecordedId > 0)
1021 pginfo =
ProgramInfo(nChanId, recstarttsRaw.toUTC());
1025 LOG(VB_UPNP, LOG_ERR,
1026 QString(
"AddRecordingLiveStream - for %1, %2 failed")
1027 .arg(QString::number(nRecordedId)));
1036 QString(
"GetRecording: Wrong Host '%1' request from '%2'.")
1040 LOG(VB_UPNP, LOG_ERR, sMsg);
1051 if (!QFile::exists( sFileName ))
1053 LOG( VB_UPNP, LOG_ERR, QString(
"AddRecordingLiveStream - for %1, %2 failed")
1055 .arg( recstarttsRaw.toUTC().toString() ));
1059 QFileInfo fInfo( sFileName );
1063 nHeight, nBitrate, nAudioBitrate, nSampleRate );
1079 throw QString(
"Id is invalid" );
1086 LOG( VB_UPNP, LOG_ERR, QString(
"AddVideoLiveStream - no metadata for %1")
1096 QString(
"AddVideoLiveStream: Wrong Host '%1' request from '%2'.")
1098 .arg( metadata->GetHost() );
1100 LOG(VB_UPNP, LOG_ERR, sMsg);
1106 QString sFileName = sg.
FindFile(metadata->GetFilename());
1112 if (!QFile::exists( sFileName ))
1114 LOG( VB_UPNP, LOG_ERR, QString(
"AddVideoLiveStream - file does not exist."));
1119 metadata->GetHost(), nMaxSegments, nWidth,
1120 nHeight, nBitrate, nAudioBitrate, nSampleRate );
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
QStringList GetDirList(const QString &StorageGroup) override
void bindValue(const QString &placeholder, const QVariant &val)
QString FileHash(QString filename)
QStringList GetDirList(void) const
DTC::LiveStreamInfo * GetLiveStream(int Id) override
QString GetHash(const QString &StorageGroup, const QString &FileName) override
QString GenMythURL(QString host=QString(), QString port=QString(), QString path=QString(), QString storageGroup=QString())
bool RemoveLiveStream(int Id) override
void FillArtworkInfoList(DTC::ArtworkInfoList *pArtworkInfoList, const QString &sInetref, uint nSeason)
QFileInfo GetRecordingArtwork(const QString &Type, const QString &Inetref, int Season, int Width, int Height) override
void SetPathname(const QString &) const
static DTC::LiveStreamInfoList * GetLiveStreamInfoList(const QString &FileName="")
QSqlQuery wrapper that fetches a DB connection from the connection pool.
void SetOutputFilename(const QString &)
QStringList GetFileList(const QString &StorageGroup) override
bool isConnected(void)
Only updated once during object creation.
QFileInfo GetAlbumArt(int Id, int Width, int Height) override
bool DownloadFile(const QString &URL, const QString &StorageGroup) override
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
DTC::LiveStreamInfoList * GetLiveStreamList(const QString &FileName) override
QFileInfo GetPreviewImage(int RecordedId, int ChanId, const QDateTime &StartTime, int Width, int Height, int SecsIn, const QString &Format) override
QFileInfo GetMusic(int Id) override
This class creates a preview image of a recording.
QString GetInetRef(void) const
QString GetStorageGroup(void) const
DTC::LiveStreamInfo * GetLiveStreamInfo(DTC::LiveStreamInfo *info=nullptr)
DTC::LiveStreamInfo * AddLiveStream(const QString &StorageGroup, const QString &FileName, const QString &HostName, int MaxSegments, int Width, int Height, int Bitrate, int AudioBitrate, int SampleRate) override
QVariant value(int i) const
DTC::ArtworkInfoList * GetProgramArtworkList(const QString &Inetref, int Season) override
Holds information on recordings and videos.
QFileInfo GetFile(const QString &StorageGroup, const QString &FileName) override
bool makeFileAccessible(QString filename)
Makes a file accessible to all frontends/backends.
DTC::LiveStreamInfo * StopLiveStream(int Id) override
QString FindNextDirMostFree(void)
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
static bool RemoveStream(int id)
uint GetSeason(void) const
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
static DTC::LiveStreamInfo * StopStream(int id)
DTC::LiveStreamInfo * AddVideoLiveStream(int Id, int MaxSegments, int Width, int Height, int Bitrate, int AudioBitrate, int SampleRate) override
QFileInfo GetRecording(int RecordedId, int ChanId, const QDateTime &StartTime) override
void SetOutputSize(const QSize &size)
DTC::LiveStreamInfo * StartStream(void)
static bool Exists(const QString &url, struct stat *fileinfo)
void SetPreviewTimeAsSeconds(long long seconds_in)
bool SaveAs(QByteArray &data)
QFileInfo GetImageFile(const QString &StorageGroup, const QString &FileName, int Width, int Height) override
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
#define LOG(_MASK_, _LEVEL_, _STRING_)
QFileInfo GetVideoArtwork(const QString &Type, int Id, int Width, int Height) override
QString FindFile(const QString &filename)
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
QString GetPlaybackURL(ProgramInfo *pginfo, bool storePath)
QStringList GetFileList(const QString &Path, bool recursive=false)
QString GetHostname(void) const
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
static void DBError(const QString &where, const MSqlQuery &query)
QFileInfo GetVideo(int Id) override
QString GetHostName(void)
DTC::ArtworkInfoList * GetRecordingArtworkList(int RecordedId, int ChanId, const QDateTime &StartTime) override
DTC::LiveStreamInfo * AddRecordingLiveStream(int RecordedId, int ChanId, const QDateTime &StartTime, int MaxSegments, int Width, int Height, int Bitrate, int AudioBitrate, int SampleRate) override