32#include <QImageWriter>
69 qRegisterMetaType< QFileInfo >();
70 qRegisterMetaType<V2ArtworkInfoList*>(
"V2ArtworkInfoList");
71 qRegisterMetaType<V2ArtworkInfo*>(
"V2ArtworkInfo");
83 const QString &sFileName )
85 QString sGroup = sStorageGroup;
89 LOG(VB_UPNP, LOG_WARNING,
90 "GetFile - StorageGroup missing... using 'Default'");
94 if (sFileName.isEmpty())
96 QString sMsg (
"GetFile - FileName missing." );
108 QString sFullFileName = storage.
FindFile( sFileName );
110 if (sFullFileName.isEmpty())
112 LOG(VB_UPNP, LOG_ERR,
113 QString(
"GetFile - Unable to find %1.").arg(sFileName));
124 return QFileInfo( sFullFileName );
127 LOG(VB_UPNP, LOG_ERR,
128 QString(
"GetFile - File Does not exist %1.").arg(sFullFileName));
138 const QString &sFileName,
142 QString sGroup = sStorageGroup;
144 if (sGroup.isEmpty())
146 LOG(VB_UPNP, LOG_WARNING,
147 "GetImageFile - StorageGroup missing... using 'Default'");
151 if (sFileName.isEmpty())
153 QString sMsg (
"GetImageFile - FileName missing." );
165 QString sFullFileName = storage.
FindFile( sFileName );
167 if (sFullFileName.isEmpty())
169 LOG(VB_UPNP, LOG_WARNING,
170 QString(
"GetImageFile - Unable to find %1.").arg(sFileName));
181 LOG(VB_UPNP, LOG_WARNING,
182 QString(
"GetImageFile - File Does not exist %1.").arg(sFullFileName));
189 if ((nWidth == 0) && (nHeight == 0))
190 return QFileInfo( sFullFileName );
195 QString sNewFileName = QString(
"%1.%2x%3.jpg" )
196 .arg( sFullFileName )
205 return QFileInfo( sNewFileName );
211 auto *pImage =
new QImage( sFullFileName );
213 if (!pImage || pImage->isNull())
216 float fAspect = (float)(pImage->width()) / pImage->height();
219 nWidth = (int)std::rint(nHeight * fAspect);
222 nHeight = (int)std::rint(nWidth / fAspect);
224 QImage img = pImage->scaled( nWidth, nHeight, Qt::KeepAspectRatio,
225 Qt::SmoothTransformation);
227 QByteArray fname = sNewFileName.toLatin1();
228 img.save( fname.constData(),
"JPG", 60 );
232 return QFileInfo( sNewFileName );
242 if (sStorageGroup.isEmpty())
244 QString sMsg(
"GetDirList - StorageGroup missing.");
245 LOG(VB_UPNP, LOG_ERR, sMsg);
262 if (sStorageGroup.isEmpty())
264 QString sMsg(
"GetFileList - StorageGroup missing.");
265 LOG(VB_UPNP, LOG_ERR, sMsg);
280 const QString &sInetref,
293 if (sType.toLower() ==
"coverart")
298 else if (sType.toLower() ==
"fanart")
303 else if (sType.toLower() ==
"banner")
309 if (!map.contains(
type))
312 QUrl url(map.value(
type).url);
313 QString sFileName = url.path();
315 if (sFileName.isEmpty())
318 return GetImageFile( sgroup, sFileName, nWidth, nHeight);
327 const QDateTime &StartTime)
329 if ((RecordedId <= 0) &&
330 (chanid <= 0 || !StartTime.isValid()))
331 throw QString(
"Recorded ID or Channel ID and StartTime appears invalid.");
358 int nId,
int nWidth,
int nHeight )
360 LOG(VB_UPNP, LOG_INFO, QString(
"GetVideoArtwork ID = %1").arg(nId));
362 QString sgroup =
"Coverart";
363 QString column =
"coverfile";
365 if (sType.toLower() ==
"coverart")
368 column =
"coverfile";
370 else if (sType.toLower() ==
"fanart")
375 else if (sType.toLower() ==
"banner")
380 else if (sType.toLower() ==
"screenshot")
382 sgroup =
"Screenshots";
383 column =
"screenshot";
392 QString querystr = QString(
"SELECT %1 FROM videometadata WHERE "
393 "intid = :ITEMID").arg(column);
404 QString sFileName = query.
value(0).toString();
406 if (sFileName.isEmpty())
409 return GetImageFile( sgroup, sFileName, nWidth, nHeight );
428 LOG(VB_GENERAL, LOG_DEBUG, QString(
"GetAlbumArt: %1").arg(sFullFileName));
435 QString sNewFileName = QString(
"/tmp/%1.%2x%3.jpg" )
436 .arg( QFileInfo(sFullFileName).fileName() )
445 return QFileInfo( sNewFileName );
453 if (sFullFileName.startsWith(
"myth://"))
455 RemoteFile rf(sFullFileName,
false,
false, 0s);
459 img.loadFromData(data);
463 img.load(sFullFileName);
471 if ((nWidth == 0) && (nHeight == 0))
473 if (!sFullFileName.startsWith(
"myth://"))
475 QFileInfo fi(sFullFileName);
476 if (fi.suffix().toLower() ==
"jpg")
480 else if (nWidth > img.width() && nHeight > img.height())
490 float fAspect = (float)(img.width()) / img.height();
492 if ( nWidth == 0 || nWidth > img.width() )
493 nWidth = (
int)std::rint(nHeight * fAspect);
495 if ( nHeight == 0 || nHeight > img.height() )
496 nHeight = (int)std::rint(nWidth / fAspect);
498 img = img.scaled( nWidth, nHeight, Qt::KeepAspectRatio,
499 Qt::SmoothTransformation);
502 QString fname = sNewFileName.toLatin1().constData();
505 if (!img.save( fname,
"JPG" ))
508 return QFileInfo( sNewFileName );
517 const QDateTime &StartTime,
521 const QString &sFormat )
523 if ((nRecordedId <= 0) &&
524 (nChanId <= 0 || !StartTime.isValid()))
525 throw QString(
"Recorded ID or Channel ID and StartTime appears invalid.");
527 if (!sFormat.isEmpty()
528 && !QImageWriter::supportedImageFormats().contains(sFormat.toLower().toLocal8Bit()))
530 throw QString(
"GetPreviewImage: Specified 'Format' is not supported.");
546 LOG(VB_GENERAL, LOG_ERR,
547 QString(
"GetPreviewImage: No recording for '%1'")
556 QString(
"GetPreviewImage: Wrong Host '%1' request from '%2'")
560 LOG(VB_UPNP, LOG_ERR, sMsg);
565 QString sImageFormat = sFormat;
566 if (sImageFormat.isEmpty())
567 sImageFormat =
"PNG";
575 QString sPreviewFileName;
577 auto nSecs = std::chrono::seconds(nSecsIn);
581 sPreviewFileName = QString(
"%1.png").arg(sFileName);
585 sPreviewFileName = QString(
"%1.%2.png").arg(sFileName).arg(nSecsIn);
593 if (!pginfo.
IsLocal() && sFileName.startsWith(
"/"))
601 previewgen->SetPreviewTimeAsSeconds( nSecs );
602 previewgen->SetOutputFilename ( sPreviewFileName );
604 bool ok = previewgen->Run();
606 previewgen->deleteLater();
612 bool bDefaultPixmap = (nWidth == 0) && (nHeight == 0);
614 QString sNewFileName;
617 sNewFileName = sPreviewFileName;
620 sNewFileName = QString(
"%1.%2.%3x%4.%5" )
623 .arg( nWidth == 0 ? -1 : nWidth )
624 .arg( nHeight == 0 ? -1 : nHeight )
625 .arg( sImageFormat.toLower() );
633 if (QFileInfo(sPreviewFileName).lastModified() <=
634 QFileInfo(sNewFileName).lastModified())
635 return QFileInfo( sNewFileName );
638 QImage image = QImage(sPreviewFileName);
646 image = image.scaledToHeight(nHeight, Qt::SmoothTransformation);
647 else if ( nHeight <= 0 )
648 image = image.scaledToWidth(nWidth, Qt::SmoothTransformation);
650 image = image.scaled(nWidth, nHeight, Qt::IgnoreAspectRatio,
651 Qt::SmoothTransformation);
653 image.save(sNewFileName, sImageFormat.toUpper().toLocal8Bit());
659 LOG(VB_GENERAL, LOG_ERR,
"Unable to change permissions on "
660 "preview image. Backends and frontends "
661 "running under different users will be "
662 "unable to access it");
667 return QFileInfo( sNewFileName );
671 previewgen->SetPreviewTimeAsSeconds( nSecs );
672 previewgen->SetOutputFilename ( sNewFileName );
673 previewgen->SetOutputSize (QSize(nWidth,nHeight));
675 bool ok = previewgen->Run();
677 previewgen->deleteLater();
682 return QFileInfo( sNewFileName );
691 const QDateTime &StartTime,
692 const QString &Download )
694 if ((nRecordedId <= 0) &&
695 (nChanId <= 0 || !StartTime.isValid()))
696 throw QString(
"Recorded ID or Channel ID and StartTime appears invalid.");
711 LOG(VB_UPNP, LOG_ERR, QString(
"GetRecording - for '%1' failed")
723 QString(
"GetRecording: Wrong Host '%1' request from '%2'.")
727 LOG(VB_UPNP, LOG_ERR, sMsg);
735 m_request->m_headers->insert(
"mythtv-download",Download);
742 return QFileInfo( sFileName );
763 query.
prepare(
"SELECT CONCAT_WS('/', music_directories.path, "
764 "music_songs.filename) AS filename FROM music_songs "
765 "LEFT JOIN music_directories ON "
766 "music_songs.directory_id="
767 "music_directories.directory_id "
768 "WHERE music_songs.song_id = :KEY");
780 sFileName = query.
value(0).toString();
784 if (sFileName.isEmpty())
787 return GetFile(
"Music", sFileName );
806 query.
prepare(
"SELECT filename FROM videometadata WHERE intid = :KEY" );
816 sFileName = query.
value(0).toString();
819 if (sFileName.isEmpty())
823 return GetFile(
"Videos", sFileName );
825 return QFileInfo( sFileName );
833 const QString &sFileName )
835 if ((sFileName.isEmpty()) ||
836 (sFileName.contains(
"/../")) ||
837 (sFileName.startsWith(
"../")))
839 LOG(VB_GENERAL, LOG_ERR,
840 QString(
"ERROR checking for file, filename '%1' "
841 "fails sanity checks").arg(sFileName));
845 QString storageGroup =
"Default";
847 if (!sStorageGroup.isEmpty())
848 storageGroup = sStorageGroup;
852 QString fullname = sgroup.
FindFile(sFileName);
867 QFileInfo finfo(sURL);
868 QString
filename = finfo.fileName();
873 if (outDir.isEmpty())
875 LOG(VB_GENERAL, LOG_ERR,
876 QString(
"Unable to determine directory "
877 "to write to in %1 write command").arg(sURL));
884 LOG(VB_GENERAL, LOG_ERR,
885 QString(
"ERROR: %1 write filename '%2' does not "
886 "pass sanity checks.").arg(sURL,
filename));
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 isConnected(void) const
Only updated once during object creation.
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.
QString GetHostName(void)
bool GetBoolSetting(const QString &key, bool defaultval=false)
static void DBError(const QString &where, const MSqlQuery &query)
bool download(const QString &url, const QString &dest, bool reload=false)
Downloads a URL to a file in blocking mode.
bool HAS_PARAMv2(const QString &p)
This class creates a preview image of a recording.
Holds information on recordings and videos.
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
QString GetInetRef(void) const
QString GetHostname(void) const
uint GetSeason(void) const
void SetPathname(const QString &pn)
bool SaveAs(QByteArray &data)
static bool Exists(const QString &url, struct stat *fileinfo)
QStringList GetDirList(void) const
QString FindFile(const QString &filename)
QString FindNextDirMostFree(void)
QStringList GetFileList(const QString &Path, bool recursive=false)
QFileInfo GetRecording(int RecordedId, int ChanId, const QDateTime &StartTime, const QString &Download)
static V2ArtworkInfoList * GetProgramArtworkList(const QString &Inetref, int Season)
static V2ArtworkInfoList * GetRecordingArtworkList(int RecordedId, int ChanId, const QDateTime &StartTime)
static void RegisterCustomTypes()
static QString GetHash(const QString &StorageGroup, const QString &FileName)
static QFileInfo GetFile(const QString &StorageGroup, const QString &FileName)
static QFileInfo GetVideoArtwork(const QString &Type, int Id, int Width, int Height)
static bool DownloadFile(const QString &URL, const QString &StorageGroup)
static QFileInfo GetRecordingArtwork(const QString &Type, const QString &Inetref, int Season, int Width, int Height)
static QFileInfo GetAlbumArt(int Id, int Width, int Height)
static QFileInfo GetMusic(int Id)
static QFileInfo GetImageFile(const QString &StorageGroup, const QString &FileName, int Width, int Height)
static QStringList GetDirList(const QString &StorageGroup)
static QFileInfo GetVideo(int Id)
static QFileInfo GetPreviewImage(int RecordedId, int ChanId, const QDateTime &StartTime, int Width, int Height, int SecsIn, const QString &Format)
static QStringList GetFileList(const QString &StorageGroup)
QString GetPlaybackURL(ProgramInfo *pginfo, bool storePath)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QString FileHash(const QString &filename)
bool makeFileAccessible(const QString &filename)
Q_GLOBAL_STATIC_WITH_ARGS(MythHTTPMetaService, s_service,(CONTENT_HANDLE, V2Content::staticMetaObject, &V2Content::RegisterCustomTypes)) void V2Content
void V2FillArtworkInfoList(V2ArtworkInfoList *pArtworkInfoList, const QString &sInetref, uint nSeason)