13#define LOC QString("SG(%1): ").arg(m_groupname)
24 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"LiveTV")
26 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"DB Backups")
27 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Videos")
28 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Trailers")
29 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Coverart")
30 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Fanart")
31 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Screenshots")
32 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Banners")
33 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Photographs")
34 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Music")
35 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"MusicArt")
51 m_allowFallback(allowFallback)
55 if (qEnvironmentVariableIsSet(
"MYTHTV_NOSGFALLBACK"))
79 QDir qdir(it.value());
81 qdir.mkpath(it.value());
85 LOG(VB_GENERAL, LOG_ERR,
86 QString(
"SG() Error: Could not create builtin"
87 "Storage Group directory '%1' for '%2'")
88 .arg(it.value(), it.key()));
108 const bool allowFallback)
122 if (!testdir.exists())
125 if (testdir.exists())
127 m_dirlist.prepend(testdir.absolutePath());
135 LOG(VB_FILE, LOG_NOTICE,
LOC +
136 QString(
"Unable to find any directories for the local "
137 "storage group '%1' on '%2', trying directories on "
138 "all hosts!").arg(group,
hostname));
147 LOG(VB_FILE, LOG_NOTICE,
LOC +
148 QString(
"Unable to find storage group '%1', trying "
149 "'Default' group!").arg(group));
157 LOG(VB_FILE, LOG_NOTICE,
LOC +
158 QString(
"Unable to find any directories for the local "
159 "Default storage group on '%1', trying directories "
160 "in all Default groups!").arg(
hostname));
172 QString msg =
"Unable to find any Storage Group Directories. ";
176 msg += QString(
"Using old 'RecordFilePrefix' value of '%1'")
182 msg += QString(
"Using hardcoded default value of '%1'")
185 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
204 const QString &lbase,
205 bool recursive,
bool onlyDirs)
208 QString base = lbase;
214 if (base.split(
"/").size() > 20)
216 LOG(VB_GENERAL, LOG_ERR,
LOC +
"GetDirFileList(), 20 levels deep, "
217 "possible directory loop detected.");
227 d.entryList(QDir::Dirs|QDir::NoDotAndDotDot|QDir::Readable);
229 for (
const auto&
p : std::as_const(list))
231 LOG(VB_FILE, LOG_DEBUG,
LOC +
232 QString(
"GetDirFileList: Dir: %1/%2").arg(base,
p));
235 files.append(base +
p);
243 QStringList list =
d.entryList(QDir::Files|QDir::Readable);
244 for (
const auto&
p : std::as_const(list))
246 LOG(VB_FILE, LOG_DEBUG,
LOC +
247 QString(
"GetDirFileList: File: %1%2").arg(base,
p));
249 files.append(base +
p);
262 for (
const auto& dir : std::as_const(
m_dirlist))
278 for (
const auto& dir : std::as_const(
m_dirlist))
296 if (Path.isEmpty() || Path ==
"/")
298 for (
const auto& dir : std::as_const(
m_dirlist))
299 files << QString(
"sgdir::%1").arg(dir);
304 for (
const auto& dir : std::as_const(
m_dirlist))
306 if (Path.startsWith(dir))
309 relPath.replace(dir,
"");
310 if (relPath.startsWith(
"/"))
311 relPath.replace(0,1,
"");
316 LOG(VB_FILE, LOG_INFO,
LOC +
317 QString(
"GetFileInfoList: Reading '%1'").arg(Path));
326 d.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
327 QFileInfoList list =
d.entryInfoList();
331 for (
const auto& entry : std::as_const(list))
333 if (entry.fileName() ==
"Thumbs.db")
339 tmp = QString(
"dir::%1::0").arg(entry.fileName());
342 tmp = QString(
"file::%1::%2::%3%4").arg(entry.fileName())
344 .arg(relPath, entry.fileName());
347 LOG(VB_FILE, LOG_DEBUG,
LOC +
348 QString(
"GetFileInfoList: (%1)").arg(
tmp));
357 LOG(VB_FILE, LOG_DEBUG,
LOC +
358 QString(
"FileExist: Testing for '%1'").arg(
filename));
364 for (
const auto & dir : std::as_const(
m_dirlist))
384 LOG(VB_FILE, LOG_DEBUG,
LOC +
385 QString(
"GetFileInfo: For '%1'") .arg(
filename));
388 bool searched =
false;
396 if ((searched && !
filename.isEmpty()) ||
402 if (fInfo.lastModified().isValid()) {
403 details << QString(
"%1").arg(fInfo.lastModified().toSecsSinceEpoch());
405 details << QString::number(UINT_MAX);
407 details << QString(
"%1").arg(fInfo.size());
426 LOG(VB_FILE, LOG_DEBUG,
427 QString(
"StorageGroup::GetRelativePathname(%1)").arg(
filename));
435 if (qurl.hasFragment())
436 result = qurl.path() +
"#" + qurl.fragment();
438 result = qurl.path();
440 if (result.startsWith(
"/"))
441 result.replace(0, 1,
"");
446 query.
prepare(
"SELECT DISTINCT dirname FROM storagegroup "
447 "ORDER BY dirname DESC;");
456 dirname = QString::fromUtf8(query.
value(0)
457 .toByteArray().constData());
461 result.replace(0, dirname.length(),
"");
462 if (result.startsWith(
"/"))
463 result.replace(0, 1,
"");
465 LOG(VB_FILE, LOG_DEBUG,
466 QString(
"StorageGroup::GetRelativePathname(%1) = '%2'")
473 query.
prepare(
"SELECT DISTINCT data FROM settings WHERE "
474 "value = 'VideoStartupDir';");
479 QString videostartupdir = query.
value(0).toString();
480 QStringList videodirs = videostartupdir.split(
':',
482 for (
const auto& directory : std::as_const(videodirs))
487 result.replace(0, directory.length(),
"");
488 if (result.startsWith(
"/"))
489 result.replace(0, 1,
"");
491 LOG(VB_FILE, LOG_DEBUG,
492 QString(
"StorageGroup::GetRelativePathname(%1) = '%2'")
506 const QString& directory = group;
510 result.replace(0, directory.length(),
"");
511 if (result.startsWith(
"/"))
512 result.replace(0, 1,
"");
514 LOG(VB_FILE, LOG_DEBUG,
515 QString(
"StorageGroup::GetRelativePathname(%1) = '%2'")
534 QStringList *dirlist)
542 QString sql =
"SELECT DISTINCT dirname "
543 "FROM storagegroup ";
545 if (!group.isEmpty())
547 sql.append(
"WHERE groupname = :GROUP");
549 sql.append(
" AND hostname = :HOSTNAME");
553 if (!group.isEmpty())
568 dirname = QString::fromUtf8(query.
value(0)
569 .toByteArray().constData());
570 dirname = dirname.trimmed();
571 if (dirname.endsWith(
"/"))
572 dirname.remove(dirname.length() - 1, 1);
574 if (
nullptr == dirlist)
576 (*dirlist) << dirname;
583 if (testdir.exists())
585 if (dirlist && !dirlist->contains(testdir.absolutePath()))
586 (*dirlist) << testdir.absolutePath();
596 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"FindFile: Searching for '%1'")
602 if (!recDir.isEmpty())
605 LOG(VB_FILE, LOG_INFO,
LOC +
606 QString(
"FindFile: Found '%1'") .arg(result));
610 LOG(VB_FILE, LOG_ERR,
LOC +
611 QString(
"FindFile: Unable to find '%1'!") .arg(
filename));
620 QFileInfo checkFile(
"");
626 LOG(VB_FILE, LOG_DEBUG,
LOC +
627 QString(
"FindFileDir: Checking '%1' for '%2'")
629 checkFile.setFile(testFile);
630 if (checkFile.exists() || checkFile.isSymLink())
641 checkFile.setFile(tmpFile);
642 if (checkFile.exists() || checkFile.isSymLink())
650 result = (tmpFile.isEmpty()) ? result : tmpFile;
657 result = (tmpFile.isEmpty()) ? result : tmpFile;
666 int64_t nextDirFree = 0;
668 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"FindNextDirMostFree: Starting"));
673 for (
const auto & dir : std::as_const(
m_dirlist))
677 LOG(VB_GENERAL, LOG_ERR,
LOC +
678 QString(
"FindNextDirMostFree: '%1' does not exist!").arg(dir));
683 LOG(VB_FILE, LOG_DEBUG,
LOC +
684 QString(
"FindNextDirMostFree: '%1' has %2 KiB free")
685 .arg(dir, QString::number(thisDirFree)));
687 if (thisDirFree > nextDirFree)
690 nextDirFree = thisDirFree;
694 if (nextDir.isEmpty())
696 LOG(VB_FILE, LOG_ERR,
LOC +
697 "FindNextDirMostFree: Unable to find any directories to use.");
701 LOG(VB_FILE, LOG_DEBUG,
LOC +
702 QString(
"FindNextDirMostFree: Using '%1'").arg(nextDir));
714 query.
prepare(
"SELECT groupname, dirname "
716 "WHERE hostname = :HOSTNAME;");
724 LOG(VB_FILE, LOG_DEBUG,
LOC +
725 "CheckAllStorageGroupDirs(): Checking All Storage Group directories");
735 dirname = QString::fromUtf8(query.
value(1)
736 .toByteArray().constData());
737 dirname = dirname.trimmed();
739 LOG(VB_FILE, LOG_DEBUG,
LOC +
740 QString(
"Checking directory '%1' in group '%2'.")
743 testDir.setPath(dirname);
744 if (!testDir.exists())
746 LOG(VB_FILE, LOG_WARNING,
LOC +
747 QString(
"Group '%1' references directory '%2' but this "
748 "directory does not exist. This directory "
749 "will not be used on this server.")
754 testFile.setFileName(dirname +
"/.test");
755 if (testFile.open(QIODevice::WriteOnly))
759 LOG(VB_GENERAL, LOG_ERR,
LOC +
760 QString(
"Group '%1' wants to use directory '%2', but "
761 "this directory is not writeable.")
774 QString sql =
"SELECT DISTINCT groupname "
776 "WHERE groupname NOT IN (";
778 sql.append(QString(
" '%1',").arg(group));
779 sql = sql.left(sql.length() - 1);
787 groups += query.
value(0).toString();
804 addHost =
" AND hostname = :HOSTNAME";
808 QString sql = QString(
"SELECT dirname,hostname "
810 "WHERE groupname = :GROUPNAME %1").arg(addHost);
813 query.
bindValue(
":GROUPNAME", groupname);
826 dirname = QString::fromUtf8(query.
value(0)
827 .toByteArray().constData());
846 const QString &host,
const QString &sgroup)
848 QString tmpGroup = sgroup;
849 QString groupKey = QString(
"%1:%2").arg(sgroup, host);
865 LOG(VB_FILE, LOG_DEBUG,
866 QString(
"GetGroupToUse(): "
867 "falling back to Videos Storage Group for host %1 "
868 "since it does not have a %2 Storage Group.")
889 QString sgroup,
bool fileNamesOnly)
895 if (sgroup.isEmpty())
898 *list <<
"QUERY_SG_GETFILELIST";
902 *list << QString::number(static_cast<int>(fileNamesOnly));
913 QString ann = QString(
"ANN Playback %1 0")
917 bool mismatch =
false;
920 addr, port, ann, &mismatch);
int64_t getFreeSpace() const
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 isActive(void) 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.
QString GetHostName(void)
MythSocket * ConnectCommandSocket(const QString &hostname, int port, const QString &announcement, bool *proto_mismatch=nullptr, int maxConnTry=-1, std::chrono::milliseconds setup_timeout=-1ms)
QString GetSetting(const QString &key, const QString &defaultval="")
int GetBackendServerPort(void)
Returns the locally defined backend control port.
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
QString GetBackendServerIP(void)
Returns the IP address of the locally defined backend IP.
bool IsMasterBackend(void)
is this the actual MBE process
static void DBError(const QString &where, const MSqlQuery &query)
Class for communcating between myth backends and frontends.
bool SendReceiveStringList(QStringList &list, uint min_reply_length=0, std::chrono::milliseconds timeoutMS=kLongTimeout)
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
QStringList GetDirFileList(const QString &dir, const QString &base, bool recursive=false, bool onlyDirs=false)
QStringList GetDirList(void) const
QString FindFileDir(const QString &filename)
void Init(const QString &group="Default", const QString &hostname="", bool allowFallback=true)
Initilizes the groupname, hostname, and dirlist.
QString GetFirstDir(bool appendSlash=false) const
static QStringList getRecordingsGroups(void)
static QStringList getGroupDirs(const QString &groupname, const QString &host)
bool FileExists(const QString &filename)
static bool remoteGetFileList(const QString &host, const QString &path, QStringList *list, QString sgroup, bool fileNamesOnly=false)
static const char * kDefaultStorageDir
static bool FindDirs(const QString &group="Default", const QString &hostname="", QStringList *dirlist=nullptr)
Finds and and optionally initialize a directory list associated with a Storage Group.
static QMap< QString, QString > m_builtinGroups
static QString GetGroupToUse(const QString &host, const QString &sgroup)
static QHash< QString, QString > s_groupToUseCache
static void ClearGroupToUseCache(void)
QStringList GetFileInfo(const QString &filename)
QString FindFile(const QString &filename)
static const QStringList kSpecialGroups
static void CheckAllStorageGroupDirs(void)
StorageGroup(QString group="", QString hostname="", bool allowFallback=true)
StorageGroup constructor.
static QMutex m_staticInitLock
static void StaticInit(void)
static QMutex s_groupToUseLock
QStringList GetFileInfoList(const QString &Path)
static QString generate_file_url(const QString &storage_group, const QString &host, const QString &path)
QString FindNextDirMostFree(void)
QStringList GetFileList(const QString &Path, bool recursive=false)
static bool m_staticInitDone
static QString GetRelativePathname(const QString &filename)
Returns the relative pathname of a file by comparing the filename against all Storage Group directori...
static const iso6937table * d
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)