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;
618 sNewFileName = sPreviewFileName;
622 sNewFileName = QString(
"%1.%2.%3x%4.%5" )
625 .arg( nWidth == 0 ? -1 : nWidth )
626 .arg( nHeight == 0 ? -1 : nHeight )
627 .arg( sImageFormat.toLower() );
635 if (QFileInfo(sPreviewFileName).lastModified() <=
636 QFileInfo(sNewFileName).lastModified())
637 return QFileInfo( sNewFileName );
640 QImage image = QImage(sPreviewFileName);
648 image = image.scaledToHeight(nHeight, Qt::SmoothTransformation);
649 else if ( nHeight <= 0 )
650 image = image.scaledToWidth(nWidth, Qt::SmoothTransformation);
652 image = image.scaled(nWidth, nHeight, Qt::IgnoreAspectRatio,
653 Qt::SmoothTransformation);
655 image.save(sNewFileName, sImageFormat.toUpper().toLocal8Bit().constData());
661 LOG(VB_GENERAL, LOG_ERR,
"Unable to change permissions on "
662 "preview image. Backends and frontends "
663 "running under different users will be "
664 "unable to access it");
669 return QFileInfo( sNewFileName );
673 previewgen->SetPreviewTimeAsSeconds( nSecs );
674 previewgen->SetOutputFilename ( sNewFileName );
675 previewgen->SetOutputSize (QSize(nWidth,nHeight));
677 bool ok = previewgen->Run();
679 previewgen->deleteLater();
684 return QFileInfo( sNewFileName );
693 const QDateTime &StartTime,
694 const QString &Download )
696 if ((nRecordedId <= 0) &&
697 (nChanId <= 0 || !StartTime.isValid()))
698 throw QString(
"Recorded ID or Channel ID and StartTime appears invalid.");
713 LOG(VB_UPNP, LOG_ERR, QString(
"GetRecording - for '%1' failed")
725 QString(
"GetRecording: Wrong Host '%1' request from '%2'.")
729 LOG(VB_UPNP, LOG_ERR, sMsg);
737 m_request->m_headers->insert(
"mythtv-download",Download);
744 return QFileInfo( sFileName );
765 query.
prepare(
"SELECT CONCAT_WS('/', music_directories.path, "
766 "music_songs.filename) AS filename FROM music_songs "
767 "LEFT JOIN music_directories ON "
768 "music_songs.directory_id="
769 "music_directories.directory_id "
770 "WHERE music_songs.song_id = :KEY");
782 sFileName = query.
value(0).toString();
786 if (sFileName.isEmpty())
789 return GetFile(
"Music", sFileName );
808 query.
prepare(
"SELECT filename FROM videometadata WHERE intid = :KEY" );
818 sFileName = query.
value(0).toString();
821 if (sFileName.isEmpty())
825 return GetFile(
"Videos", sFileName );
827 return QFileInfo( sFileName );
835 const QString &sFileName )
837 if ((sFileName.isEmpty()) ||
838 (sFileName.contains(
"/../")) ||
839 (sFileName.startsWith(
"../")))
841 LOG(VB_GENERAL, LOG_ERR,
842 QString(
"ERROR checking for file, filename '%1' "
843 "fails sanity checks").arg(sFileName));
847 QString storageGroup =
"Default";
849 if (!sStorageGroup.isEmpty())
850 storageGroup = sStorageGroup;
854 QString fullname = sgroup.
FindFile(sFileName);
869 QFileInfo finfo(sURL);
870 QString
filename = finfo.fileName();
875 if (outDir.isEmpty())
877 LOG(VB_GENERAL, LOG_ERR,
878 QString(
"Unable to determine directory "
879 "to write to in %1 write command").arg(sURL));
886 LOG(VB_GENERAL, LOG_ERR,
887 QString(
"ERROR: %1 write filename '%2' does not "
888 "pass sanity checks.").arg(sURL,
filename));
899#include "moc_v2content.cpp"
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)