12 #define LOC QString("SG(%1): ").arg(m_groupname)
23 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"LiveTV")
25 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"DB Backups")
26 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Videos")
27 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Trailers")
28 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Coverart")
29 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Fanart")
30 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Screenshots")
31 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Banners")
32 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Photographs")
33 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"Music")
34 << QT_TRANSLATE_NOOP(
"(StorageGroups)",
"MusicArt")
50 m_allowFallback(allowFallback)
54 if (qEnvironmentVariableIsSet(
"MYTHTV_NOSGFALLBACK"))
78 QDir qdir(it.value());
80 qdir.mkpath(it.value());
84 LOG(VB_GENERAL, LOG_ERR,
85 QString(
"SG() Error: Could not create builtin"
86 "Storage Group directory '%1' for '%2'")
87 .arg(it.value(), it.key()));
107 const bool allowFallback)
121 if (!testdir.exists())
124 if (testdir.exists())
126 m_dirlist.prepend(testdir.absolutePath());
134 LOG(VB_FILE, LOG_NOTICE,
LOC +
135 QString(
"Unable to find any directories for the local "
136 "storage group '%1' on '%2', trying directories on "
137 "all hosts!").arg(group,
hostname));
146 LOG(VB_FILE, LOG_NOTICE,
LOC +
147 QString(
"Unable to find storage group '%1', trying "
148 "'Default' group!").arg(group));
156 LOG(VB_FILE, LOG_NOTICE,
LOC +
157 QString(
"Unable to find any directories for the local "
158 "Default storage group on '%1', trying directories "
159 "in all Default groups!").arg(
hostname));
171 QString msg =
"Unable to find any Storage Group Directories. ";
175 msg += QString(
"Using old 'RecordFilePrefix' value of '%1'")
181 msg += QString(
"Using hardcoded default value of '%1'")
184 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
203 const QString &lbase,
204 bool recursive,
bool onlyDirs)
207 QString base = lbase;
213 if (base.split(
"/").size() > 20)
215 LOG(VB_GENERAL, LOG_ERR,
LOC +
"GetDirFileList(), 20 levels deep, "
216 "possible directory loop detected.");
226 d.entryList(QDir::Dirs|QDir::NoDotAndDotDot|QDir::Readable);
228 for (
const auto&
p : qAsConst(list))
230 LOG(VB_FILE, LOG_DEBUG,
LOC +
231 QString(
"GetDirFileList: Dir: %1/%2").arg(base,
p));
234 files.append(base +
p);
242 QStringList list =
d.entryList(QDir::Files|QDir::Readable);
243 for (
const auto&
p : qAsConst(list))
245 LOG(VB_FILE, LOG_DEBUG,
LOC +
246 QString(
"GetDirFileList: File: %1%2").arg(base,
p));
248 files.append(base +
p);
261 for (
const auto& dir : qAsConst(
m_dirlist))
277 for (
const auto& dir : qAsConst(
m_dirlist))
295 if (Path.isEmpty() || Path ==
"/")
297 for (
const auto& dir : qAsConst(
m_dirlist))
298 files << QString(
"sgdir::%1").arg(dir);
303 for (
const auto& dir : qAsConst(
m_dirlist))
305 if (Path.startsWith(dir))
308 relPath.replace(dir,
"");
309 if (relPath.startsWith(
"/"))
310 relPath.replace(0,1,
"");
315 LOG(VB_FILE, LOG_INFO,
LOC +
316 QString(
"GetFileInfoList: Reading '%1'").arg(Path));
325 d.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
326 QFileInfoList list =
d.entryInfoList();
330 for (
const auto& entry : qAsConst(list))
332 if (entry.fileName() ==
"Thumbs.db")
338 tmp = QString(
"dir::%1::0").arg(entry.fileName());
341 tmp = QString(
"file::%1::%2::%3%4").arg(entry.fileName())
343 .arg(relPath, entry.fileName());
346 LOG(VB_FILE, LOG_DEBUG,
LOC +
347 QString(
"GetFileInfoList: (%1)").arg(
tmp));
356 LOG(VB_FILE, LOG_DEBUG,
LOC +
357 QString(
"FileExist: Testing for '%1'").arg(
filename));
363 for (
const auto & dir : qAsConst(
m_dirlist))
383 LOG(VB_FILE, LOG_DEBUG,
LOC +
384 QString(
"GetFileInfo: For '%1'") .arg(
filename));
387 bool searched =
false;
395 if ((searched && !
filename.isEmpty()) ||
401 if (fInfo.lastModified().isValid()) {
402 details << QString(
"%1").arg(fInfo.lastModified().toSecsSinceEpoch());
404 details << QString::number(UINT_MAX);
406 details << QString(
"%1").arg(fInfo.size());
425 LOG(VB_FILE, LOG_DEBUG,
426 QString(
"StorageGroup::GetRelativePathname(%1)").arg(
filename));
434 if (qurl.hasFragment())
435 result = qurl.path() +
"#" + qurl.fragment();
437 result = qurl.path();
439 if (result.startsWith(
"/"))
440 result.replace(0, 1,
"");
445 query.
prepare(
"SELECT DISTINCT dirname FROM storagegroup "
446 "ORDER BY dirname DESC;");
455 dirname = QString::fromUtf8(query.
value(0)
456 .toByteArray().constData());
460 result.replace(0, dirname.length(),
"");
461 if (result.startsWith(
"/"))
462 result.replace(0, 1,
"");
464 LOG(VB_FILE, LOG_DEBUG,
465 QString(
"StorageGroup::GetRelativePathname(%1) = '%2'")
472 query.
prepare(
"SELECT DISTINCT data FROM settings WHERE "
473 "value = 'VideoStartupDir';");
478 QString videostartupdir = query.
value(0).toString();
479 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
480 QStringList videodirs = videostartupdir.split(
':',
481 QString::SkipEmptyParts);
483 QStringList videodirs = videostartupdir.split(
':',
486 for (
const auto& directory : qAsConst(videodirs))
491 result.replace(0, directory.length(),
"");
492 if (result.startsWith(
"/"))
493 result.replace(0, 1,
"");
495 LOG(VB_FILE, LOG_DEBUG,
496 QString(
"StorageGroup::GetRelativePathname(%1) = '%2'")
510 const QString& directory = group;
514 result.replace(0, directory.length(),
"");
515 if (result.startsWith(
"/"))
516 result.replace(0, 1,
"");
518 LOG(VB_FILE, LOG_DEBUG,
519 QString(
"StorageGroup::GetRelativePathname(%1) = '%2'")
538 QStringList *dirlist)
546 QString sql =
"SELECT DISTINCT dirname "
547 "FROM storagegroup ";
549 if (!group.isEmpty())
551 sql.append(
"WHERE groupname = :GROUP");
553 sql.append(
" AND hostname = :HOSTNAME");
557 if (!group.isEmpty())
566 else if (query.
next())
573 dirname = QString::fromUtf8(query.
value(0)
574 .toByteArray().constData());
575 dirname = dirname.trimmed();
576 if (dirname.endsWith(
"/"))
577 dirname.remove(dirname.length() - 1, 1);
580 (*dirlist) << dirname;
584 while (query.
next());
591 if (testdir.exists())
593 if (dirlist && !dirlist->contains(testdir.absolutePath()))
594 (*dirlist) << testdir.absolutePath();
604 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"FindFile: Searching for '%1'")
610 if (!recDir.isEmpty())
613 LOG(VB_FILE, LOG_INFO,
LOC +
614 QString(
"FindFile: Found '%1'") .arg(result));
618 LOG(VB_FILE, LOG_ERR,
LOC +
619 QString(
"FindFile: Unable to find '%1'!") .arg(
filename));
628 QFileInfo checkFile(
"");
634 LOG(VB_FILE, LOG_DEBUG,
LOC +
635 QString(
"FindFileDir: Checking '%1' for '%2'")
637 checkFile.setFile(testFile);
638 if (checkFile.exists() || checkFile.isSymLink())
649 checkFile.setFile(tmpFile);
650 if (checkFile.exists() || checkFile.isSymLink())
658 result = (tmpFile.isEmpty()) ? result : tmpFile;
665 result = (tmpFile.isEmpty()) ? result : tmpFile;
674 int64_t nextDirFree = 0;
675 int64_t thisDirTotal = 0;
676 int64_t thisDirUsed = 0;
677 int64_t thisDirFree = 0;
679 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"FindNextDirMostFree: Starting"));
692 if (!checkDir.exists())
694 LOG(VB_GENERAL, LOG_ERR,
LOC +
695 QString(
"FindNextDirMostFree: '%1' does not exist!")
703 LOG(VB_FILE, LOG_DEBUG,
LOC +
704 QString(
"FindNextDirMostFree: '%1' has %2 KiB free")
705 .arg(
m_dirlist[curDir], QString::number(thisDirFree)));
707 if (thisDirFree > nextDirFree)
710 nextDirFree = thisDirFree;
715 if (nextDir.isEmpty())
717 LOG(VB_FILE, LOG_ERR,
LOC +
718 "FindNextDirMostFree: Unable to find any directories to use.");
722 LOG(VB_FILE, LOG_DEBUG,
LOC +
723 QString(
"FindNextDirMostFree: Using '%1'").arg(nextDir));
735 query.
prepare(
"SELECT groupname, dirname "
737 "WHERE hostname = :HOSTNAME;");
745 LOG(VB_FILE, LOG_DEBUG,
LOC +
746 "CheckAllStorageGroupDirs(): Checking All Storage Group directories");
756 dirname = QString::fromUtf8(query.
value(1)
757 .toByteArray().constData());
758 dirname = dirname.trimmed();
760 LOG(VB_FILE, LOG_DEBUG,
LOC +
761 QString(
"Checking directory '%1' in group '%2'.")
764 testDir.setPath(dirname);
765 if (!testDir.exists())
767 LOG(VB_FILE, LOG_WARNING,
LOC +
768 QString(
"Group '%1' references directory '%2' but this "
769 "directory does not exist. This directory "
770 "will not be used on this server.")
775 testFile.setFileName(dirname +
"/.test");
776 if (testFile.open(QIODevice::WriteOnly))
780 LOG(VB_GENERAL, LOG_ERR,
LOC +
781 QString(
"Group '%1' wants to use directory '%2', but "
782 "this directory is not writeable.")
795 QString sql =
"SELECT DISTINCT groupname "
797 "WHERE groupname NOT IN (";
799 sql.append(QString(
" '%1',").arg(group));
800 sql = sql.left(sql.length() - 1);
808 groups += query.
value(0).toString();
825 addHost =
" AND hostname = :HOSTNAME";
829 QString sql = QString(
"SELECT dirname,hostname "
831 "WHERE groupname = :GROUPNAME %1").arg(addHost);
834 query.
bindValue(
":GROUPNAME", groupname);
847 dirname = QString::fromUtf8(query.
value(0)
848 .toByteArray().constData());
867 const QString &host,
const QString &sgroup)
869 QString tmpGroup = sgroup;
870 QString groupKey = QString(
"%1:%2").arg(sgroup, host);
886 LOG(VB_FILE, LOG_DEBUG,
887 QString(
"GetGroupToUse(): "
888 "falling back to Videos Storage Group for host %1 "
889 "since it does not have a %2 Storage Group.")