15#include "libmythbase/mythconfig.h"
18#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
19#include <QtSystemDetection>
24#if CONFIG_SYSTEMD_NOTIFY
25#include <systemd/sd-daemon.h>
29#include <QCoreApplication>
33#include <QWaitCondition>
34#include <QWriteLocker>
36#include <QRegularExpression>
40#include <QNetworkInterface>
41#include <QNetworkProxy>
42#include <QHostAddress>
57#include "libmythbase/mythversion.h"
88static constexpr std::chrono::milliseconds
PRT_TIMEOUT { 10ms };
92#define LOC QString("MainServer: ")
93#define LOC_WARN QString("MainServer, Warning: ")
94#define LOC_ERR QString("MainServer, Error: ")
99 bool followLinks,
bool checkexists)
103 bool success1 =
true;
104 bool success2 =
true;
106 LOG(VB_FILE, LOG_INFO,
LOC +
107 QString(
"About to delete file: %1").arg(
filename));
111 if (finfo.isSymLink())
115 QFile target(linktext);
116 success1 = target.remove();
119 LOG(VB_GENERAL, LOG_ERR,
LOC +
120 QString(
"Error deleting '%1' -> '%2'")
125 if (!checkexists || checkFile.exists())
127 success2 = checkFile.remove();
130 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error deleting '%1': %2")
134 return success1 && success2;
199 QMutexLocker locker(&
m_lock);
209 m_wait.wait(locker.mutex(), left.count());
215 QMutexLocker locker(&
m_lock);
240 QMap<int, EncoderLink *> *_tvList,
242 m_encoderList(_tvList),
244 m_ismaster(master), m_threadPool(
"ProcessRequestPool"),
245 m_sched(
sched), m_expirer(_expirer)
267 bool v4IsSet = !config_v4.isNull();
272 bool v6IsSet = !config_v6.isNull();
274 if (v6IsSet && !listenAddrs.contains(config_v6))
275 LOG(VB_GENERAL, LOG_WARNING,
LOC +
276 "Unable to find IPv6 address to bind");
278 if (v4IsSet && !listenAddrs.contains(config_v4))
279 LOG(VB_GENERAL, LOG_WARNING,
LOC +
280 "Unable to find IPv4 address to bind");
282 if ((v4IsSet && !listenAddrs.contains(config_v4))
283 && (v6IsSet && !listenAddrs.contains(config_v6))
286 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to find either IPv4 or IPv6 "
287 "address we can bind to, exiting");
437 auto *ms =
new MythSocket(socketDescriptor,
this);
438 if (ms->IsConnected())
450 QCoreApplication::processEvents();
458 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"No data on sock %1")
472 QStringList listline;
475 if (!
pbs->ReadStringList(listline) || listline.empty())
478 LOG(VB_GENERAL, LOG_INFO,
"No data in ProcessRequestWork()");
483 else if (!bIsControl)
490 LOG(VB_GENERAL, LOG_INFO,
LOC +
"No data in ProcessRequestWork()");
494 QString line = listline[0];
496 line = line.simplified();
497 QStringList tokens = line.split(
' ', Qt::SkipEmptyParts);
498 QString command = tokens[0];
500 if (command ==
"MYTH_PROTO_VERSION")
502 if (tokens.size() < 2)
508 if (command ==
"ANN")
513 if (command ==
"DONE")
524 LOG(VB_GENERAL, LOG_ERR,
LOC +
"ProcessRequest unknown socket");
530 if (command ==
"QUERY_FILETRANSFER")
532 if (tokens.size() != 2)
537 else if (command ==
"QUERY_RECORDINGS")
539 if (tokens.size() != 2)
544 else if (command ==
"QUERY_RECORDING")
548 else if (command ==
"GO_TO_SLEEP")
552 else if (command ==
"QUERY_FREE_SPACE")
556 else if (command ==
"QUERY_FREE_SPACE_LIST")
560 else if (command ==
"QUERY_FREE_SPACE_SUMMARY")
564 else if (command ==
"QUERY_LOAD")
568 else if (command ==
"QUERY_UPTIME")
572 else if (command ==
"QUERY_HOSTNAME")
576 else if (command ==
"QUERY_MEMSTATS")
580 else if (command ==
"QUERY_TIME_ZONE")
584 else if (command ==
"QUERY_CHECKFILE")
588 else if (command ==
"QUERY_FILE_EXISTS")
590 if (listline.size() < 2)
595 else if (command ==
"QUERY_FINDFILE")
597 if (listline.size() < 4)
602 else if (command ==
"QUERY_FILE_HASH")
604 if (listline.size() < 3)
609 else if (command ==
"QUERY_GUIDEDATATHROUGH")
613 else if (command ==
"DELETE_FILE")
615 if (listline.size() < 3)
620 else if (command ==
"MOVE_FILE")
622 if (listline.size() < 4)
627 else if (command ==
"STOP_RECORDING")
631 else if (command ==
"CHECK_RECORDING")
635 else if (command ==
"DELETE_RECORDING")
637 if (3 <= tokens.size() && tokens.size() <= 5)
639 bool force = (tokens.size() >= 4) && (tokens[3] ==
"FORCE");
640 bool forget = (tokens.size() >= 5) && (tokens[4] ==
"FORGET");
648 else if (command ==
"FORCE_DELETE_RECORDING")
652 else if (command ==
"UNDELETE_RECORDING")
656 else if (command ==
"ADD_CHILD_INPUT")
661 LOG(VB_GENERAL, LOG_ERR,
LOC +
662 "ADD_CHILD_INPUT command received in master context");
663 reslist << QString(
"ERROR: Called in master context");
665 else if (tokens.size() != 2)
667 reslist <<
"ERROR: Bad ADD_CHILD_INPUT request";
675 reslist << QString(
"ERROR: Failed to add child input");
679 else if (command ==
"RESCHEDULE_RECORDINGS")
681 listline.pop_front();
684 else if (command ==
"FORGET_RECORDING")
688 else if (command ==
"QUERY_GETALLPENDING")
690 if (tokens.size() == 1)
692 else if (tokens.size() == 2)
697 else if (command ==
"QUERY_GETALLSCHEDULED")
701 else if (command ==
"QUERY_GETCONFLICTING")
705 else if (command ==
"QUERY_GETEXPIRING")
709 else if (command ==
"QUERY_SG_GETFILELIST")
713 else if (command ==
"QUERY_SG_FILEQUERY")
717 else if (command ==
"GET_FREE_INPUT_INFO")
719 if (tokens.size() != 2)
724 else if (command ==
"QUERY_RECORDER")
726 if (tokens.size() != 2)
731 else if ((command ==
"QUERY_RECORDING_DEVICE") ||
732 (command ==
"QUERY_RECORDING_DEVICES"))
736 else if (command ==
"SET_NEXT_LIVETV_DIR")
738 if (tokens.size() != 3)
743 else if (command ==
"SET_CHANNEL_INFO")
747 else if (command ==
"QUERY_REMOTEENCODER")
749 if (tokens.size() != 2)
754 else if (command ==
"GET_RECORDER_FROM_NUM")
758 else if (command ==
"GET_RECORDER_NUM")
762 else if (command ==
"QUERY_GENPIXMAP2")
766 else if (command ==
"QUERY_PIXMAP_LASTMODIFIED")
770 else if (command ==
"QUERY_PIXMAP_GET_IF_MODIFIED")
774 else if (command ==
"QUERY_ISRECORDING")
778 else if (command ==
"MESSAGE")
780 if ((listline.size() >= 2) && (listline[1].startsWith(
"SET_VERBOSE")))
782 else if ((listline.size() >= 2) &&
783 (listline[1].startsWith(
"SET_LOG_LEVEL")))
788 else if (command ==
"FILL_PROGRAM_INFO")
792 else if (command ==
"LOCK_TUNER")
794 if (tokens.size() == 1)
796 else if (tokens.size() == 2)
801 else if (command ==
"FREE_TUNER")
803 if (tokens.size() != 2)
808 else if (command ==
"QUERY_ACTIVE_BACKENDS")
812 else if (command ==
"QUERY_IS_ACTIVE_BACKEND")
814 if (tokens.size() != 1)
819 else if (command ==
"QUERY_COMMBREAK")
821 if (tokens.size() != 3)
826 else if (command ==
"QUERY_CUTLIST")
828 if (tokens.size() != 3)
833 else if (command ==
"QUERY_BOOKMARK")
835 if (tokens.size() != 3)
840 else if (command ==
"SET_BOOKMARK")
842 if (tokens.size() != 4)
847 else if (command ==
"QUERY_SETTING")
849 if (tokens.size() != 3)
854 else if (command ==
"SET_SETTING")
856 if (tokens.size() != 4)
861 else if (command ==
"SCAN_VIDEOS")
865 else if (command ==
"SCAN_MUSIC")
869 else if (command ==
"MUSIC_TAG_UPDATE_VOLATILE")
871 if (listline.size() != 6)
876 else if (command ==
"MUSIC_CALC_TRACK_LENGTH")
878 if (listline.size() != 3)
883 else if (command ==
"MUSIC_TAG_UPDATE_METADATA")
885 if (listline.size() != 3)
890 else if (command ==
"MUSIC_FIND_ALBUMART")
892 if (listline.size() != 4)
897 else if (command ==
"MUSIC_TAG_GETIMAGE")
899 if (listline.size() < 4)
904 else if (command ==
"MUSIC_TAG_ADDIMAGE")
906 if (listline.size() < 5)
911 else if (command ==
"MUSIC_TAG_REMOVEIMAGE")
913 if (listline.size() < 4)
918 else if (command ==
"MUSIC_TAG_CHANGEIMAGE")
920 if (listline.size() < 5)
925 else if (command ==
"MUSIC_LYRICS_FIND")
927 if (listline.size() < 3)
932 else if (command ==
"MUSIC_LYRICS_GETGRABBERS")
936 else if (command ==
"MUSIC_LYRICS_SAVE")
938 if (listline.size() < 3)
943 else if (command ==
"IMAGE_SCAN")
946 QStringList reply = (listline.size() == 2)
948 : QStringList(
"ERROR") <<
"Bad: " << listline;
952 else if (command ==
"IMAGE_COPY")
955 QStringList reply = (listline.size() >= 2)
957 : QStringList(
"ERROR") <<
"Bad: " << listline;
961 else if (command ==
"IMAGE_MOVE")
964 QStringList reply = (listline.size() == 4)
966 HandleDbMove(listline[1], listline[2], listline[3])
967 : QStringList(
"ERROR") <<
"Bad: " << listline;
971 else if (command ==
"IMAGE_DELETE")
974 QStringList reply = (listline.size() == 2)
976 : QStringList(
"ERROR") <<
"Bad: " << listline;
980 else if (command ==
"IMAGE_HIDE")
983 QStringList reply = (listline.size() == 3)
985 HandleHide(listline[1].toInt() != 0, listline[2])
986 : QStringList(
"ERROR") <<
"Bad: " << listline;
990 else if (command ==
"IMAGE_TRANSFORM")
993 QStringList reply = (listline.size() == 3)
995 HandleTransform(listline[1].toInt(), listline[2])
996 : QStringList(
"ERROR") <<
"Bad: " << listline;
1000 else if (command ==
"IMAGE_RENAME")
1003 QStringList reply = (listline.size() == 3)
1005 : QStringList(
"ERROR") <<
"Bad: " << listline;
1009 else if (command ==
"IMAGE_CREATE_DIRS")
1012 QStringList reply = (listline.size() >= 4)
1014 HandleDirs(listline[1], listline[2].toInt() != 0, listline.mid(3))
1015 : QStringList(
"ERROR") <<
"Bad: " << listline;
1019 else if (command ==
"IMAGE_COVER")
1022 QStringList reply = (listline.size() == 3)
1024 HandleCover(listline[1].toInt(), listline[2].toInt())
1025 : QStringList(
"ERROR") <<
"Bad: " << listline;
1029 else if (command ==
"IMAGE_IGNORE")
1032 QStringList reply = (listline.size() == 2)
1034 : QStringList(
"ERROR") <<
"Bad: " << listline;
1038 else if (command ==
"ALLOW_SHUTDOWN")
1040 if (tokens.size() != 1)
1045 else if (command ==
"BLOCK_SHUTDOWN")
1047 if (tokens.size() != 1)
1052 else if (command ==
"SHUTDOWN_NOW")
1054 if (tokens.size() != 1)
1061 if (listline.size() >= 2)
1062 halt_cmd = listline[1];
1064 if (!halt_cmd.isEmpty())
1066 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
1067 "Going down now as of Mainserver request!");
1076 else if (command ==
"BACKEND_MESSAGE")
1078 const QString& message = listline[1];
1079 QStringList extra( listline[2] );
1080 for (
int i = 3; i < listline.size(); i++)
1081 extra << listline[i];
1085 else if ((command ==
"DOWNLOAD_FILE") ||
1086 (command ==
"DOWNLOAD_FILE_NOW"))
1088 if (listline.size() != 4)
1093 else if (command ==
"REFRESH_BACKEND")
1095 LOG(VB_GENERAL, LOG_INFO ,
LOC +
"Reloading backend settings");
1098 else if (command ==
"OK")
1100 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Got 'OK' out of sequence.");
1102 else if (command ==
"UNKNOWN_COMMAND")
1104 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Got 'UNKNOWN_COMMAND' out of sequence.");
1108 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unknown command: " + command);
1112 QStringList strlist;
1113 strlist <<
"UNKNOWN_COMMAND";
1126 QStringList broadcast;
1127 QSet<QString> receivers;
1145 auto *me =
dynamic_cast<MythEvent *
>(e);
1149 QString message = me->
Message();
1151 if ((message ==
"PREVIEW_SUCCESS" || message ==
"PREVIEW_QUEUED") &&
1152 me->ExtraDataCount() >= 5)
1155 uint recordingID = me->ExtraData(0).toUInt();
1156 const QString&
filename = me->ExtraData(1);
1157 const QString& msg = me->ExtraData(2);
1158 const QString& datetime = me->ExtraData(3);
1160 if (message ==
"PREVIEW_QUEUED")
1162 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1163 QString(
"Preview Queued: '%1' '%2'")
1169 ok = ok &&
file.open(QIODevice::ReadOnly);
1173 QByteArray data =
file.readAll();
1174 QStringList extra(
"OK");
1175 extra.push_back(QString::number(recordingID));
1176 extra.push_back(msg);
1177 extra.push_back(datetime);
1178 extra.push_back(QString::number(data.size()));
1179#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1180 quint16 checksum = qChecksum(data.constData(), data.size());
1182 quint16 checksum = qChecksum(data);
1184 extra.push_back(QString::number(checksum));
1185 extra.push_back(QString(data.toBase64()));
1187 for (
uint i = 4 ; i < (
uint) me->ExtraDataCount(); i++)
1189 const QString& token = me->ExtraData(i);
1190 extra.push_back(token);
1194 receivers.insert(*it);
1199 if (receivers.empty())
1201 LOG(VB_GENERAL, LOG_ERR,
LOC +
1202 "PREVIEW_SUCCESS but no receivers.");
1206 broadcast.push_back(
"BACKEND_MESSAGE");
1207 broadcast.push_back(
"GENERATED_PIXMAP");
1212 message =
"PREVIEW_FAILED";
1218 if (message ==
"PREVIEW_FAILED" && me->ExtraDataCount() >= 5)
1220 const QString& pginfokey = me->ExtraData(0);
1221 const QString& msg = me->ExtraData(2);
1223 QStringList extra(
"ERROR");
1224 extra.push_back(pginfokey);
1225 extra.push_back(msg);
1226 for (
uint i = 4 ; i < (
uint) me->ExtraDataCount(); i++)
1228 const QString& token = me->ExtraData(i);
1229 extra.push_back(token);
1233 receivers.insert(*it);
1238 if (receivers.empty())
1240 LOG(VB_GENERAL, LOG_ERR,
LOC +
1241 "PREVIEW_FAILED but no receivers.");
1245 broadcast.push_back(
"BACKEND_MESSAGE");
1246 broadcast.push_back(
"GENERATED_PIXMAP");
1250 if (me->Message().startsWith(
"AUTO_EXPIRE"))
1252 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1253 if (tokens.size() != 3)
1255 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad AUTO_EXPIRE message");
1279 QString msg = QString(
"Cannot find program info for '%1', "
1280 "while attempting to Auto-Expire.")
1281 .arg(me->Message());
1282 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
1288 if (me->Message().startsWith(
"QUERY_NEXT_LIVETV_DIR") &&
m_sched)
1290 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1291 if (tokens.size() != 2)
1293 LOG(VB_GENERAL, LOG_ERR,
LOC +
1294 QString(
"Bad %1 message").arg(tokens[0]));
1302 if (me->Message().startsWith(
"STOP_RECORDING"))
1304 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1305 if (tokens.size() < 3 || tokens.size() > 3)
1307 LOG(VB_GENERAL, LOG_ERR,
LOC +
1308 QString(
"Bad STOP_RECORDING message: %1")
1309 .arg(me->Message()));
1322 LOG(VB_GENERAL, LOG_ERR,
LOC +
1323 QString(
"Cannot find program info for '%1' while "
1324 "attempting to stop recording.").arg(me->Message()));
1330 if ((me->Message().startsWith(
"DELETE_RECORDING")) ||
1331 (me->Message().startsWith(
"FORCE_DELETE_RECORDING")))
1333 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1334 if (tokens.size() < 3 || tokens.size() > 5)
1336 LOG(VB_GENERAL, LOG_ERR,
LOC +
1337 QString(
"Bad %1 message").arg(tokens[0]));
1341 bool force = (tokens.size() >= 4) && (tokens[3] ==
"FORCE");
1342 bool forget = (tokens.size() >= 5) && (tokens[4] ==
"FORGET");
1349 if (tokens[0] ==
"FORCE_DELETE_RECORDING")
1356 LOG(VB_GENERAL, LOG_ERR,
LOC +
1357 QString(
"Cannot find program info for '%1' while "
1358 "attempting to delete.").arg(me->Message()));
1364 if (me->Message().startsWith(
"UNDELETE_RECORDING"))
1366 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1367 if (tokens.size() < 3 || tokens.size() > 3)
1369 LOG(VB_GENERAL, LOG_ERR,
LOC +
1370 QString(
"Bad UNDELETE_RECORDING message: %1")
1371 .arg(me->Message()));
1384 LOG(VB_GENERAL, LOG_ERR,
LOC +
1385 QString(
"Cannot find program info for '%1' while "
1386 "attempting to undelete.").arg(me->Message()));
1392 if (me->Message().startsWith(
"ADD_CHILD_INPUT"))
1394 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1397 LOG(VB_GENERAL, LOG_ERR,
LOC +
1398 "ADD_CHILD_INPUT event received in slave context");
1400 else if (tokens.size() != 2)
1402 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad ADD_CHILD_INPUT message");
1411 if (me->Message().startsWith(
"RESCHEDULE_RECORDINGS") &&
m_sched)
1413 const QStringList& request = me->ExtraDataList();
1418 if (me->Message().startsWith(
"SCHEDULER_ADD_RECORDING") &&
m_sched)
1423 LOG(VB_GENERAL, LOG_ERR,
LOC +
1424 "Bad SCHEDULER_ADD_RECORDING message");
1432 if (me->Message().startsWith(
"UPDATE_RECORDING_STATUS") &&
m_sched)
1434 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1435 if (tokens.size() != 6)
1437 LOG(VB_GENERAL, LOG_ERR,
LOC +
1438 "Bad UPDATE_RECORDING_STATUS message");
1442 uint cardid = tokens[1].toUInt();
1443 uint chanid = tokens[2].toUInt();
1448 recstatus, recendts);
1454 if (me->Message().startsWith(
"LIVETV_EXITED"))
1456 const QString& chainid = me->ExtraData();
1464 if (me->Message() ==
"CLEAR_SETTINGS_CACHE")
1467 if (me->Message().startsWith(
"RESET_IDLETIME") &&
m_sched)
1470 if (me->Message() ==
"LOCAL_RECONNECT_TO_MASTER")
1473 if (me->Message() ==
"LOCAL_SLAVE_BACKEND_ENCODERS_OFFLINE")
1476 if (me->Message().startsWith(
"LOCAL_"))
1479 if (me->Message() ==
"CREATE_THUMBNAILS")
1482 if (me->Message() ==
"IMAGE_GET_METADATA")
1485 std::unique_ptr<MythEvent> mod_me {
nullptr};
1486 if (me->Message().startsWith(
"MASTER_UPDATE_REC_INFO"))
1488 QStringList tokens = me->Message().simplified().split(
" ");
1489 uint recordedid = 0;
1490 if (tokens.size() >= 2)
1491 recordedid = tokens[1].toUInt();
1492 if (recordedid == 0)
1506 mod_me = std::make_unique<MythEvent>(
"RECORDING_LIST_CHANGE UPDATE", list);
1514 if (me->Message().startsWith(
"DOWNLOAD_FILE"))
1516 QStringList extraDataList = me->ExtraDataList();
1517 QString localFile = extraDataList[1];
1518 QFile
file(localFile);
1519 QStringList tokens = me->Message().simplified().split(
" ");
1527 if ((tokens.size() >= 2) && (tokens[1] ==
"FINISHED"))
1530 mod_me = std::make_unique<MythEvent>(me->Message(), extraDataList);
1533 if (broadcast.empty())
1535 broadcast.push_back(
"BACKEND_MESSAGE");
1536 if (mod_me !=
nullptr)
1538 broadcast.push_back(mod_me->Message());
1539 broadcast += mod_me->ExtraDataList();
1543 broadcast.push_back(me->Message());
1544 broadcast += me->ExtraDataList();
1549 if (!broadcast.empty())
1552 std::vector<PlaybackSock *> localPBSList;
1557 localPBSList.push_back(
pbs);
1561 bool sendGlobal =
false;
1562 if (
m_ismaster && broadcast[1].startsWith(
"GLOBAL_"))
1564 broadcast[1].replace(
"GLOBAL_",
"LOCAL_");
1565 MythEvent me(broadcast[1], broadcast[2]);
1571 QSet<PlaybackSock*> sentSet;
1573 bool isSystemEvent = broadcast[1].startsWith(
"SYSTEM_EVENT ");
1576 std::vector<PlaybackSock*>::const_iterator iter;
1577 for (iter = localPBSList.begin(); iter != localPBSList.end(); ++iter)
1581 if (sentSet.contains(
pbs) ||
pbs->IsDisconnected())
1584 if (!receivers.empty() && !receivers.contains(
pbs->getHostname()))
1587 sentSet.insert(
pbs);
1589 bool reallysendit =
false;
1591 if (broadcast[1] ==
"CLEAR_SETTINGS_CACHE")
1594 (
pbs->isSlaveBackend() ||
pbs->wantsEvents()))
1595 reallysendit =
true;
1597 else if (sendGlobal)
1599 if (
pbs->isSlaveBackend())
1600 reallysendit =
true;
1602 else if (
pbs->wantsEvents())
1604 reallysendit =
true;
1611 if (!
pbs->wantsSystemEvents())
1615 if (!
pbs->wantsOnlySystemEvents())
1617 if (sentSetSystemEvent.contains(
pbs->getHostname()))
1620 sentSetSystemEvent <<
pbs->getHostname();
1623 else if (
pbs->wantsOnlySystemEvents())
1635 for (iter = localPBSList.begin(); iter != localPBSList.end(); ++iter)
1653 QStringList retlist;
1654 const QString&
version = slist[1];
1655 if (
version != MYTH_PROTO_VERSION)
1657 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1658 "MainServer::HandleVersion - Client speaks protocol version " +
1659 version +
" but we speak " + MYTH_PROTO_VERSION +
'!');
1660 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1666 if (slist.size() < 3)
1668 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1669 "MainServer::HandleVersion - Client did not pass protocol "
1670 "token. Refusing connection!");
1671 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1677 const QString& token = slist[2];
1678 if (token != QString::fromUtf8(MYTH_PROTO_TOKEN))
1680 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1681 QString(
"MainServer::HandleVersion - Client sent incorrect "
1682 "protocol token \"%1\" for protocol version. Refusing "
1683 "connection!").arg(token));
1684 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1690 retlist <<
"ACCEPT" << MYTH_PROTO_VERSION;
1719 QStringList retlist(
"OK" );
1720 QStringList errlist(
"ERROR" );
1722 if (commands.size() < 3 || commands.size() > 6)
1725 if (commands.size() == 2)
1726 info = QString(
" %1").arg(commands[1]);
1728 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Received malformed ANN%1 query")
1731 errlist <<
"malformed_ann_query";
1739 if (
pbs->getSocket() == socket)
1741 LOG(VB_GENERAL, LOG_WARNING,
LOC +
1742 QString(
"Client %1 is trying to announce a socket "
1752 if (commands[1] ==
"Playback" || commands[1] ==
"Monitor" ||
1753 commands[1] ==
"Frontend")
1755 if (commands.size() < 4)
1757 LOG(VB_GENERAL, LOG_ERR,
LOC +
1758 QString(
"Received malformed ANN %1 query")
1761 errlist <<
"malformed_ann_query";
1778 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"MainServer::ANN %1")
1780 LOG(VB_GENERAL, LOG_INFO,
LOC +
1781 QString(
"adding: %1(%2) as a client (events: %3)")
1783 .arg(quintptr(socket),0,16)
1785 pbs->setBlockShutdown((commands[1] ==
"Playback") ||
1786 (commands[1] ==
"Frontend"));
1788 if (commands[1] ==
"Frontend")
1790 pbs->SetAsFrontend();
1792 frontend->m_name = commands[2];
1807 else if (commands[1] ==
"MediaServer")
1809 if (commands.size() < 3)
1811 LOG(VB_GENERAL, LOG_ERR,
LOC +
1812 "Received malformed ANN MediaServer query");
1813 errlist <<
"malformed_ann_query";
1822 pbs->setAsMediaServer();
1823 pbs->setBlockShutdown(
false);
1828 QString(
"CLIENT_CONNECTED HOSTNAME %1").arg(commands[2]));
1830 else if (commands[1] ==
"SlaveBackend")
1832 if (commands.size() < 4)
1834 LOG(VB_GENERAL, LOG_ERR,
LOC +
1835 QString(
"Received malformed ANN %1 query")
1837 errlist <<
"malformed_ann_query";
1849 LOG(VB_GENERAL, LOG_INFO,
LOC +
1850 QString(
"adding: %1 as a slave backend server")
1852 pbs->setAsSlaveBackend();
1853 pbs->setIP(commands[3]);
1858 QStringList::const_iterator sit = slist.
cbegin()+1;
1859 while (sit != slist.cend())
1862 if (!recinfo->GetChanID())
1872 bool wasAsleep =
true;
1876 if (elink->GetHostName() == commands[2])
1878 if (! (elink->IsWaking() || elink->IsAsleep()))
1880 elink->SetSocket(
pbs);
1888 QString message = QString(
"LOCAL_SLAVE_BACKEND_ONLINE %2")
1893 pbs->setBlockShutdown(
false);
1898 QString(
"SLAVE_CONNECTED HOSTNAME %1").arg(commands[2]));
1900 else if (commands[1] ==
"FileTransfer")
1902 if (slist.size() < 3)
1904 LOG(VB_GENERAL, LOG_ERR,
LOC +
1905 "Received malformed FileTransfer command");
1906 errlist <<
"malformed_filetransfer_command";
1911 LOG(VB_NETWORK, LOG_INFO,
LOC +
1912 "MainServer::HandleAnnounce FileTransfer");
1913 LOG(VB_NETWORK, LOG_INFO,
LOC +
1914 QString(
"adding: %1 as a remote file transfer") .arg(commands[2]));
1915 QStringList::const_iterator it = slist.cbegin();
1916 QString path = *(++it);
1917 QString wantgroup = *(++it);
1919 QStringList checkfiles;
1921 for (++it; it != slist.cend(); ++it)
1925 bool writemode =
false;
1926 bool usereadahead =
true;
1927 std::chrono::milliseconds timeout_ms = 2s;
1928 if (commands.size() > 3)
1929 writemode = (commands[3].toInt() != 0);
1931 if (commands.size() > 4)
1932 usereadahead = (commands[4].toInt() != 0);
1934 if (commands.size() > 5)
1935 timeout_ms = std::chrono::milliseconds(commands[5].toInt());
1939 if (wantgroup.isEmpty())
1940 wantgroup =
"Default";
1946 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to determine directory "
1947 "to write to in FileTransfer write command");
1948 errlist <<
"filetransfer_directory_not_found";
1955 LOG(VB_GENERAL, LOG_ERR,
LOC +
1956 QString(
"FileTransfer write filename is empty in path '%1'.")
1958 errlist <<
"filetransfer_filename_empty";
1963 if ((path.contains(
"/../")) ||
1964 (path.startsWith(
"../")))
1966 LOG(VB_GENERAL, LOG_ERR,
LOC +
1967 QString(
"FileTransfer write filename '%1' does not pass "
1968 "sanity checks.") .arg(path));
1969 errlist <<
"filetransfer_filename_dangerous";
1983 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Empty filename, cowardly aborting!");
1984 errlist <<
"filetransfer_filename_empty";
1993 LOG(VB_GENERAL, LOG_ERR,
LOC +
1994 QString(
"FileTransfer filename '%1' is actually a directory, "
1995 "cannot transfer.") .arg(
filename));
1996 errlist <<
"filetransfer_filename_is_a_directory";
2003 QString dirPath = finfo.absolutePath();
2007 if (!qdir.mkpath(dirPath))
2009 LOG(VB_GENERAL, LOG_ERR,
LOC +
2010 QString(
"FileTransfer filename '%1' is in a "
2011 "subdirectory which does not exist, and can "
2012 "not be created.") .arg(
filename));
2013 errlist <<
"filetransfer_unable_to_create_subdirectory";
2033 LOG(VB_GENERAL, LOG_ERR,
LOC +
2034 QString(
"Can't open %1").arg(
filename));
2035 errlist <<
"filetransfer_unable_to_open_file";
2042 LOG(VB_GENERAL, LOG_INFO,
LOC +
2043 QString(
"adding: %1(%2) as a file transfer")
2045 .arg(quintptr(socket),0,16));
2055 if (!checkfiles.empty())
2058 QDir dir = fi.absoluteDir();
2059 for (
const auto &
file : std::as_const(checkfiles))
2061 if (dir.exists(
file) &&
2062 (
file.endsWith(
".srt") ||
2095 QStringList strList(
"ERROR");
2110 bool do_write =
false;
2125 LOG(VB_GENERAL, LOG_ERR,
LOC +
2126 "SendResponse: Unable to write to client socket, as it's no "
2142 QString playbackhost =
pbs->getHostname();
2144 QMap<QString,ProgramInfo*> recMap;
2149 QMap<QString,bool> isJobRunning =
2155 if ((
type ==
"Ascending") || (
type ==
"Play"))
2157 else if ((
type ==
"Descending") || (
type ==
"Delete"))
2162 destination, (
type ==
"Recording"),
2163 inUseMap, isJobRunning, recMap, sort);
2165 QMap<QString,ProgramInfo*>::iterator mit = recMap.begin();
2166 for (; mit != recMap.end(); mit = recMap.erase(mit))
2169 QStringList outputlist(QString::number(destination.
size()));
2170 QMap<QString, int> backendPortMap;
2174 for (
auto* proginfo : destination)
2185 proginfo->GetBasename()));
2186 if (!proginfo->GetFilesize())
2189 if (tmpURL.startsWith(
'/'))
2191 QFile checkFile(tmpURL);
2192 if (!tmpURL.isEmpty() && checkFile.exists())
2194 proginfo->SetFilesize(checkFile.size());
2195 if (proginfo->GetRecordingEndTime() <
2198 proginfo->SaveFilesize(proginfo->GetFilesize());
2207 if (proginfo->GetPathname().isEmpty())
2209 LOG(VB_GENERAL, LOG_ERR,
LOC +
2210 QString(
"HandleQueryRecordings() "
2211 "Couldn't find backend for:\n\t\t\t%1")
2214 proginfo->SetFilesize(0);
2215 proginfo->SetPathname(
"file not found");
2220 if (!proginfo->GetFilesize())
2224 LOG(VB_GENERAL, LOG_ERR,
LOC +
2225 "MainServer::HandleQueryRecordings()"
2226 "\n\t\t\tCould not fill program info "
2231 if (proginfo->GetRecordingEndTime() <
2234 proginfo->SaveFilesize(proginfo->GetFilesize());
2243 if (!backendPortMap.contains(
hostname))
2255 proginfo->ToStringList(outputlist);
2268 if (slist.size() < 3)
2270 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad QUERY_RECORDING query");
2275 QString command = slist[1].toUpper();
2278 if (command ==
"BASENAME")
2282 else if (command ==
"TIMESLOT")
2284 if (slist.size() < 4)
2286 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad QUERY_RECORDING query");
2291 pginfo =
new ProgramInfo(slist[2].toUInt(), recstartts);
2294 QStringList strlist;
2315 const QString& playbackhost = slist[1];
2317 QStringList::const_iterator it = slist.cbegin() + 2;
2332 const QFileInfo
info(lpath);
2336 QStringList strlist;
2354 std::this_thread::sleep_for(3s + std::chrono::microseconds(
MythRandom(0, 2000)));
2359 QString logInfo = QString(
"recording id %1 (chanid %2 at %3)")
2364 QString name = QString(
"deleteThread%1%2").arg(getpid()).arg(
MythRandom());
2370 QString msg = QString(
"ERROR opening database connection for Delete "
2371 "Thread for chanid %1 recorded at %2. Program "
2372 "will NOT be deleted.")
2375 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2385 QString msg = QString(
"ERROR retrieving program info when trying to "
2386 "delete program for chanid %1 recorded at %2. "
2387 "Recording will NOT be deleted.")
2390 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2400 if ((!checkFile.exists()) && pginfo.
GetFilesize() &&
2403 LOG(VB_GENERAL, LOG_ERR,
LOC +
2404 QString(
"ERROR when trying to delete file: %1. File "
2405 "doesn't exist. Database metadata will not be removed.")
2423 bool errmsg =
false;
2438 if ((fd < 0) && checkFile.exists())
2444 std::this_thread::sleep_for(2s);
2445 if (checkFile.exists())
2451 LOG(VB_GENERAL, LOG_ERR,
LOC +
2452 QString(
"Error deleting file: %1. Keeping metadata in database.")
2467 QStringList nameFilters;
2468 nameFilters.push_back(fInfo.fileName() +
"*.png");
2469 nameFilters.push_back(fInfo.fileName() +
"*.jpg");
2470 nameFilters.push_back(fInfo.fileName() +
".tmp");
2471 nameFilters.push_back(fInfo.fileName() +
".old");
2472 nameFilters.push_back(fInfo.fileName() +
".map");
2473 nameFilters.push_back(fInfo.fileName() +
".tmp.map");
2474 nameFilters.push_back(fInfo.baseName() +
".srt");
2476 QDir dir (fInfo.path());
2477 QFileInfoList miscFiles = dir.entryInfoList(nameFilters);
2479 for (
const auto &
file : std::as_const(miscFiles))
2481 QString sFileName =
file.absoluteFilePath();
2493 if (slowDeletes && fd >= 0)
2499 QString logInfo = QString(
"recording id %1 filename %2")
2502 LOG(VB_GENERAL, LOG_NOTICE,
"DeleteRecordedFiles - " + logInfo);
2506 query.
prepare(
"SELECT basename, hostname, storagegroup FROM recordedfile "
2507 "WHERE recordedid = :RECORDEDID;");
2510 if (!query.
exec() || !query.
size())
2513 LOG(VB_GENERAL, LOG_ERR,
LOC +
2514 QString(
"Error querying recordedfiles for %1.") .arg(logInfo));
2517 while (query.
next())
2519 QString basename = query.
value(0).toString();
2522 bool deleteInDB =
false;
2524 if (basename == QFileInfo(ds->
m_filename).fileName())
2555 update.
prepare(
"DELETE FROM recordedfile "
2556 "WHERE recordedid = :RECORDEDID "
2557 "AND basename = :BASENAME ;");
2559 update.
bindValue(
":BASENAME", basename);
2563 LOG(VB_GENERAL, LOG_ERR,
LOC +
2564 QString(
"Error querying recordedfile (%1) for %2.")
2565 .arg(query.
value(1).toString(), logInfo));
2573 QString logInfo = QString(
"recording id %1 (chanid %2 at %3)")
2577 LOG(VB_GENERAL, LOG_NOTICE,
"DoDeleteINDB - " + logInfo);
2580 query.
prepare(
"DELETE FROM recorded WHERE recordedid = :RECORDEDID AND "
2585 if (!query.
exec() || !query.
size())
2588 LOG(VB_GENERAL, LOG_ERR,
LOC +
2589 QString(
"Error deleting recorded entry for %1.") .arg(logInfo));
2592 std::this_thread::sleep_for(1s);
2595 QString msg = QString(
"RECORDING_LIST_CHANGE DELETE %1")
2600 std::this_thread::sleep_for(3s);
2602 query.
prepare(
"DELETE FROM recordedmarkup "
2603 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2610 LOG(VB_GENERAL, LOG_ERR,
LOC +
2611 QString(
"Error deleting recordedmarkup for %1.") .arg(logInfo));
2614 query.
prepare(
"DELETE FROM recordedseek "
2615 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2622 LOG(VB_GENERAL, LOG_ERR,
LOC +
2623 QString(
"Error deleting recordedseek for %1.")
2638 bool deleteBrokenSymlinks)
2642 QString linktext =
"";
2643 QByteArray fname =
filename.toLocal8Bit();
2646 LOG(VB_FILE, LOG_INFO,
LOC +
2647 QString(
"About to unlink/delete file: '%1'")
2648 .arg(fname.constData()));
2650 QString errmsg = QString(
"Delete Error '%1'").arg(fname.constData());
2651 if (finfo.isSymLink())
2654 QByteArray alink = linktext.toLocal8Bit();
2655 errmsg += QString(
" -> '%2'").arg(alink.constData());
2658 if (followLinks && finfo.isSymLink())
2660 if (!finfo.exists() && deleteBrokenSymlinks)
2662 unlink(fname.constData());
2669 unlink(fname.constData());
2672 else if (!finfo.isSymLink())
2679 int err = unlink(fname.constData());
2684 if (fd < 0 && open_errno != EISDIR)
2685 LOG(VB_GENERAL, LOG_ERR,
LOC + errmsg +
ENO);
2701 QByteArray fname =
filename.toLocal8Bit();
2702 QString msg = QString(
"Error deleting '%1'").arg(fname.constData());
2703 int fd = open(fname.constData(), O_WRONLY);
2707 if (errno == EISDIR)
2712 LOG(VB_GENERAL, LOG_ERR, msg +
" could not delete directory " +
ENO);
2718 LOG(VB_GENERAL, LOG_ERR, msg +
" could not open " +
ENO);
2722 else if (unlink(fname.constData()))
2724 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
" could not unlink " +
ENO);
2741 const QString &
filename, off_t fsize)
2754 query.
prepare(
"SELECT COUNT(cardid) FROM capturecard;");
2756 cards = query.
value(0).toInt();
2760 constexpr std::chrono::milliseconds sleep_time = 500ms;
2761 const size_t min_tps = 8LL * 1024 * 1024;
2762 const auto calc_tps = (size_t) (cards * 1.2 * (22200000LL / 8.0));
2763 const size_t tps = std::max(min_tps, calc_tps);
2764 const auto increment = (size_t) (tps * (sleep_time.count() * 0.001F));
2766 LOG(VB_FILE, LOG_INFO,
LOC +
2767 QString(
"Truncating '%1' by %2 MB every %3 milliseconds")
2769 .arg(increment / (1024.0 * 1024.0), 0,
'f', 2)
2770 .arg(sleep_time.count()));
2772 GetMythDB()->GetDBManager()->PurgeIdleConnections(
false);
2778 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"Truncating '%1' to %2 MB")
2779 .arg(
filename).arg(fsize / (1024.0 * 1024.0), 0,
'f', 2));
2782 int err = ftruncate(fd, fsize);
2785 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error truncating '%1'")
2789 return 0 ==
close(fd);
2794 if (pginfo && ((count % 100) == 0))
2799 std::this_thread::sleep_for(sleep_time);
2802 bool ok = (0 ==
close(fd));
2807 LOG(VB_FILE, LOG_INFO,
LOC +
2808 QString(
"Finished truncating '%1'").arg(
filename));
2818 pbssock =
pbs->getSocket();
2820 QStringList::const_iterator it = slist.cbegin() + 1;
2842 result = iter.key();
2847 QStringList outputlist( QString::number(result) );
2854 QStringList::const_iterator it = slist.cbegin() + 1;
2866 bool hasConflicts =
false;
2868 for (
auto *pInfo : schedList)
2886 pbssock =
pbs->getSocket();
2909 (*m_encoderList)[num]->StopRecording();
2917 QStringList outputlist(
"0" );
2942 recnum = iter.key();
2949 std::this_thread::sleep_for(100us);
2965 QStringList outputlist( QString::number(recnum) );
2972 bool forceMetadataDelete,
2980 qDebug() <<
"HandleDeleteRecording(chanid, starttime) Empty Recording ID";
2987 pbssock =
pbs->getSocket();
2989 QStringList outputlist( QString::number(0) );
2999 bool forceMetadataDelete)
3001 QStringList::const_iterator it = slist.cbegin() + 1;
3006 qDebug() <<
"HandleDeleteRecording(QStringList) Empty Recording ID";
3015 bool forceMetadataDelete,
bool lexpirer,
bool forgetHistory)
3017 int resultCode = -1;
3020 pbssock =
pbs->getSocket();
3022 bool justexpire = lexpirer ?
false :
3030 LOG(VB_GENERAL, LOG_ERR,
LOC +
3031 QString(
"ERROR when trying to delete file for %1. Unable "
3032 "to determine filename of recording.")
3038 QStringList outputlist(QString::number(resultCode));
3048 if (justexpire && !forceMetadataDelete &&
3057 QStringList outputlist( QString::number(0) );
3081 QStringList outputlist( QString::number(num) );
3091 bool fileExists = checkFile.exists();
3094 QFile checkFileUTF8(QString::fromUtf8(
filename.toLatin1().constData()));
3095 fileExists = checkFileUTF8.exists();
3104 if (fileExists || !recinfo.
GetFilesize() || forceMetadataDelete)
3110 qDebug() <<
"DoHandleDeleteRecording() Empty Recording ID";
3117 forceMetadataDelete);
3118 deleteThread->start();
3123 QString logInfo = QString(
"chanid %1")
3127 LOG(VB_GENERAL, LOG_ERR,
LOC +
3128 QString(
"ERROR when trying to delete file: %1. File doesn't "
3129 "exist. Database metadata will not be removed.")
3136 QStringList outputlist( QString::number(resultCode) );
3148 if (fileExists || !recinfo.
GetFilesize() || forceMetadataDelete)
3151 QString(
"REC_DELETED CHANID %1 STARTTIME %2")
3161 if (slist.size() == 3)
3170 QStringList::const_iterator it = slist.cbegin()+1;
3184 pbssock =
pbs->getSocket();
3198 QStringList outputlist( QString::number(ret) );
3235 result = QStringList(QString::number(1));
3239 result = QStringList(QString::number(0));
3258 LOG(VB_GENERAL, LOG_INFO,
LOC +
"HandleAddChildInput: Already locked");
3262 LOG(VB_GENERAL, LOG_INFO,
LOC +
3263 QString(
"HandleAddChildInput: Handling input %1").arg(inputid));
3273 LOG(VB_GENERAL, LOG_ERR,
LOC +
3274 QString(
"HandleAddChildInput: "
3275 "Failed to add child to input %1").arg(inputid));
3281 LOG(VB_GENERAL, LOG_INFO,
LOC +
3282 QString(
"HandleAddChildInput: Added child input %1").arg(childid));
3290 auto *tv =
new TVRec(childid);
3291 if (!tv || !tv->Init())
3293 LOG(VB_GENERAL, LOG_ERR,
LOC +
3294 QString(
"HandleAddChildInput: "
3295 "Failed to initialize input %1").arg(childid));
3304 (*m_encoderList)[childid] = enc;
3311 LOG(VB_GENERAL, LOG_ERR,
LOC +
3312 QString(
"HandleAddChildInput: "
3313 "Failed to add remote input %1").arg(childid));
3323 (*m_encoderList)[childid] = enc;
3332 auto *tv =
new TVRec(inputid);
3333 if (!tv || !tv->Init())
3335 LOG(VB_GENERAL, LOG_ERR,
LOC +
3336 QString(
"HandleAddChildInput: "
3337 "Failed to initialize input %1").arg(inputid));
3345 (*m_encoderList)[inputid] = enc;
3351 LOG(VB_GENERAL, LOG_INFO,
LOC +
3352 QString(
"HandleAddChildInput: "
3353 "Successfully handled input %1").arg(inputid));
3360 QStringList::const_iterator it = slist.cbegin() + 1;
3367 pbssock =
pbs->getSocket();
3370 QStringList outputlist( QString::number(0) );
3382 QStringList strlist;
3385 if (!sleepCmd.isEmpty())
3389 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
3390 "Received GO_TO_SLEEP command from master, running SleepCommand.");
3395 strlist <<
"ERROR: SleepCommand is empty";
3396 LOG(VB_GENERAL, LOG_ERR,
LOC +
3397 "ERROR: in HandleGoToSleep(), but no SleepCommand found!");
3413 QStringList strlist;
3447 QStringList strlist;
3466 QStringList shortlist;
3467 if (strlist.size() < 4)
3469 shortlist << QString(
"0");
3470 shortlist << QString(
"0");
3474 unsigned int index = (
uint)(strlist.size()) - 2;
3475 shortlist << strlist[index++];
3476 shortlist << strlist[index++];
3492 QStringList strlist;
3494#if defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
3495 strlist <<
"0" <<
"0" <<
"0";
3501 strlist <<
"getloadavg() failed";
3505 strlist << QString::number(loads[0])
3506 << QString::number(loads[1])
3507 << QString::number(loads[2]);
3522 QStringList strlist;
3523 std::chrono::seconds uptime = 0s;
3527 strlist << QString::number(uptime.count());
3532 strlist <<
"Could not determine uptime.";
3546 QStringList strlist;
3561 QStringList strlist;
3567 if (
getMemStats(totalMB, freeMB, totalVM, freeVM))
3569 strlist << QString::number(totalMB) << QString::number(freeMB)
3570 << QString::number(totalVM) << QString::number(freeVM);
3575 strlist <<
"Could not determine memory stats.";
3589 QStringList strlist;
3604 bool checkSlaves = slist[1].toInt() != 0;
3606 QStringList::const_iterator it = slist.cbegin() + 2;
3622 QStringList outputlist( QString::number(
static_cast<int>(
exists)) );
3642 QStringList strlist( QString::number(
static_cast<int>(
exists)) );
3654 QString storageGroup =
"Default";
3659 switch (slist.size()) {
3661 if (!slist[3].isEmpty())
3665 if (slist[2].isEmpty())
3666 storageGroup = slist[2];
3674 LOG(VB_GENERAL, LOG_ERR,
LOC +
3675 QString(
"ERROR checking for file, filename '%1' "
3676 "fails sanity checks").arg(
filename));
3683 LOG(VB_GENERAL, LOG_ERR,
LOC +
3684 "ERROR, invalid input count for QUERY_FILE_HASH");
3721 const QString&
filename = slist[1];
3722 QString storageGroup =
"Default";
3723 QStringList retlist;
3725 if (slist.size() > 2)
3726 storageGroup = slist[2];
3732 LOG(VB_GENERAL, LOG_ERR,
LOC +
3733 QString(
"ERROR checking for file, filename '%1' "
3734 "fails sanity checks").arg(
filename));
3740 if (storageGroup.isEmpty())
3741 storageGroup =
"Default";
3747 if (!fullname.isEmpty())
3750 retlist << fullname;
3752 struct stat fileinfo {};
3753 if (stat(fullname.toLocal8Bit().constData(), &fileinfo) >= 0)
3755 retlist << QString::number(fileinfo.st_dev);
3756 retlist << QString::number(fileinfo.st_ino);
3757 retlist << QString::number(fileinfo.st_mode);
3758 retlist << QString::number(fileinfo.st_nlink);
3759 retlist << QString::number(fileinfo.st_uid);
3760 retlist << QString::number(fileinfo.st_gid);
3761 retlist << QString::number(fileinfo.st_rdev);
3762 retlist << QString::number(fileinfo.st_size);
3767 retlist << QString::number(fileinfo.st_blksize);
3768 retlist << QString::number(fileinfo.st_blocks);
3770 retlist << QString::number(fileinfo.st_atime);
3771 retlist << QString::number(fileinfo.st_mtime);
3772 retlist << QString::number(fileinfo.st_ctime);
3786 query.
prepare(
"SELECT MAX(endtime) FROM program WHERE manualid = 0;");
3796 QDateTime GuideDataThrough;
3798 QStringList strlist;
3802 if (GuideDataThrough.isNull())
3803 strlist << QString(
"0000-00-00 00:00");
3805 strlist << GuideDataThrough.toString(
"yyyy-MM-dd hh:mm");
3811 const QString& tmptable,
int recordid)
3815 QStringList strList;
3819 if (tmptable.isEmpty())
3833 query.
prepare(
"SELECT NULL FROM record "
3834 "WHERE recordid = :RECID;");
3840 record->m_recordID = recordid;
3841 if (record->Load() &&
3847 query.
prepare(
"DELETE FROM program WHERE manualid = :RECID;");
3857 strList << QString::number(0);
3858 strList << QString::number(0);
3868 QStringList strList;
3873 strList << QString::number(0);
3883 QStringList::const_iterator it = slist.cbegin() + 1;
3886 QStringList strlist;
3891 strlist << QString::number(0);
3900 QStringList strList;
3905 strList << QString::number(0);
3914 QStringList strList;
3916 if ((sList.size() < 4) || (sList.size() > 5))
3918 LOG(VB_GENERAL, LOG_ERR,
LOC +
3919 QString(
"HandleSGGetFileList: Invalid Request. %1")
3920 .arg(sList.join(
"[]:[]")));
3921 strList <<
"EMPTY LIST";
3927 const QString& wantHost = sList.at(1);
3928 QHostAddress wantHostaddr(wantHost);
3929 const QString& groupname = sList.at(2);
3930 const QString& path = sList.at(3);
3931 bool fileNamesOnly =
false;
3933 if (sList.size() >= 5)
3934 fileNamesOnly = (sList.at(4).toInt() != 0);
3936 bool slaveUnreachable =
false;
3938 LOG(VB_FILE, LOG_INFO,
LOC +
3939 QString(
"HandleSGGetFileList: group = %1 host = %2 "
3940 " path = %3 wanthost = %4")
3941 .arg(groupname, host, path, wantHost));
3945 if ((host.toLower() == wantHost.toLower()) ||
3946 (!addr.isEmpty() && addr == wantHostaddr.toString()))
3949 LOG(VB_FILE, LOG_INFO,
LOC +
"HandleSGGetFileList: Getting local info");
3960 LOG(VB_FILE, LOG_INFO,
LOC +
3961 "HandleSGGetFileList: Getting remote info");
3965 slaveUnreachable =
false;
3969 LOG(VB_FILE, LOG_INFO,
LOC +
3970 QString(
"HandleSGGetFileList: Failed to grab slave socket "
3971 ": %1 :").arg(wantHost));
3972 slaveUnreachable =
true;
3977 if (slaveUnreachable)
3978 strList <<
"SLAVE UNREACHABLE: " << host;
3980 if (strList.isEmpty() || (strList.at(0) ==
"0"))
3981 strList <<
"EMPTY LIST";
3991 QString storageGroup = slist[2];
3993 bool allowFallback =
true;
3994 bool useRegex =
false;
3995 QStringList fileList;
3997 if (!QHostAddress(
hostname).isNull())
3999 LOG(VB_GENERAL, LOG_ERR, QString(
"Mainserver: QUERY_FINDFILE called "
4000 "with IP (%1) instead of hostname. "
4001 "This is invalid.").arg(
hostname));
4007 if (storageGroup.isEmpty())
4008 storageGroup =
"Default";
4013 LOG(VB_GENERAL, LOG_ERR,
LOC +
4014 QString(
"ERROR QueryFindFile, filename '%1' "
4015 "fails sanity checks").arg(
filename));
4016 fileList <<
"ERROR: Bad/Missing Filename";
4021 if (slist.size() >= 5)
4022 useRegex = (slist[4].toInt() > 0);
4024 if (slist.size() >= 6)
4025 allowFallback = (slist[5].toInt() > 0);
4027 LOG(VB_FILE, LOG_INFO,
LOC +
4028 QString(
"Looking for file '%1' on host '%2' in group '%3' (useregex: %4, allowfallback: %5")
4042 QStringList files = sgroup.
GetFileList(
'/' + fi.path());
4044 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Looking in dir '%1' for '%2'")
4045 .arg(fi.path(), fi.fileName()));
4047 for (
int x = 0; x < files.size(); x++)
4049 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Found '%1 - %2'").arg(x).arg(files[x]));
4052 QStringList filteredFiles = files.filter(QRegularExpression(fi.fileName()));
4053 for (
const QString&
file : std::as_const(filteredFiles))
4057 fi.path() +
'/' +
file,
4073 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Checking remote host '%1' for file").arg(
hostname));
4081 if (!slaveFiles.isEmpty() && slaveFiles[0] !=
"NOT FOUND" && !slaveFiles[0].startsWith(
"ERROR: "))
4082 fileList += slaveFiles;
4088 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Slave '%1' was unreachable").arg(
hostname));
4089 fileList << QString(
"ERROR: SLAVE UNREACHABLE: %1").arg(
hostname);
4097 if (
m_ismaster && fileList.isEmpty() && allowFallback)
4102 QString sql =
"SELECT DISTINCT hostname "
4103 "FROM storagegroup "
4104 "WHERE groupname = :GROUP "
4105 "AND hostname != :HOSTNAME";
4107 query.
bindValue(
":GROUP", storageGroup);
4113 fileList <<
"ERROR: failed to get host list";
4129 QStringList files = sgroup.
GetFileList(
'/' + fi.path());
4131 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Looking in dir '%1' for '%2'")
4132 .arg(fi.path(), fi.fileName()));
4134 for (
int x = 0; x < files.size(); x++)
4136 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Found '%1 - %2'").arg(x).arg(files[x]));
4139 QStringList filteredFiles = files.filter(QRegularExpression(fi.fileName()));
4141 for (
const QString&
file : std::as_const(filteredFiles))
4145 fi.path() +
'/' +
file,
4152 if (!fname.isEmpty())
4167 if (!slaveFiles.isEmpty() && slaveFiles[0] !=
"NOT FOUND" && !slaveFiles[0].startsWith(
"ERROR: "))
4168 fileList += slaveFiles;
4174 if (!fileList.isEmpty())
4179 if (fileList.isEmpty())
4181 fileList <<
"NOT FOUND";
4182 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"File was not found"));
4186 for (
int x = 0; x < fileList.size(); x++)
4188 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"File %1 was found at: '%2'").arg(x).arg(fileList[0]));
4201 QStringList strList;
4203 if (sList.size() < 4)
4205 LOG(VB_GENERAL, LOG_ERR,
LOC +
4206 QString(
"HandleSGFileQuery: Invalid Request. %1")
4207 .arg(sList.join(
"[]:[]")));
4208 strList <<
"EMPTY LIST";
4214 const QString& wantHost = sList.at(1);
4215 QHostAddress wantHostaddr(wantHost);
4216 const QString& groupname = sList.at(2);
4217 const QString&
filename = sList.at(3);
4219 bool allowFallback =
true;
4220 if (sList.size() >= 5)
4221 allowFallback = (sList.at(4).toInt() > 0);
4222 LOG(VB_FILE, LOG_ERR, QString(
"HandleSGFileQuery - allowFallback: %1").arg(allowFallback));
4224 bool slaveUnreachable =
false;
4226 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"HandleSGFileQuery: %1")
4231 if ((host.toLower() == wantHost.toLower()) ||
4232 (!addr.isEmpty() && addr == wantHostaddr.toString()))
4234 LOG(VB_FILE, LOG_INFO,
LOC +
"HandleSGFileQuery: Getting local info");
4243 LOG(VB_FILE, LOG_INFO,
LOC +
4244 "HandleSGFileQuery: Getting remote info");
4247 slaveUnreachable =
false;
4251 LOG(VB_FILE, LOG_INFO,
LOC +
4252 QString(
"HandleSGFileQuery: Failed to grab slave socket : %1 :")
4254 slaveUnreachable =
true;
4259 if (slaveUnreachable)
4260 strList <<
"SLAVE UNREACHABLE: " << wantHost;
4262 if (strList.count() == 0 || (strList.at(0) ==
"0"))
4263 strList <<
"EMPTY LIST";
4271 QString pbshost =
pbs->getHostname();
4273 QStringList strlist;
4282 if ((cardid != -1) && (cardid != elink->GetInputID()))
4285 if (elink->IsLocal())
4288 enchost = elink->GetHostName();
4290 if ((enchost == pbshost) &&
4291 (elink->IsConnected()) &&
4292 (!elink->IsBusy()) &&
4293 (!elink->IsTunerLocked()))
4307 QString msg = QString(
"Cardid %1 LOCKed for external use on %2.")
4308 .arg(retval).arg(pbshost);
4309 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
4312 query.
prepare(
"SELECT videodevice, audiodevice, "
4315 "WHERE cardid = :CARDID ;");
4321 strlist << QString::number(retval)
4322 << query.
value(0).toString()
4323 << query.
value(1).toString()
4324 << query.
value(2).toString();
4332 LOG(VB_GENERAL, LOG_ERR,
LOC +
4333 "MainServer::LockTuner(): Could not find "
4334 "card info in database");
4339 strlist <<
"-2" <<
"" <<
"" <<
"";
4345 strlist <<
"-1" <<
"" <<
"" <<
"";
4352 QStringList strlist;
4359 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleFreeTuner() " +
4360 QString(
"Unknown encoder: %1").arg(cardid));
4361 strlist <<
"FAILED";
4368 QString msg = QString(
"Cardid %1 FREED from external use on %2.")
4369 .arg(cardid).arg(
pbs->getHostname());
4370 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
4390 uint excluded_input)
4392 LOG(VB_CHANNEL, LOG_INFO,
4393 LOC + QString(
"Excluding input %1")
4394 .arg(excluded_input));
4397 std::vector<InputInfo> busyinputs;
4398 std::vector<InputInfo> freeinputs;
4399 QMap<uint, QSet<uint> > groupids;
4407 info.m_inputId = elink->GetInputID();
4409 if (!elink->IsConnected() || elink->IsTunerLocked())
4411 LOG(VB_CHANNEL, LOG_INFO,
4412 LOC + QString(
"Input %1 is locked or not connected")
4413 .arg(
info.m_inputId));
4417 std::vector<uint> infogroups;
4419 for (
uint group : infogroups)
4420 groupids[
info.m_inputId].insert(group);
4423 if (
info.m_inputId != excluded_input && elink->IsBusy(&busyinfo))
4425 LOG(VB_CHANNEL, LOG_DEBUG,
4426 LOC + QString(
"Input %1 is busy on %2/%3")
4430 busyinputs.push_back(
info);
4432 else if (
info.m_liveTvOrder)
4434 LOG(VB_CHANNEL, LOG_DEBUG,
4435 LOC + QString(
"Input %1 is free")
4436 .arg(
info.m_inputId));
4437 freeinputs.push_back(
info);
4444 for (
auto & busyinfo : busyinputs)
4446 auto freeiter = freeinputs.begin();
4447 while (freeiter != freeinputs.end())
4451 if ((groupids[busyinfo.m_inputId] & groupids[freeinfo.
m_inputId])
4458 if (busyinfo.m_sourceId == freeinfo.
m_sourceId)
4460 LOG(VB_CHANNEL, LOG_DEBUG,
4461 LOC + QString(
"Input %1 is limited to %2/%3 by input %4")
4462 .arg(freeinfo.
m_inputId).arg(busyinfo.m_chanId)
4463 .arg(busyinfo.m_mplexId).arg(busyinfo.m_inputId));
4464 freeinfo.
m_chanId = busyinfo.m_chanId;
4465 freeinfo.
m_mplexId = busyinfo.m_mplexId;
4470 LOG(VB_CHANNEL, LOG_DEBUG,
4471 LOC + QString(
"Input %1 is unavailable by input %2")
4472 .arg(freeinfo.
m_inputId).arg(busyinfo.m_inputId));
4473 freeiter = freeinputs.erase(freeiter);
4479 QStringList strlist;
4480 for (
auto & input : freeinputs)
4482 LOG(VB_CHANNEL, LOG_INFO,
4483 LOC + QString(
"Input %1 is available on %2/%3")
4484 .arg(input.m_inputId).arg(input.m_chanId)
4485 .arg(input.m_mplexId));
4486 input.ToStringList(strlist);
4489 if (strlist.empty())
4514 if (commands.size() < 2 || slist.size() < 2)
4517 int recnum = commands[1].toInt();
4524 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleRecorderQuery() " +
4525 QString(
"Unknown encoder: %1").arg(recnum));
4526 QStringList retlist(
"bad" );
4532 const QString& command = slist[1];
4534 QStringList retlist;
4539 LOG(VB_GENERAL, LOG_ERR,
LOC +
" MainServer::HandleRecorderQuery() " +
4540 QString(
"Command %1 for unconnected encoder %2")
4541 .arg(command).arg(recnum));
4547 if (command ==
"IS_RECORDING")
4551 else if (command ==
"GET_FRAMERATE")
4555 else if (command ==
"GET_FRAMES_WRITTEN")
4559 else if (command ==
"GET_FILE_POSITION")
4563 else if (command ==
"GET_MAX_BITRATE")
4567 else if (command ==
"GET_CURRENT_RECORDING")
4572 info->ToStringList(retlist);
4582 else if (command ==
"GET_KEYFRAME_POS")
4584 long long desired = slist[2].toLongLong();
4587 else if (command ==
"FILL_POSITION_MAP")
4589 int64_t start = slist[2].toLongLong();
4590 int64_t end = slist[3].toLongLong();
4599 for (
auto it = map.cbegin(); it != map.cend(); ++it)
4601 retlist += QString::number(it.key());
4602 retlist += QString::number(*it);
4604 if (retlist.empty())
4608 else if (command ==
"FILL_DURATION_MAP")
4610 int64_t start = slist[2].toLongLong();
4611 int64_t end = slist[3].toLongLong();
4620 for (
auto it = map.cbegin(); it != map.cend(); ++it)
4622 retlist += QString::number(it.key());
4623 retlist += QString::number(*it);
4625 if (retlist.empty())
4629 else if (command ==
"GET_RECORDING")
4644 else if (command ==
"FRONTEND_READY")
4649 else if (command ==
"CANCEL_NEXT_RECORDING")
4651 const QString& cancel = slist[2];
4652 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
4653 QString(
"Received: CANCEL_NEXT_RECORDING %1").arg(cancel));
4657 else if (command ==
"SPAWN_LIVETV")
4659 const QString& chainid = slist[2];
4670 enc->
SpawnLiveTV(chain, slist[3].toInt() != 0, slist[4]);
4673 else if (command ==
"STOP_LIVETV")
4690 else if (command ==
"PAUSE")
4695 else if (command ==
"FINISH_RECORDING")
4700 else if (command ==
"SET_LIVE_RECORDING")
4702 int recording = slist[2].toInt();
4706 else if (command ==
"GET_INPUT")
4709 ret = (ret.isEmpty()) ?
"UNKNOWN" : ret;
4712 else if (command ==
"SET_INPUT")
4714 const QString& input = slist[2];
4715 QString ret = enc->
SetInput(input);
4716 ret = (ret.isEmpty()) ?
"UNKNOWN" : ret;
4719 else if (command ==
"TOGGLE_CHANNEL_FAVORITE")
4721 const QString& changroup = slist[2];
4725 else if (command ==
"CHANGE_CHANNEL")
4731 else if (command ==
"SET_CHANNEL")
4733 const QString& name = slist[2];
4737 else if (command ==
"SET_SIGNAL_MONITORING_RATE")
4739 auto rate = std::chrono::milliseconds(slist[2].toInt());
4740 int notifyFrontend = slist[3].toInt();
4742 retlist << QString::number(oldrate.count());
4744 else if (command ==
"GET_COLOUR")
4747 retlist << QString::number(ret);
4749 else if (command ==
"GET_CONTRAST")
4752 retlist << QString::number(ret);
4754 else if (command ==
"GET_BRIGHTNESS")
4757 retlist << QString::number(ret);
4759 else if (command ==
"GET_HUE")
4762 retlist << QString::number(ret);
4764 else if (command ==
"CHANGE_COLOUR")
4766 int type = slist[2].toInt();
4767 bool up = slist[3].toInt() != 0;
4770 retlist << QString::number(ret);
4772 else if (command ==
"CHANGE_CONTRAST")
4774 int type = slist[2].toInt();
4775 bool up = slist[3].toInt() != 0;
4778 retlist << QString::number(ret);
4780 else if (command ==
"CHANGE_BRIGHTNESS")
4782 int type= slist[2].toInt();
4783 bool up = slist[3].toInt() != 0;
4786 retlist << QString::number(ret);
4788 else if (command ==
"CHANGE_HUE")
4790 int type= slist[2].toInt();
4791 bool up = slist[3].toInt() != 0;
4794 retlist << QString::number(ret);
4796 else if (command ==
"CHECK_CHANNEL")
4798 const QString& name = slist[2];
4799 retlist << QString::number((
int)(enc->
CheckChannel(name)));
4801 else if (command ==
"SHOULD_SWITCH_CARD")
4803 const QString& chanid = slist[2];
4806 else if (command ==
"CHECK_CHANNEL_PREFIX")
4808 QString needed_spacer;
4809 const QString&
prefix = slist[2];
4810 uint complete_valid_channel_on_rec = 0;
4811 bool is_extra_char_useful =
false;
4814 prefix, complete_valid_channel_on_rec,
4815 is_extra_char_useful, needed_spacer);
4817 retlist << QString::number((
int)match);
4818 retlist << QString::number(complete_valid_channel_on_rec);
4819 retlist << QString::number((
int)is_extra_char_useful);
4820 retlist << ((needed_spacer.isEmpty()) ? QString(
"X") : needed_spacer);
4822 else if (command ==
"GET_NEXT_PROGRAM_INFO" && (slist.size() >= 6))
4824 QString channelname = slist[2];
4825 uint chanid = slist[3].toUInt();
4827 QString starttime = slist[5];
4830 QString subtitle =
"";
4832 QString category =
"";
4833 QString endtime =
"";
4834 QString callsign =
"";
4835 QString iconpath =
"";
4836 QString seriesid =
"";
4837 QString programid =
"";
4840 title, subtitle, desc, category, starttime,
4841 endtime, callsign, iconpath, channelname, chanid,
4842 seriesid, programid);
4853 retlist << QString::number(chanid);
4857 else if (command ==
"GET_CHANNEL_INFO")
4859 uint chanid = slist[2].toUInt();
4861 QString callsign =
"";
4862 QString channum =
"";
4863 QString channame =
"";
4867 callsign, channum, channame, xmltv);
4869 retlist << QString::number(chanid);
4870 retlist << QString::number(sourceid);
4878 LOG(VB_GENERAL, LOG_ERR,
LOC +
4879 QString(
"Unknown command: %1").arg(command));
4891 int recnum = commands[1].toInt();
4898 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleSetNextLiveTVDir() " +
4899 QString(
"Unknown encoder: %1").arg(recnum));
4900 QStringList retlist(
"bad" );
4909 QStringList retlist(
"OK" );
4917 uint chanid = slist[1].toUInt();
4918 uint sourceid = slist[2].toUInt();
4919 QString oldcnum =
cleanup(slist[3]);
4920 QString callsign =
cleanup(slist[4]);
4921 QString channum =
cleanup(slist[5]);
4922 QString channame =
cleanup(slist[6]);
4923 QString xmltv =
cleanup(slist[7]);
4925 QStringList retlist;
4926 if (!chanid || !sourceid)
4938 ok &= encoder->SetChannelInfo(chanid, sourceid, oldcnum,
4939 callsign, channum, channame, xmltv);
4944 retlist << (ok ?
"1" :
"0");
4953 int recnum = commands[1].toInt();
4954 QStringList retlist;
4961 LOG(VB_GENERAL, LOG_ERR,
LOC +
4962 QString(
"HandleRemoteEncoder(cmd %1) ").arg(slist[1]) +
4963 QString(
"Unknown encoder: %1").arg(recnum));
4972 const QString& command = slist[1];
4974 if (command ==
"GET_STATE")
4976 retlist << QString::number((
int)enc->
GetState());
4978 else if (command ==
"GET_SLEEPSTATUS")
4982 else if (command ==
"GET_FLAGS")
4984 retlist << QString::number(enc->
GetFlags());
4986 else if (command ==
"IS_BUSY")
4988 std::chrono::seconds time_buffer = 5s;
4989 if (slist.size() >= 3)
4990 time_buffer = std::chrono::seconds(slist[2].toInt());
4992 retlist << QString::number((
int)enc->
IsBusy(&busy_input, time_buffer));
4995 else if (command ==
"MATCHES_RECORDING" &&
4998 QStringList::const_iterator it = slist.cbegin() + 2;
5003 else if (command ==
"START_RECORDING" &&
5006 QStringList::const_iterator it = slist.cbegin() + 2;
5013 else if (command ==
"GET_RECORDING_STATUS")
5017 else if (command ==
"RECORD_PENDING" &&
5020 auto secsleft = std::chrono::seconds(slist[2].toInt());
5021 int haslater = slist[3].toInt();
5022 QStringList::const_iterator it = slist.cbegin() + 4;
5029 else if (command ==
"CANCEL_NEXT_RECORDING" &&
5030 (slist.size() >= 3))
5032 bool cancel = (bool) slist[2].toInt();
5036 else if (command ==
"STOP_RECORDING")
5041 else if (command ==
"GET_MAX_BITRATE")
5045 else if (command ==
"GET_CURRENT_RECORDING")
5050 info->ToStringList(retlist);
5073 if (
pbs->isMediaServer())
5084 QStringList retlist;
5086 retlist.push_front(QString::number(retlist.size()));
5093 QStringList retlist;
5094 const QString& queryhostname = slist[1];
5099 if (slave !=
nullptr)
5119 size_t totalKBperMin = 0;
5124 if (!enc->IsConnected() || !enc->IsBusy())
5127 long long maxBitrate = enc->GetMaxBitrate();
5129 maxBitrate = 19500000LL;
5130 long long thisKBperMin = (((size_t)maxBitrate)*((size_t)15))>>11;
5131 totalKBperMin += thisKBperMin;
5132 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Cardid %1: max bitrate %2 KB/min")
5133 .arg(enc->GetInputID()).arg(thisKBperMin));
5137 LOG(VB_FILE, LOG_INFO,
LOC +
5138 QString(
"Maximal bitrate of busy encoders is %1 KB/min")
5139 .arg(totalKBperMin));
5141 return totalKBperMin;
5148 QString allHostList;
5152 QMap <QString, bool> backendsCounted;
5153 std::list<PlaybackSock *> localPlaybackList;
5159 if ((
pbs->IsDisconnected()) ||
5160 (!
pbs->isMediaServer()) ||
5162 (backendsCounted.contains(
pbs->getHostname())))
5165 backendsCounted[
pbs->getHostname()] =
true;
5167 localPlaybackList.push_back(
pbs);
5168 allHostList +=
"," +
pbs->getHostname();
5173 for (
auto &
pbs : localPlaybackList) {
5174 fsInfos <<
pbs->GetDiskSpace();
5183 maxWriteFiveSec = std::max((int64_t)2048, maxWriteFiveSec);
5202 QStringList strlist;
5210 for (
auto & fsInfo : fsInfos)
5212 fsInfo.setFSysID(-1);
5215 LOG(VB_SCHEDULE | VB_FILE, LOG_DEBUG,
LOC +
5216 "Determining unique filesystems");
5219 maxWriteFiveSec = std::max((
size_t)2048, maxWriteFiveSec);
5225 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5226 "--- GetFilesystemInfos directory list start ---");
5227 for (
const auto&
fs1 : std::as_const(fsInfos))
5230 QString(
"Dir: %1:%2")
5231 .arg(
fs1.getHostname(),
fs1.getPath());
5232 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC + msg) ;
5233 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5234 QString(
" Location: %1")
5235 .arg(
fs1.isLocal() ?
"Local" :
"Remote"));
5236 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5237 QString(
" fsID : %1")
5238 .arg(
fs1.getFSysID()));
5239 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5240 QString(
" dirID : %1")
5241 .arg(
fs1.getGroupID()));
5242 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5243 QString(
" BlkSize : %1")
5244 .arg(
fs1.getBlockSize()));
5245 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5246 QString(
" TotalKB : %1")
5247 .arg(
fs1.getTotalSpace()));
5248 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5249 QString(
" UsedKB : %1")
5250 .arg(
fs1.getUsedSpace()));
5251 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5252 QString(
" FreeKB : %1")
5253 .arg(
fs1.getFreeSpace()));
5255 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5256 "--- GetFilesystemInfos directory list end ---");
5265 const QString &src,
const QString &dst)
5268 QStringList retlist;
5270 if (src.isEmpty() || dst.isEmpty()
5271 || src.contains(
"..") || dst.contains(
".."))
5273 LOG(VB_GENERAL, LOG_ERR,
LOC +
5274 QString(
"HandleMoveFile: ERROR moving file '%1' -> '%2', "
5275 "a path fails sanity checks").arg(src, dst));
5276 retlist <<
"0" <<
"Invalid path";
5281 QString srcAbs = sgroup.
FindFile(src);
5282 if (srcAbs.isEmpty())
5284 LOG(VB_GENERAL, LOG_ERR,
LOC +
5285 QString(
"HandleMoveFile: Unable to find %1").arg(src));
5286 retlist <<
"0" <<
"Source file not found";
5294 QString dstAbs = sgroup.
FindFile(dst);
5295 if (!dstAbs.isEmpty() && QFileInfo(dstAbs).isFile())
5297 LOG(VB_GENERAL, LOG_ERR,
LOC +
5298 QString(
"HandleMoveFile: Destination exists at %1").arg(dstAbs));
5299 retlist <<
"0" <<
"Destination file exists";
5305 int sgPathSize = srcAbs.size() - src.size();
5306 dstAbs = srcAbs.mid(0, sgPathSize) + dst;
5320 LOG(VB_FILE, LOG_INFO, QString(
"MainServer::RenameThread: Renaming %1 -> %2")
5323 QStringList retlist;
5324 QFileInfo fi(
m_dst);
5326 if (QDir().mkpath(fi.path()) && QFile::rename(
m_src,
m_dst))
5332 retlist <<
"0" <<
"Rename failed";
5333 LOG(VB_FILE, LOG_ERR,
"MainServer::DoRenameThread: Rename failed");
5366 QStringList retlist;
5372 LOG(VB_GENERAL, LOG_ERR,
LOC +
5373 QString(
"ERROR deleting file, filename '%1' "
5374 "fails sanity checks").arg(
filename));
5385 if (fullfile.isEmpty()) {
5386 LOG(VB_GENERAL, LOG_ERR,
LOC +
5387 QString(
"Unable to find %1 in HandleDeleteFile()") .arg(
filename));
5396 QFile checkFile(fullfile);
5403 const QFileInfo
info(fullfile);
5407 if ((fd < 0) && checkFile.exists())
5409 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error deleting file: %1.")
5429 auto *truncateThread =
new TruncateThread(
this, fullfile, fd, size);
5430 truncateThread->run();
5441 const QString &starttime,
5446 pbssock =
pbs->getSocket();
5449 frm_dir_map_t::const_iterator it;
5451 QStringList retlist;
5454 const ProgramInfo pginfo(chanid.toUInt(), recstartdt);
5463 for (it = markMap.cbegin(); it != markMap.cend(); ++it)
5466 QString intstr = QString(
"%1").arg(*it);
5468 retlist << QString::number(it.key());
5473 retlist.prepend(QString(
"%1").arg(rowcnt));
5482 const QString &starttime,
5497 const QString &starttime,
5513 const QString &starttime,
5524 pbssock =
pbs->getSocket();
5528 chanid.toUInt(), recstartts);
5530 QStringList retlist;
5531 retlist << QString::number(bookmark);
5550 pbssock =
pbs->getSocket();
5552 const QString& chanid = tokens[1];
5553 const QString& starttime = tokens[2];
5554 long long bookmark = tokens[3].toLongLong();
5557 QStringList retlist;
5568 retlist <<
"FAILED";
5582 pbssock =
pbs->getSocket();
5584 const QString&
hostname = tokens[1];
5585 const QString& setting = tokens[2];
5586 QStringList retlist;
5590 retlist << retvalue;
5598 bool synchronous = (command[0] ==
"DOWNLOAD_FILE_NOW");
5599 const QString& srcURL = command[1];
5600 const QString& storageGroup = command[2];
5605 QStringList retlist;
5609 pbssock =
pbs->getSocket();
5613 QFileInfo finfo(srcURL);
5617 if (outDir.isEmpty())
5619 LOG(VB_GENERAL, LOG_ERR,
LOC +
5620 QString(
"Unable to determine directory "
5621 "to write to in %1 write command").arg(command[0]));
5622 retlist <<
"downloadfile_directory_not_found";
5631 LOG(VB_GENERAL, LOG_ERR,
LOC +
5632 QString(
"ERROR: %1 write filename '%2' does not pass "
5633 "sanity checks.") .arg(command[0],
filename));
5634 retlist <<
"downloadfile_filename_dangerous";
5677 pbssock =
pbs->getSocket();
5679 const QString&
hostname = tokens[1];
5680 const QString& setting = tokens[2];
5681 const QString& svalue = tokens[3];
5682 QStringList retlist;
5697 QStringList retlist;
5719 QStringList strlist;
5725 QString sql =
"SELECT DISTINCT hostname "
5726 "FROM storagegroup "
5727 "WHERE groupname = 'Music'";
5741 LOG(VB_GENERAL, LOG_INFO,
LOC +
5742 QString(
"HandleScanMusic: running filescanner on master BE '%1'").arg(
hostname));
5754 LOG(VB_GENERAL, LOG_INFO,
LOC +
5755 QString(
"HandleScanMusic: asking slave '%1' to run file scanner").arg(
hostname));
5761 LOG(VB_GENERAL, LOG_INFO,
LOC +
5762 QString(
"HandleScanMusic: Failed to grab slave socket on '%1'").arg(
hostname));
5771 LOG(VB_GENERAL, LOG_INFO,
LOC +
5772 QString(
"HandleScanMusic: running filescanner on slave BE '%1'")
5790 QStringList strlist;
5794 const QString&
hostname = slist[1];
5802 LOG(VB_GENERAL, LOG_INFO,
LOC +
5803 QString(
"HandleMusicTagUpdateVolatile: asking slave '%1' to update the metadata").arg(
hostname));
5813 LOG(VB_GENERAL, LOG_INFO,
LOC +
5814 QString(
"HandleMusicTagUpdateVolatile: Failed to grab slave socket on '%1'").arg(
hostname));
5816 strlist <<
"ERROR: slave not found";
5825 QStringList paramList;
5826 paramList.append(QString(
"--songid='%1'").arg(slist[2]));
5827 paramList.append(QString(
"--rating='%1'").arg(slist[3]));
5828 paramList.append(QString(
"--playcount='%1'").arg(slist[4]));
5829 paramList.append(QString(
"--lastplayed='%1'").arg(slist[5]));
5831 QString command =
GetAppBinDir() +
"mythutil --updatemeta " + paramList.join(
" ");
5833 LOG(VB_GENERAL, LOG_INFO,
LOC +
5834 QString(
"HandleMusicTagUpdateVolatile: running %1'").arg(command));
5850 QStringList strlist;
5854 const QString&
hostname = slist[1];
5862 LOG(VB_GENERAL, LOG_INFO,
LOC +
5863 QString(
"HandleMusicCalcTrackLen: asking slave '%1' to update the track length").arg(
hostname));
5873 LOG(VB_GENERAL, LOG_INFO,
LOC +
5874 QString(
"HandleMusicCalcTrackLen: Failed to grab slave socket on '%1'").arg(
hostname));
5876 strlist <<
"ERROR: slave not found";
5885 QStringList paramList;
5886 paramList.append(QString(
"--songid='%1'").arg(slist[2]));
5888 QString command =
GetAppBinDir() +
"mythutil --calctracklen " + paramList.join(
" ");
5890 LOG(VB_GENERAL, LOG_INFO,
LOC +
5891 QString(
"HandleMusicCalcTrackLen: running %1'").arg(command));
5908 QStringList strlist;
5912 const QString&
hostname = slist[1];
5920 LOG(VB_GENERAL, LOG_INFO,
LOC +
5921 QString(
"HandleMusicTagUpdateMetadata: asking slave '%1' "
5922 "to update the metadata").arg(
hostname));
5932 LOG(VB_GENERAL, LOG_INFO,
LOC +
5933 QString(
"HandleMusicTagUpdateMetadata: Failed to grab "
5934 "slave socket on '%1'").arg(
hostname));
5936 strlist <<
"ERROR: slave not found";
5945 int songID = slist[2].toInt();
5951 LOG(VB_GENERAL, LOG_ERR,
LOC +
5952 QString(
"HandleMusicTagUpdateMetadata: "
5953 "Cannot find metadata for trackid: %1")
5956 strlist <<
"ERROR: track not found";
5969 LOG(VB_GENERAL, LOG_ERR,
LOC +
5970 QString(
"HandleMusicTagUpdateMetadata: "
5971 "Failed to write to tag for trackid: %1")
5974 strlist <<
"ERROR: write to tag failed";
5994 QStringList strlist;
5998 const QString&
hostname = slist[1];
6006 LOG(VB_GENERAL, LOG_INFO,
LOC +
6007 QString(
"HandleMusicFindAlbumArt: asking slave '%1' "
6008 "to update the albumart").arg(
hostname));
6018 LOG(VB_GENERAL, LOG_INFO,
LOC +
6019 QString(
"HandleMusicFindAlbumArt: Failed to grab "
6020 "slave socket on '%1'").arg(
hostname));
6022 strlist <<
"ERROR: slave not found";
6031 int songID = slist[2].toInt();
6032 bool updateDatabase = (slist[3].toInt() == 1);
6038 LOG(VB_GENERAL, LOG_ERR,
LOC +
6039 QString(
"HandleMusicFindAlbumArt: "
6040 "Cannot find metadata for trackid: %1").arg(songID));
6042 strlist <<
"ERROR: track not found";
6052 QDir dir = fi.absoluteDir();
6055 "*.png;*.jpg;*.jpeg;*.gif;*.bmp");
6056 dir.setNameFilters(nameFilter.split(
";"));
6058 QStringList files = dir.entryList();
6063 fi.setFile(mdata->
Filename(
false));
6064 QString startDir = fi.path();
6066 for (
const QString&
file : std::as_const(files))
6070 image->m_filename = startDir +
'/' + fi.fileName();
6072 image->m_embedded =
false;
6074 image->m_description =
"";
6075 images->addImage(image);
6087 for (
int x = 0; x < artList.count(); x++)
6091 images->addImage(image);
6099 LOG(VB_GENERAL, LOG_ERR,
LOC +
6100 QString(
"HandleMusicFindAlbumArt: "
6101 "Failed to find a tagger for trackid: %1").arg(songID));
6106 images->dumpToDatabase();
6109 strlist.append(QString(
"%1").arg(images->getImageCount()));
6111 for (
uint x = 0; x < images->getImageCount(); x++)
6114 strlist.append(QString(
"%1").arg(image->
m_id));
6115 strlist.append(QString(
"%1").arg((
int)image->
m_imageType));
6116 strlist.append(QString(
"%1").arg(
static_cast<int>(image->
m_embedded)));
6124 QStringList paramList;
6125 paramList.append(QString(
"--songid='%1'").arg(mdata->
ID()));
6126 paramList.append(QString(
"--imagetype='%1'").arg(image->
m_imageType));
6128 QString command =
GetAppBinDir() +
"mythutil --extractimage " + paramList.join(
" ");
6146 QStringList strlist;
6150 const QString&
hostname = slist[1];
6151 const QString& songid = slist[2];
6152 const QString& imagetype = slist[3];
6160 LOG(VB_GENERAL, LOG_INFO,
LOC +
6161 QString(
"HandleMusicTagGetImage: asking slave '%1' to "
6162 "extract the image").arg(
hostname));
6172 LOG(VB_GENERAL, LOG_INFO,
LOC +
6173 QString(
"HandleMusicTagGetImage: Failed to grab slave "
6178 QStringList paramList;
6179 paramList.append(QString(
"--songid='%1'").arg(songid));
6180 paramList.append(QString(
"--imagetype='%1'").arg(imagetype));
6182 QString command =
GetAppBinDir() +
"mythutil --extractimage " + paramList.join(
" ");
6200 QStringList strlist;
6204 const QString&
hostname = slist[1];
6212 LOG(VB_GENERAL, LOG_INFO,
LOC +
6213 QString(
"HandleMusicTagChangeImage: asking slave '%1' "
6214 "to update the metadata").arg(
hostname));
6224 LOG(VB_GENERAL, LOG_INFO,
LOC +
6225 QString(
"HandleMusicTagChangeImage: Failed to grab "
6226 "slave socket on '%1'").arg(
hostname));
6228 strlist <<
"ERROR: slave not found";
6236 int songID = slist[2].toInt();
6237 auto oldType = (
ImageType)slist[3].toInt();
6238 auto newType = (
ImageType)slist[4].toInt();
6245 LOG(VB_GENERAL, LOG_ERR,
LOC +
6246 QString(
"HandleMusicTagChangeImage: "
6247 "Cannot find metadata for trackid: %1")
6250 strlist <<
"ERROR: track not found";
6291 LOG(VB_GENERAL, LOG_ERR,
"HandleMusicTagChangeImage: failed to change image type");
6293 strlist <<
"ERROR: failed to change image type";
6311 image->
m_filename = fi.path() + QString(
"/%1-%2.jpg")
6327 QStringList paramList;
6328 paramList.append(QString(
"--songid='%1'").arg(mdata->
ID()));
6329 paramList.append(QString(
"--imagetype='%1'").arg(image->
m_imageType));
6331 QString command =
GetAppBinDir() +
"mythutil --extractimage " + paramList.join(
" ");
6344 image->
m_filename = fi.absolutePath() + QString(
"/%1.jpg")
6369 QStringList strlist;
6373 const QString&
hostname = slist[1];
6381 LOG(VB_GENERAL, LOG_INFO,
LOC +
6382 QString(
"HandleMusicTagAddImage: asking slave '%1' "
6383 "to add the image").arg(
hostname));
6393 LOG(VB_GENERAL, LOG_INFO,
LOC +
6394 QString(
"HandleMusicTagAddImage: Failed to grab "
6395 "slave socket on '%1'").arg(
hostname));
6397 strlist <<
"ERROR: slave not found";
6406 int songID = slist[2].toInt();
6407 const QString&
filename = slist[3];
6408 auto imageType = (
ImageType) slist[4].toInt();
6414 LOG(VB_GENERAL, LOG_ERR,
LOC +
6415 QString(
"HandleMusicTagAddImage: Cannot find metadata for trackid: %1")
6418 strlist <<
"ERROR: track not found";
6430 LOG(VB_GENERAL, LOG_ERR,
LOC +
6431 "HandleMusicTagAddImage: failed to find a tagger for track");
6433 strlist <<
"ERROR: tagger not found";
6444 LOG(VB_GENERAL, LOG_ERR,
LOC +
6445 "HandleMusicTagAddImage: asked to write album art to the tag "
6446 "but the tagger doesn't support it!");
6448 strlist <<
"ERROR: embedded images not supported by tag";
6459 bool isDirectoryImage =
false;
6462 if (imageFilename.isEmpty())
6466 imageFilename = fi.absolutePath() +
'/' +
filename;
6467 isDirectoryImage =
true;
6472 LOG(VB_GENERAL, LOG_ERR,
LOC +
6473 QString(
"HandleMusicTagAddImage: cannot find image file %1").arg(
filename));
6475 strlist <<
"ERROR: failed to find image file";
6491 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleMusicTagAddImage: failed to write album art to tag");
6493 strlist <<
"ERROR: failed to write album art to tag";
6498 if (!isDirectoryImage)
6499 QFile::remove(imageFilename);
6507 if (!isDirectoryImage)
6508 QFile::remove(imageFilename);
6524 QStringList strlist;
6528 const QString&
hostname = slist[1];
6536 LOG(VB_GENERAL, LOG_INFO,
LOC +
6537 QString(
"HandleMusicTagRemoveImage: asking slave '%1' "
6538 "to remove the image").arg(
hostname));
6548 LOG(VB_GENERAL, LOG_INFO,
LOC +
6549 QString(
"HandleMusicTagRemoveImage: Failed to grab "
6550 "slave socket on '%1'").arg(
hostname));
6552 strlist <<
"ERROR: slave not found";
6560 int songID = slist[2].toInt();
6561 int imageID = slist[3].toInt();
6568 LOG(VB_GENERAL, LOG_ERR,
LOC +
6569 QString(
"HandleMusicTagRemoveImage: Cannot find metadata for trackid: %1")
6572 strlist <<
"ERROR: track not found";
6584 LOG(VB_GENERAL, LOG_ERR,
LOC +
6585 "HandleMusicTagRemoveImage: failed to find a tagger for track");
6587 strlist <<
"ERROR: tagger not found";
6598 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleMusicTagRemoveImage: asked to remove album art "
6599 "from the tag but the tagger doesn't support it!");
6601 strlist <<
"ERROR: embedded images not supported by tag";
6614 LOG(VB_GENERAL, LOG_ERR,
LOC +
6615 QString(
"HandleMusicTagRemoveImage: Cannot find image for imageid: %1")
6618 strlist <<
"ERROR: image not found";
6630 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleMusicTagRemoveImage: failed to remove album art from tag");
6632 strlist <<
"ERROR: failed to remove album art from tag";
6651 QStringList strlist;
6655 const QString&
hostname = slist[1];
6656 const QString& songid = slist[2];
6657 const QString& grabberName = slist[3];
6658 QString artist =
"";
6662 if (slist.size() == 7)
6675 LOG(VB_GENERAL, LOG_INFO,
LOC +
6676 QString(
"HandleMusicFindLyrics: asking slave '%1' to "
6687 LOG(VB_GENERAL, LOG_INFO,
LOC +
6688 QString(
"HandleMusicFindLyrics: Failed to grab slave "
6693 QStringList paramList;
6694 paramList.append(QString(
"--songid='%1'").arg(songid));
6695 paramList.append(QString(
"--grabber='%1'").arg(grabberName));
6697 if (!artist.isEmpty())
6698 paramList.append(QString(
"--artist=\"%1\"").arg(artist));
6700 if (!album.isEmpty())
6701 paramList.append(QString(
"--album=\"%1\"").arg(album));
6703 if (!title.isEmpty())
6704 paramList.append(QString(
"--title=\"%1\"").arg(title));
6706 QString command =
GetAppBinDir() +
"mythutil --findlyrics " + paramList.join(
" ");
6740 QStringList strlist;
6744 QString scriptDir =
GetShareDir() +
"metadata/Music/lyrics";
6749 LOG(VB_GENERAL, LOG_ERR, QString(
"Cannot find lyric scripts directory: %1").arg(scriptDir));
6750 strlist << QString(
"ERROR: Cannot find lyric scripts directory: %1").arg(scriptDir);
6758 d.setFilter(QDir::Files | QDir::NoDotAndDotDot);
6759 d.setNameFilters(QStringList(
"*.py"));
6760 QFileInfoList list =
d.entryInfoList();
6763 LOG(VB_GENERAL, LOG_ERR, QString(
"Cannot find any lyric scripts in: %1").arg(scriptDir));
6764 strlist << QString(
"ERROR: Cannot find any lyric scripts in: %1").arg(scriptDir);
6772 QStringList scripts;
6773 for (
const auto & fi : std::as_const(list))
6775 LOG(VB_FILE, LOG_NOTICE, QString(
"Found lyric script at: %1").arg(fi.filePath()));
6776 scripts.append(fi.filePath());
6779 QStringList grabbers;
6782 for (
int x = 0; x < scripts.count(); x++)
6784 QStringList
args { scripts.at(x),
"-v" };
6786 p.start(PYTHON_EXE,
args);
6787 p.waitForFinished(-1);
6788 QString result =
p.readAllStandardOutput();
6790 QDomDocument domDoc;
6791#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
6794 int errorColumn = 0;
6796 if (!domDoc.setContent(result,
false, &errorMsg, &errorLine, &errorColumn))
6798 LOG(VB_GENERAL, LOG_ERR,
6799 QString(
"FindLyrics: Could not parse version from %1").arg(scripts.at(x)) +
6800 QString(
"\n\t\t\tError at line: %1 column: %2 msg: %3").arg(errorLine).arg(errorColumn).arg(errorMsg));
6804 auto parseResult = domDoc.setContent(result);
6807 LOG(VB_GENERAL, LOG_ERR,
6808 QString(
"FindLyrics: Could not parse version from %1")
6809 .arg(scripts.at(x)) +
6810 QString(
"\n\t\t\tError at line: %1 column: %2 msg: %3")
6811 .arg(parseResult.errorLine).arg(parseResult.errorColumn)
6812 .arg(parseResult.errorMessage));
6817 QDomNodeList itemList = domDoc.elementsByTagName(
"grabber");
6818 QDomNode itemNode = itemList.item(0);
6820 grabbers.append(itemNode.namedItem(QString(
"name")).toElement().text());
6827 for (
int x = 0; x < grabbers.count(); x++)
6828 strlist.append(grabbers.at(x));
6839 QStringList strlist;
6843 const QString&
hostname = slist[1];
6844 int songID = slist[2].toInt();
6852 LOG(VB_GENERAL, LOG_INFO,
LOC +
6853 QString(
"HandleMusicSaveLyrics: asking slave '%1' to "
6864 LOG(VB_GENERAL, LOG_INFO,
LOC +
6865 QString(
"HandleMusicSaveLyrics: Failed to grab slave "
6873 LOG(VB_GENERAL, LOG_ERR, QString(
"Cannot find metadata for trackid: %1").arg(songID));
6874 strlist << QString(
"ERROR: Cannot find metadata for trackid: %1").arg(songID);
6882 QString lyricsFile =
GetConfDir() + QString(
"/MythMusic/Lyrics/%1.txt").arg(songID);
6886 QFile::remove(lyricsFile);
6889 QFile
file(QLatin1String(qPrintable(lyricsFile)));
6891 if (
file.open(QIODevice::WriteOnly))
6893 QTextStream stream(&
file);
6894 for (
int x = 3; x < slist.count(); x++)
6895 stream << slist.at(x);
6907 QStringList &commands,
6912 int recnum = commands[1].toInt();
6913 const QString& command = slist[1];
6915 QStringList retlist;
6921 if (command ==
"DONE")
6929 LOG(VB_GENERAL, LOG_ERR,
LOC +
6930 QString(
"Unknown file transfer socket: %1").arg(recnum));
6931 retlist << QString(
"ERROR: Unknown file transfer socket: %1")
6943 if (command ==
"REQUEST_BLOCK")
6945 int size = slist[2].toInt();
6949 else if (command ==
"WRITE_BLOCK")
6951 int size = slist[2].toInt();
6953 retlist << QString::number(ft->
WriteBlock(size));
6955 else if (command ==
"SEEK")
6957 long long pos = slist[2].toLongLong();
6958 int whence = slist[3].toInt();
6959 long long curpos = slist[4].toLongLong();
6961 long long ret = ft->
Seek(curpos, pos, whence);
6962 retlist << QString::number(ret);
6964 else if (command ==
"IS_OPEN")
6966 bool isopen = ft->
isOpen();
6968 retlist << QString::number(static_cast<int>(isopen));
6970 else if (command ==
"REOPEN")
6972 retlist << QString::number(static_cast<int>(ft->
ReOpen(slist[2])));
6974 else if (command ==
"DONE")
6979 else if (command ==
"SET_TIMEOUT")
6981 bool fast = slist[2].toInt() != 0;
6985 else if (command ==
"REQUEST_SIZE")
6993 LOG(VB_GENERAL, LOG_ERR,
LOC +
6994 QString(
"Unknown command: %1").arg(command));
6995 retlist <<
"ERROR" <<
"invalid_call";
7009 QStringList::const_iterator it = slist.cbegin() + 1;
7021 retval = iter.key();
7027 QStringList strlist( QString::number(retval) );
7044 strlist <<
"nohost";
7056 int recordernum = slist[1].toInt();
7058 QStringList strlist;
7081 strlist <<
"nohost";
7090 if (slist.size() < 2)
7095 const QString& message = slist[1];
7096 QStringList extra_data;
7097 for (
uint i = 2; i < (
uint) slist.size(); i++)
7098 extra_data.push_back(slist[i]);
7100 if (extra_data.empty())
7111 QStringList retlist(
"OK" );
7119 QStringList retlist;
7121 const QString& newverbose = slist[1];
7122 int len = newverbose.length();
7128 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
7129 QString(
"Verbose mask changed, new mask is: %1").arg(
verboseString));
7135 LOG(VB_GENERAL, LOG_ERR,
LOC +
7136 QString(
"Invalid SET_VERBOSE string: '%1'").arg(newverbose));
7137 retlist <<
"Failed";
7146 QStringList retlist;
7147 const QString& newstring = slist[1];
7148 LogLevel_t newlevel = LOG_UNKNOWN;
7150 int len = newstring.length();
7154 if (newlevel != LOG_UNKNOWN)
7158 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
7159 QString(
"Log level changed, new level is: %1")
7166 if (newlevel == LOG_UNKNOWN)
7168 LOG(VB_GENERAL, LOG_ERR,
LOC +
7169 QString(
"Invalid SET_VERBOSE string: '%1'").arg(newstring));
7170 retlist <<
"Failed";
7180 int RecordingsInProgress = 0;
7181 int LiveTVRecordingsInProgress = 0;
7182 QStringList retlist;
7187 if (elink->IsBusyRecording()) {
7188 RecordingsInProgress++;
7191 if (
info &&
info->GetRecordingGroup() ==
"LiveTV")
7192 LiveTVRecordingsInProgress++;
7199 retlist << QString::number(RecordingsInProgress);
7200 retlist << QString::number(LiveTVRecordingsInProgress);
7209 if (slist.size() < 3)
7211 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Too few params in pixmap request");
7212 QStringList outputlist(
"ERROR");
7213 outputlist +=
"TOO_FEW_PARAMS";
7218 bool time_fmt_sec =
true;
7219 std::chrono::seconds time = std::chrono::seconds::max();
7220 long long frame = -1;
7224 bool has_extra_data =
false;
7226 QString token = slist[1];
7227 if (token.isEmpty())
7229 LOG(VB_GENERAL, LOG_ERR,
LOC +
7230 "Failed to parse pixmap request. Token absent");
7231 QStringList outputlist(
"ERROR");
7232 outputlist +=
"TOKEN_ABSENT";
7237 QStringList::const_iterator it = slist.cbegin() + 2;
7238 QStringList::const_iterator end = slist.cend();
7243 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to parse pixmap request. "
7244 "ProgramInfo missing pathname");
7245 QStringList outputlist(
"BAD");
7246 outputlist +=
"NO_PATHNAME";
7250 if (token.toLower() ==
"do_not_care")
7252 token = QString(
"%1:%2")
7255 if (it != slist.cend())
7256 (time_fmt_sec = ((*it).toLower() ==
"s")), ++it;
7257 if (it != slist.cend())
7260 time = std::chrono::seconds((*it).toLongLong()), ++it;
7262 frame = (*it).toLongLong(), ++it;
7264 if (it != slist.cend())
7265 (outputfile = *it), ++it;
7266 outputfile = (outputfile ==
"<EMPTY>") ? QString() : outputfile;
7267 if (it != slist.cend())
7269 width = (*it).toInt(&ok); ++it;
7270 width = ok ? width : -1;
7272 if (it != slist.cend())
7274 height = (*it).toInt(&ok); ++it;
7275 height = ok ? height : -1;
7276 has_extra_data =
true;
7278 QSize outputsize = QSize(width, height);
7282 auto pos_text = (time != std::chrono::seconds::max())
7283 ? QString::number(time.count()) +
"s"
7284 : QString::number(frame) +
"f";
7285 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
7286 QString(
"HandleGenPreviewPixmap got extra data\n\t\t\t"
7289 .arg(width).arg(height).arg(outputfile));
7304 QStringList outputlist;
7307 if (time != std::chrono::seconds::max())
7310 token, &pginfo, time, -1, outputfile, outputsize);
7315 token, &pginfo, std::chrono::seconds::max(), frame, outputfile, outputsize);
7325 if (outputlist.empty() || outputlist[0] !=
"OK")
7331 LOG(VB_GENERAL, LOG_ERR,
LOC +
7332 QString(
"HandleGenPreviewPixmap() "
7333 "Couldn't find backend for:\n\t\t\t%1")
7339 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleGenPreviewPixmap: Unable to "
7340 "find file locally, unable to make preview image.");
7341 QStringList outputlist(
"ERROR" );
7342 outputlist +=
"FILE_INACCESSIBLE";
7350 if (time != std::chrono::seconds::max()) {
7352 pginfo, outputsize, outputfile, time, -1, token);
7355 pginfo, outputsize, outputfile, -1s, frame, token);
7363 QStringList outputlist(
"OK");
7364 if (!outputfile.isEmpty())
7365 outputlist += outputfile;
7373 QStringList::const_iterator it = slist.cbegin() + 1;
7378 QStringList strlist;
7391 strlist = (slavetime.isValid()) ?
7392 QStringList(QString::number(slavetime.toSecsSinceEpoch())) :
7399 LOG(VB_GENERAL, LOG_ERR,
LOC +
7400 QString(
"HandlePixmapLastModified() "
7401 "Couldn't find backend for:\n\t\t\t%1")
7407 LOG(VB_GENERAL, LOG_ERR,
LOC +
7408 "MainServer: HandlePixmapLastModified: Unable to "
7409 "find file locally, unable to get last modified date.");
7410 QStringList outputlist(
"BAD" );
7421 QDateTime lastmodified = finfo.lastModified();
7422 if (lastmodified.isValid())
7423 strlist = QStringList(QString::number(lastmodified.toSecsSinceEpoch()));
7425 strlist = QStringList(QString::number(UINT_MAX));
7429 strlist = QStringList(
"BAD" );
7438 QStringList strlist;
7443 strlist = QStringList(
"ERROR");
7444 strlist +=
"1: Parameter list too short";
7449 QDateTime cachemodified;
7450 if (!slist[1].isEmpty() && (slist[1].toInt() != -1))
7455 int max_file_size = slist[2].toInt();
7457 QStringList::const_iterator it = slist.begin() + 3;
7462 strlist = QStringList(
"ERROR");
7463 strlist +=
"2: Invalid ProgramInfo";
7474 size_t fsize = finfo.size();
7475 QDateTime lastmodified = finfo.lastModified();
7476 bool out_of_date = !cachemodified.isValid() ||
7477 (lastmodified > cachemodified);
7479 if (out_of_date && (fsize > 0) && ((ssize_t)fsize < max_file_size))
7483 bool open_ok =
file.open(QIODevice::ReadOnly);
7485 data =
file.readAll();
7487 if (!data.isEmpty())
7489 LOG(VB_FILE, LOG_INFO,
LOC +
7490 QString(
"Read preview file '%1'")
7492 if (lastmodified.isValid())
7493 strlist += QString::number(lastmodified.toSecsSinceEpoch());
7495 strlist += QString::number(UINT_MAX);
7496 strlist += QString::number(data.size());
7497#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
7498 quint16 checksum = qChecksum(data.constData(), data.size());
7500 quint16 checksum = qChecksum(data);
7502 strlist += QString::number(checksum);
7503 strlist += QString(data.toBase64());
7507 LOG(VB_GENERAL, LOG_ERR,
LOC +
7508 QString(
"Failed to read preview file '%1'")
7511 strlist = QStringList(
"ERROR");
7513 QString(
"3: Failed to read preview file '%1'%2")
7515 open_ok ?
"" :
" open failed");
7518 else if (out_of_date && (max_file_size > 0))
7520 if (fsize >= (
size_t) max_file_size)
7522 strlist = QStringList(
"WARNING");
7523 strlist += QString(
"1: Preview file too big %1 > %2")
7524 .arg(fsize).arg(max_file_size);
7528 strlist = QStringList(
"ERROR");
7529 strlist +=
"4: Preview file is invalid";
7534 if (lastmodified.isValid())
7535 strlist += QString::number(lastmodified.toSecsSinceEpoch());
7537 strlist += QString::number(UINT_MAX);
7551 strlist = QStringList(
"ERROR");
7553 "5: Could not locate mythbackend that made this recording";
7562 if (!strlist.empty())
7569 strlist = QStringList(
"WARNING");
7570 strlist +=
"2: Could not locate requested file";
7576 QStringList retlist(
"OK" );
7582 pbs->setBlockShutdown(blockShutdown);
7585 QStringList retlist(
"OK" );
7630 QList<uint> disconnectedSlaves;
7642 MythEvent me(
"LOCAL_RECONNECT_TO_MASTER");
7648 disconnectedSlaves.clear();
7649 bool needsReschedule =
false;
7653 LOG(VB_GENERAL, LOG_ERR,
LOC +
7654 QString(
"Slave backend: %1 no longer connected")
7655 .arg(
pbs->getHostname()));
7657 bool isFallingAsleep =
true;
7661 if (elink->GetSocket() ==
pbs)
7663 if (!elink->IsFallingAsleep())
7664 isFallingAsleep =
false;
7666 elink->SetSocket(
nullptr);
7668 disconnectedSlaves.push_back(elink->GetInputID());
7672 if (
m_sched && !isFallingAsleep)
7673 needsReschedule =
true;
7675 QString message = QString(
"LOCAL_SLAVE_BACKEND_OFFLINE %1")
7676 .arg(
pbs->getHostname());
7684 QString(
"SLAVE_DISCONNECTED HOSTNAME %1")
7685 .arg(
pbs->getHostname()));
7694 if (chain !=
nullptr)
7705 std::this_thread::sleep_for(500us);
7707 if (enc->IsBusy() &&
7708 enc->GetChainID() == chain->
GetID())
7719 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 sock(%2) '%3' disconnected")
7720 .arg(
pbs->getBlockShutdown() ?
"Playback" :
"Monitor")
7721 .arg(quintptr(socket),0,16)
7722 .arg(
pbs->getHostname()) );
7723 pbs->SetDisconnected();
7728 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Playback sock still exists?");
7736 if (!disconnectedSlaves.isEmpty())
7747 MythEvent me(
"LOCAL_CONNECTION_CLOSED");
7761 LOG(VB_GENERAL, LOG_INFO, QString(
"BEFileTransfer sock(%1) disconnected")
7762 .arg(quintptr(socket),0,16) );
7774 LOG(VB_GENERAL, LOG_INFO, QString(
"Control sock(%1) disconnected")
7775 .arg(quintptr(socket),0,16) );
7785 LOG(VB_GENERAL, LOG_WARNING,
LOC +
7786 QString(
"Unknown socket closing MythSocket(0x%1)")
7787 .arg((intptr_t)socket,0,16));
7800 if (
pbs->isSlaveBackend() &&
7823 if (
pbs->isMediaServer() &&
7839 {
return sock ==
pbs->getSocket(); });
7847 if (
id == ft->getSocket()->GetSocketDescriptor())
7856 if (sock == ft->getSocket())
7866 if (chain->GetID() ==
id)
7876 if (chain->IsHostSocket(sock))
7886 if (chain->ProgramIsAt(pginfo) >= 0)
7906 std::vector<LiveTVChain*> newChains;
7911 newChains.push_back(entry);
7921 if (closeApplication)
7927 QString lpath = QString(path);
7929 if (lpath.section(
'/', -2, -2) ==
"channels")
7932 QString
file = lpath.section(
'/', -1);
7936 query.
prepare(
"SELECT icon FROM channel "
7937 "WHERE deleted IS NULL AND icon LIKE :FILENAME ;");
7942 lpath = query.
value(0).toString();
7951 lpath = lpath.section(
'/', -1);
7953 QString fpath = lpath;
7954 if (fpath.endsWith(
".png"))
7955 fpath = fpath.left(fpath.length() - 4);
7961 if (pburl.startsWith(
"/"))
7963 lpath = pburl.section(
'/', 0, -2) +
"/" + lpath;
7964 LOG(VB_FILE, LOG_INFO,
LOC +
7965 QString(
"Local file path: %1").arg(lpath));
7969 LOG(VB_GENERAL, LOG_ERR,
LOC +
7970 QString(
"ERROR: LocalFilePath unable to find local "
7971 "path for '%1', found '%2' instead.")
7972 .arg(lpath, pburl));
7976 else if (!lpath.isEmpty())
7979 QString opath = lpath;
7982 if (!wantgroup.isEmpty())
7984 sgroup.
Init(wantgroup);
7985 lpath = QString(path);
7989 lpath = QFileInfo(lpath).fileName();
7992 QString tmpFile = sgroup.
FindFile(lpath);
7993 if (!tmpFile.isEmpty())
7996 LOG(VB_FILE, LOG_INFO,
LOC +
7997 QString(
"LocalFilePath(%1 '%2'), found file through "
7998 "exhaustive search at '%3'")
7999 .arg(path, opath, lpath));
8003 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"ERROR: LocalFilePath "
8004 "unable to find local path for '%1'.") .arg(path));
8020 auto *masterServerSock =
new MythSocket(-1,
this);
8025 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
8026 QString(
"Connecting to master server: %1:%2")
8027 .arg(server).arg(port));
8029 if (!masterServerSock->ConnectToHost(server, port))
8031 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
8032 "Connection to master server timed out.");
8034 masterServerSock->DecrRef();
8038 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Connected successfully");
8040 QString str = QString(
"ANN SlaveBackend %1 %2")
8044 QStringList strlist( str );
8049 elink->CancelNextRecording(
true);
8067 masterServerSock->SetReadyReadCallbackEnabled(
false);
8068 if (!masterServerSock->SendReceiveStringList(strlist, 1) ||
8069 (strlist[0] ==
"ERROR"))
8071 masterServerSock->DecrRef();
8072 masterServerSock =
nullptr;
8073 if (strlist.empty())
8075 LOG(VB_GENERAL, LOG_ERR,
LOC +
8076 "Failed to open master server socket, timeout");
8080 LOG(VB_GENERAL, LOG_ERR,
LOC +
8081 "Failed to open master server socket" +
8082 ((strlist.size() >= 2) ?
8083 QString(
", error was %1").arg(strlist[1]) :
8084 QString(
", remote error")));
8089 masterServerSock->SetReadyReadCallbackEnabled(
true);
8104 bool foundClient =
false;
8114 if ((*it)->isSlaveBackend())
8119 if (onlyBlockingClients && !(*it)->getBlockShutdown())
8136 QStringList bcast(
"SHUTDOWN_NOW" );
8143 if (
pbs->isSlaveBackend())
8144 pbs->getSocket()->WriteStringList(bcast);
8154 bool needsReschedule =
event.ExtraData(0).toUInt() != 0U;
8155 for (
int i = 1; i <
event.ExtraDataCount(); i++)
8158 if (needsReschedule)
8164 const QList<uint> &offlineEncoderIDs,
bool needsReschedule)
8166 QStringList extraData;
8167 extraData.push_back(
8168 QString::number(
static_cast<uint>(needsReschedule)));
8170 QList<uint>::const_iterator it;
8171 for (it = offlineEncoderIDs.begin(); it != offlineEncoderIDs.end(); ++it)
8172 extraData.push_back(QString::number(*it));
8174 MythEvent me(
"LOCAL_SLAVE_BACKEND_ENCODERS_OFFLINE", extraData);
8180#if CONFIG_SYSTEMD_NOTIFY
8181 QStringList status2;
8184 status2 << QString(
"Master backend.");
8186 status2 << QString(
"Slave backend.");
8191 int playback = 0, frontend = 0, monitor = 0, slave = 0, media = 0;
8197 if (
pbs->IsDisconnected())
8199 if (
pbs->isSlaveBackend())
8201 else if (
pbs->isMediaServer())
8203 else if (
pbs->IsFrontend())
8205 else if (
pbs->getBlockShutdown())
8210 status2 << QString(
"Connections: Pl %1, Fr %2, Mo %3, Sl %4, MS %5, FT %6, Co %7")
8211 .arg(playback).arg(frontend).arg(monitor).arg(slave).arg(media)
8222 if (not elink->IsLocal())
8224 switch (elink->GetState())
8243 for (
auto & recording : recordings)
8251 while (!recordings.empty())
8255 recordings.pop_back();
8259 QString(
"Recordings: active %1, scheduled %2")
8260 .arg(active).arg(scheduled);
8264 QString status(
"STATUS=" + status2.join(
' '));
8265 (void)sd_notify(0, qPrintable(status));
BackendContext * gBackendContext
AlbumArtImage * getImage(ImageType type)
static QString getTypeFilename(ImageType type)
static ImageType guessImageType(const QString &filename)
AlbumArtImage * getImageByID(int imageID)
const_iterator cbegin(void) const
Used to expire recordings to make space for new recordings.
void SetMainServer(MainServer *ms)
static void Update(int encoder, int fsID, bool immediately)
This is used to update the global AutoExpire instance "expirer".
void GetAllExpiring(QStringList &strList)
Gets the full list of programs that can expire in expiration order.
int RequestBlock(int size)
uint64_t GetFileSize(void)
bool ReOpen(const QString &newFilename="")
void SetTimeout(bool fast)
long long Seek(long long curpos, long long pos, int whence)
QString GetFileName(void)
~BEProcessRequestRunnable() override
BEProcessRequestRunnable(MainServer &parent, MythSocket *sock)
void SetFrontendConnected(Frontend *frontend)
void SetFrontendDisconnected(const QString &name)
static bool GetInputInfo(InputInfo &input, std::vector< uint > *groupids=nullptr)
static uint AddChildInput(uint parentid)
static bool DeleteInput(uint inputid)
static QString GetHostname(uint inputid)
bool m_forceMetadataDelete
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Provides an interface to both local and remote TVRec's for the mythbackend.
void FinishRecording(void)
Tells TVRec to stop recording, but only after "overrecord" seconds.
void CancelNextRecording(bool cancel)
Tells TVRec to cancel the next recording.
bool ShouldSwitchToAnotherInput(const QString &channelid)
Checks if named channel exists on current tuner, or another tuner.
void SetNextLiveTVDir(const QString &dir)
Tells TVRec where to put the next LiveTV recording.
RecStatus::Type StartRecording(ProgramInfo *rec)
Tells TVRec to Start recording the program "rec" as soon as possible.
bool IsConnected(void) const
Returns true if the EncoderLink instance is usable.
RecStatus::Type GetRecordingStatus(void)
QString SetInput(QString input)
Tells TVRec's recorder to change to the specified input.
bool AddChildInput(uint childid)
bool IsBusyRecording(void)
Returns true if the TVRec state is in a recording state.
void GetNextProgram(BrowseDirection direction, QString &title, QString &subtitle, QString &desc, QString &category, QString &starttime, QString &endtime, QString &callsign, QString &iconpath, QString &channelname, uint &chanid, QString &seriesid, QString &programid)
Returns information about the program that would be seen if we changed the channel using ChangeChanne...
void ToggleChannelFavorite(const QString &changroup)
Toggles whether the current channel should be on our favorites list.
ProgramInfo * GetRecording(void)
Returns TVRec's current recording.
float GetFramerate(void)
Returns the recording frame rate from TVRec.
QString GetInput(void) const
Returns TVRec's recorders current input.
void SetSocket(PlaybackSock *lsock)
Used to set the socket for a non-local EncoderLink.
long long GetMaxBitrate(void)
Returns maximum bits per second this recorder might output.
int LockTuner(void)
Lock the tuner for exclusive use.
bool IsLocal(void) const
Returns true for a local EncoderLink.
int GetInputID(void) const
Returns the inputid used to refer to the recorder in the DB.
bool CheckChannelPrefix(const QString &prefix, uint &complete_valid_channel_on_rec, bool &is_extra_char_useful, QString &needed_spacer)
Checks a prefix against the channels in the DB.
bool MatchesRecording(const ProgramInfo *rec)
Returns true if rec is actually being recorded by TVRec.
void ChangeChannel(ChannelChangeDirection channeldirection)
Changes to the next or previous channel.
bool IsBusy(InputInfo *busy_input=nullptr, std::chrono::seconds time_buffer=5s)
Returns true if the recorder is busy, or will be within the next time_buffer seconds.
uint GetFlags(void)
Returns the flag state of the recorder.
void StopLiveTV(void)
Tells TVRec to stop a "Live TV" recorder.
bool GetKeyframePositions(int64_t start, int64_t end, frm_pos_map_t &map)
TVState GetState()
Returns the TVState of the recorder.
void PauseRecorder(void)
Tells TVRec to pause a recorder, used for channel and input changes.
int GetPictureAttribute(PictureAttribute attr)
Changes brightness/contrast/colour/hue of a recording.
SleepStatus GetSleepStatus(void) const
Returns the current Sleep Status of the encoder.
void FreeTuner(void)
Unlock the tuner.
void FrontendReady(void)
Tells TVRec that the frontend is ready for data.
void RecordPending(const ProgramInfo *rec, std::chrono::seconds secsleft, bool hasLater)
Tells TVRec there is a pending recording "rec" in "secsleft" seconds.
bool CheckChannel(const QString &name)
Checks if named channel exists on current tuner.
int ChangePictureAttribute(PictureAdjustType type, PictureAttribute attr, bool direction)
Changes brightness/contrast/colour/hue of a recording.
void SetLiveRecording(int recording)
Tells TVRec to keep a LiveTV recording if 'recording' is 1.
void SetChannel(const QString &name)
Changes to a named channel on the current tuner.
void SpawnLiveTV(LiveTVChain *chain, bool pip, QString startchan)
Tells TVRec to Spawn a "Live TV" recorder.
void StopRecording(bool killFile=false)
Tells TVRec to stop recording immediately.
QString GetHostName(void) const
Returns the remote host for a non-local EncoderLink.
PlaybackSock * GetSocket(void)
Returns the socket, if set, for a non-local EncoderLink.
long long GetFramesWritten(void)
Returns number of frames written to disk by TVRec's RecorderBase instance.
bool GetChannelInfo(uint &chanid, uint &sourceid, QString &callsign, QString &channum, QString &channame, QString &xmltv) const
int64_t GetKeyframePosition(uint64_t desired)
Returns byte position in RingBuffer of a keyframe.
bool GetKeyframeDurations(int64_t start, int64_t end, frm_pos_map_t &map)
std::chrono::milliseconds SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend)
Sets the signal monitoring rate.
QString GetChainID(void)
Get the LiveTV chain id that's in use.
long long GetFilePosition(void)
Returns total number of bytes written by TVRec's RingBuffer.
bool IsReallyRecording(void)
Checks if the RecorderBase held by TVRec is actually recording.
static FileSystemInfoList QueryFileSystems(void)
static constexpr std::chrono::milliseconds kRequeryTimeout
~FreeSpaceUpdater() override
bool KeepRunning(bool dorun)
static constexpr std::chrono::milliseconds kExitTimeout
FreeSpaceUpdater(MainServer &parent)
QStringList HandleDbCreate(QStringList defs) const
Creates images for files created by a copy operation.
QStringList HandleDelete(const QString &ids) const
Deletes images/dirs.
QStringList HandleCreateThumbnails(const QStringList &message) const
Creates thumbnails on-demand.
QStringList HandleGetMetadata(const QString &id) const
Read meta data for an image.
QStringList HandleScanRequest(const QString &command, int devId=DEVICE_INVALID) const
Process scan requests.
QStringList HandleRename(const QString &id, const QString &newBase) const
Change name of an image/dir.
QStringList HandleIgnore(const QString &exclusions) const
Updates exclusion list for images.
static ImageManagerBe * getInstance()
Get Backend Gallery.
static bool DeleteAllJobs(uint chanid, const QDateTime &recstartts)
Keeps track of recordings in a current LiveTV instance.
uint HostSocketCount(void) const
QString GetID(void) const
void DelHostSocket(MythSocket *sock)
void DeleteProgram(ProgramInfo *pginfo)
void SetHostSocket(MythSocket *sock)
void LoadFromExistingChain(const QString &id)
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
static bool testDBConnection()
Checks DB connection + login (login info via Mythcontext)
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.
void setMaxThreadCount(int maxThreadCount)
void startReserved(QRunnable *runnable, const QString &debugName, std::chrono::milliseconds waitForAvailMS=0ms)
static MThreadPool * globalInstance(void)
void start(QRunnable *runnable, const QString &debugName, int priority=0)
QSet< MythSocket * > m_controlSocketList
QReadWriteLock m_sockListLock
void HandleMessage(QStringList &slist, PlaybackSock *pbs)
void NewConnection(qintptr socketDescriptor)
void HandleRecorderQuery(QStringList &slist, QStringList &commands, PlaybackSock *pbs)
void HandleQueryTimeZone(PlaybackSock *pbs)
friend class DeleteThread
QMutex m_downloadURLsLock
static const std::chrono::milliseconds kMasterServerReconnectTimeout
QMutex m_deferredDeleteLock
QTimer * m_autoexpireUpdateTimer
void HandleSGFileQuery(QStringList &sList, PlaybackSock *pbs)
void HandleQueryCheckFile(QStringList &slist, PlaybackSock *pbs)
std::vector< LiveTVChain * > m_liveTVChains
QTimer * m_deferredDeleteTimer
void DoHandleDeleteRecording(RecordingInfo &recinfo, PlaybackSock *pbs, bool forceMetadataDelete, bool lexpirer=false, bool forgetHistory=false)
PlaybackSock * GetPlaybackBySock(MythSocket *socket)
Warning you must hold a sockListLock lock before calling this.
MythServer * m_mythserver
void HandleVersion(MythSocket *socket, const QStringList &slist)
void HandleMusicFindLyrics(const QStringList &slist, PlaybackSock *pbs)
void HandleSetLogLevel(const QStringList &slist, PlaybackSock *pbs)
void BackendQueryDiskSpace(QStringList &strlist, bool consolidated, bool allHosts)
void HandleUndeleteRecording(QStringList &slist, PlaybackSock *pbs)
void GetActiveBackends(QStringList &hosts)
void HandleDeleteRecording(QString &chanid, QString &starttime, PlaybackSock *pbs, bool forceMetadataDelete, bool forgetHistory)
void HandleGetRecorderNum(QStringList &slist, PlaybackSock *pbs)
void ShutSlaveBackendsDown(const QString &haltcmd)
Sends the Slavebackends the request to shut down using haltcmd.
void HandleGetScheduledRecordings(PlaybackSock *pbs)
QMutex m_addChildInputLock
bool HandleDeleteFile(const QStringList &slist, PlaybackSock *pbs)
QWaitCondition m_masterFreeSpaceListWait
void HandleQueryFileExists(QStringList &slist, PlaybackSock *pbs)
friend class FreeSpaceUpdater
bool m_masterBackendOverride
static void DeleteRecordedFiles(DeleteStruct *ds)
void HandleMusicTagAddImage(const QStringList &slist, PlaybackSock *pbs)
static void getGuideDataThrough(QDateTime &GuideDataThrough)
void HandleActiveBackendsQuery(PlaybackSock *pbs)
static void DoDeleteInDB(DeleteStruct *ds)
void ProcessRequestWork(MythSocket *sock)
static QString LocalFilePath(const QString &path, const QString &wantgroup)
void DoHandleUndeleteRecording(RecordingInfo &recinfo, PlaybackSock *pbs)
void HandleMoveFile(PlaybackSock *pbs, const QString &storagegroup, const QString &src, const QString &dst)
void HandleSetNextLiveTVDir(QStringList &commands, PlaybackSock *pbs)
void HandleMusicFindAlbumArt(const QStringList &slist, PlaybackSock *pbs)
void HandleSetVerbose(const QStringList &slist, PlaybackSock *pbs)
void deferredDeleteSlot(void)
void connectionClosed(MythSocket *socket) override
void HandleMusicTagRemoveImage(const QStringList &slist, PlaybackSock *pbs)
void HandleSetSetting(const QStringList &tokens, PlaybackSock *pbs)
void HandleIsActiveBackendQuery(const QStringList &slist, PlaybackSock *pbs)
void DeleteChain(LiveTVChain *chain)
QMap< int, EncoderLink * > * m_encoderList
PlaybackSock * GetSlaveByHostname(const QString &hostname)
static int OpenAndUnlink(const QString &filename)
Opens a file, unlinks it and returns the file descriptor.
void HandleBookmarkQuery(const QString &chanid, const QString &starttime, PlaybackSock *pbs)
MainServer(bool master, int port, QMap< int, EncoderLink * > *tvList, Scheduler *sched, AutoExpire *expirer)
std::vector< MythSocket * > m_decrRefSocketList
void HandleQueryHostname(PlaybackSock *pbs)
void HandleForgetRecording(QStringList &slist, PlaybackSock *pbs)
std::vector< BEFileTransfer * > m_fileTransferList
void HandleDone(MythSocket *socket)
QMap< QString, QString > m_downloadURLs
void DoDeleteThread(DeleteStruct *ds)
void readyRead(MythSocket *socket) override
void HandleSlaveDisconnectedEvent(const MythEvent &event)
static void SendSlaveDisconnectedEvent(const QList< uint > &offlineEncoderIDs, bool needsReschedule)
LiveTVChain * GetChainWithRecording(const ProgramInfo &pginfo)
void customEvent(QEvent *e) override
bool isClientConnected(bool onlyBlockingClients=false)
void HandleMusicTagGetImage(const QStringList &slist, PlaybackSock *pbs)
MythDeque< DeferredDeleteStruct > m_deferredDeleteList
QStringList m_masterFreeSpaceList
void HandleFreeTuner(int cardid, PlaybackSock *pbs)
void HandleQueryFreeSpaceSummary(PlaybackSock *pbs)
static bool TruncateAndClose(ProgramInfo *pginfo, int fd, const QString &filename, off_t fsize)
Repeatedly truncate an open file in small increments.
void HandlePixmapLastModified(QStringList &slist, PlaybackSock *pbs)
void HandleBlockShutdown(bool blockShutdown, PlaybackSock *pbs)
void HandleSGGetFileList(QStringList &sList, PlaybackSock *pbs)
QTimer * m_masterServerReconnect
void HandleScanMusic(const QStringList &slist, PlaybackSock *pbs)
void UpdateSystemdStatus(void)
void HandleGetPendingRecordings(PlaybackSock *pbs, const QString &table="", int recordid=-1)
static void autoexpireUpdate(void)
std::vector< PlaybackSock * > m_playbackList
void HandleRemoteEncoder(QStringList &slist, QStringList &commands, PlaybackSock *pbs)
void DoHandleStopRecording(RecordingInfo &recinfo, PlaybackSock *pbs)
BEFileTransfer * GetFileTransferByID(int id)
Warning you must hold a sockListLock lock before calling this.
FreeSpaceUpdater *volatile m_masterFreeSpaceListUpdater
QMutex m_masterFreeSpaceListLock
static QMutex s_truncate_and_close_lock
QMutex m_fsInfosCacheLock
void DeletePBS(PlaybackSock *sock)
void HandleMusicTagUpdateVolatile(const QStringList &slist, PlaybackSock *pbs)
RequestedBy m_previewRequestedBy
void HandleCutlistQuery(const QString &chanid, const QString &starttime, PlaybackSock *pbs)
void HandleQueryFreeSpace(PlaybackSock *pbs, bool allHosts)
PlaybackSock * m_masterServer
void HandleGetFreeInputInfo(PlaybackSock *pbs, uint excluded_input)
void HandleQueryMemStats(PlaybackSock *pbs)
void HandleMusicSaveLyrics(const QStringList &slist, PlaybackSock *pbs)
size_t GetCurrentMaxBitrate(void)
friend class TruncateThread
void HandleCommBreakQuery(const QString &chanid, const QString &starttime, PlaybackSock *pbs)
friend class RenameThread
void ProcessRequest(MythSocket *sock)
void HandleGetExpiringRecordings(PlaybackSock *pbs)
void HandleQueryLoad(PlaybackSock *pbs)
void HandleCutMapQuery(const QString &chanid, const QString &starttime, PlaybackSock *pbs, bool commbreak)
void HandleSetChannelInfo(QStringList &slist, PlaybackSock *pbs)
LiveTVChain * GetExistingChain(const QString &id)
void HandleMusicGetLyricGrabbers(const QStringList &slist, PlaybackSock *pbs)
This function processes the received network protocol message to get the names of all scripts the gra...
FileSystemInfoList m_fsInfosCache
void HandleDownloadFile(const QStringList &command, PlaybackSock *pbs)
void HandleQueryFileHash(QStringList &slist, PlaybackSock *pbs)
void HandleQueryFindFile(QStringList &slist, PlaybackSock *pbs)
void HandleBackendRefresh(MythSocket *socket)
void HandleCheckRecordingActive(QStringList &slist, PlaybackSock *pbs)
MetadataFactory * m_metadatafactory
void HandleMusicTagChangeImage(const QStringList &slist, PlaybackSock *pbs)
void HandleQueryRecordings(const QString &type, PlaybackSock *pbs)
void reconnectTimeout(void)
void HandleIsRecording(const QStringList &slist, PlaybackSock *pbs)
void HandleLockTuner(PlaybackSock *pbs, int cardid=-1)
void HandleScanVideos(PlaybackSock *pbs)
void HandleSetBookmark(QStringList &tokens, PlaybackSock *pbs)
void SendResponse(MythSocket *sock, QStringList &commands)
void SendErrorResponse(MythSocket *sock, const QString &error)
void HandleQueryRecording(QStringList &slist, PlaybackSock *pbs)
void HandleRescheduleRecordings(const QStringList &request, PlaybackSock *pbs)
This function processes the received network protocol message to reschedule recordings.
void HandleMusicTagUpdateMetadata(const QStringList &slist, PlaybackSock *pbs)
void HandleStopRecording(QStringList &slist, PlaybackSock *pbs)
void HandleQueryUptime(PlaybackSock *pbs)
PlaybackSock * GetMediaServerByHostname(const QString &hostname)
void HandleFillProgramInfo(QStringList &slist, PlaybackSock *pbs)
void SetExitCode(int exitCode, bool closeApplication)
QMutex m_liveTVChainsLock
void DoTruncateThread(DeleteStruct *ds)
void HandleAnnounce(QStringList &slist, QStringList commands, MythSocket *socket)
void HandleSettingQuery(const QStringList &tokens, PlaybackSock *pbs)
void HandleFileTransferQuery(QStringList &slist, QStringList &commands, PlaybackSock *pbs)
void HandleMusicCalcTrackLen(const QStringList &slist, PlaybackSock *pbs)
void HandleGoToSleep(PlaybackSock *pbs)
void HandleGetConflictingRecordings(QStringList &slist, PlaybackSock *pbs)
void HandleQueryGuideDataThrough(PlaybackSock *pbs)
static int DeleteFile(const QString &filename, bool followLinks, bool deleteBrokenSymlinks=false)
Deletes links and unlinks the main file and returns the descriptor.
void HandleGetRecorderFromNum(QStringList &slist, PlaybackSock *pbs)
void GetFilesystemInfos(FileSystemInfoList &fsInfos, bool useCache=true)
bool HandleAddChildInput(uint inputid)
void AddToChains(LiveTVChain *chain)
void HandlePixmapGetIfModified(const QStringList &slist, PlaybackSock *pbs)
BEFileTransfer * GetFileTransferBySock(MythSocket *socket)
Warning you must hold a sockListLock lock before calling this.
void HandleGenPreviewPixmap(QStringList &slist, PlaybackSock *pbs)
void ClearSettingsCache(const QString &myKey=QString(""))
QString resolveSettingAddress(const QString &name, const QString &host=QString(), ResolveType type=ResolveAny, bool keepscope=false)
Retrieve IP setting "name" for "host".
QString GetMasterServerIP(void)
Returns the Master Backend IP address If the address is an IPv6 address, the scope Id is removed.
QString GetHostName(void)
bool IsThisHost(const QString &addr)
is this address mapped to this host
QString GetMasterHostPrefix(const QString &storageGroup=QString(), const QString &path=QString())
QString GetSetting(const QString &key, const QString &defaultval="")
void SendSystemEvent(const QString &msg)
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)
static int GetMasterServerPort(void)
Returns the Master Backend control port If no master server port has been defined in the database,...
bool IsRegisteredFileForWrite(const QString &file)
int GetBackendServerPort(void)
Returns the locally defined backend control port.
QString GetSettingOnHost(const QString &key, const QString &host, const QString &defaultval="")
void dispatch(const MythEvent &event)
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
int GetNumSetting(const QString &key, int defaultval=0)
QString GetBackendServerIP(void)
Returns the IP address of the locally defined backend IP.
QString GetMasterHostName(void)
void SendEvent(const MythEvent &event)
bool GetBoolSetting(const QString &key, bool defaultval=false)
static void DBError(const QString &where, const MSqlQuery &query)
void queueDownload(const QString &url, const QString &dest, QObject *caller, bool reload=false)
Adds a url to the download queue.
This class is used as a container for messages.
int ExtraDataCount() const
const QString & Message() const
const QString & ExtraData(int idx=0) const
static const Type kMythEventMessage
void addListener(QObject *listener)
Add a listener to the observable.
void removeListener(QObject *listener)
Remove a listener to the observable.
void newConnection(qintptr socket)
virtual void error(MythSocket *, int)
Class for communcating between myth backends and frontends.
bool ReadStringList(QStringList &list, std::chrono::milliseconds timeoutMS=kShortTimeout)
bool IsConnected(void) const
bool IsDataAvailable(void)
int GetSocketDescriptor(void) const
void DisconnectFromHost(void)
bool WriteStringList(const QStringList &list)
QHostAddress GetPeerAddress(void) const
static MythSystem * Create(const QStringList &args, uint flags=kMSNone, const QString &startPath=QString(), Priority cpuPriority=kInheritPriority, Priority diskPriority=kInheritPriority)
A QElapsedTimer based timer to replace use of QTime as a timer.
std::chrono::milliseconds restart(void)
Returns milliseconds elapsed since last start() or restart() and resets the count.
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
void start(void)
starts measuring elapsed time.
QDateTime PixmapLastModified(const ProgramInfo *pginfo)
int DeleteRecording(const ProgramInfo *pginfo, bool forceMetadataDelete=false)
bool FillProgramInfo(ProgramInfo &pginfo, const QString &playbackhost)
QStringList GenPreviewPixmap(const QString &token, const ProgramInfo *pginfo)
QString GetFileHash(const QString &filename, const QString &storageGroup)
bool CheckFile(ProgramInfo *pginfo)
QStringList GetSGFileQuery(const QString &host, const QString &groupname, const QString &filename)
QStringList GetFindFile(const QString &host, const QString &filename, const QString &storageGroup, bool useRegex)
int CheckRecordingActive(const ProgramInfo *pginfo)
QStringList GetSGFileList(const QString &host, const QString &groupname, const QString &directory, bool fileNamesOnly)
QStringList ForwardRequest(const QStringList &slist)
MythSocket * getSocket(void) const
int StopRecording(const ProgramInfo *pginfo)
static void GetPreviewImage(const ProgramInfo &pginfo, const QString &token)
Submit a request for the generation of a preview image.
static void CreatePreviewGeneratorQueue(PreviewGenerator::Mode mode, uint maxAttempts, std::chrono::seconds minBlockSeconds)
Create the singleton queue of preview generators.
static void AddListener(QObject *listener)
Request notifications when a preview event is generated.
static void RemoveListener(QObject *listener)
Stop receiving notifications when a preview event is generated.
static void TeardownPreviewGeneratorQueue()
Destroy the singleton queue of preview generators.
Holds information on recordings and videos.
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
QString GetBasename(void) const
bool HasPathname(void) const
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
void UpdateInUseMark(bool force=false)
QString GetRecordingGroup(void) const
void SaveAutoExpire(AutoExpireType autoExpire, bool updateDelete=false)
Set "autoexpire" field in "recorded" table to "autoExpire".
uint GetRecordingID(void) const
bool IsSameProgram(const ProgramInfo &other) const
Checks whether this is the same program as "other", which may or may not be a repeat or on another ch...
void SetRecordingStatus(RecStatus::Type status)
void QueryCommBreakList(frm_dir_map_t &frames) const
QString GetHostname(void) const
virtual void SetFilesize(uint64_t sz)
void UpdateLastDelete(bool setTime) const
Set or unset the record.last_delete field.
void SendDeletedEvent(void) const
Sends event out that the ProgramInfo should be delete from lists.
QString GetTitle(void) const
void MarkAsInUse(bool inuse, const QString &usedFor="")
Tracks a recording's in use status, to prevent deletion and to allow the storage scheduler to perform...
static QMap< QString, bool > QueryJobsRunning(int type)
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
bool QueryCutList(frm_dir_map_t &delMap, bool loadAutosave=false) const
void SetChanID(uint _chanid)
QString MakeUniqueKey(void) const
Creates a unique string that can be used to identify an existing recording.
QString GetPathname(void) const
virtual uint64_t GetFilesize(void) const
void ToStringList(QStringList &list) const
Serializes ProgramInfo into a QStringList which can be passed over a socket.
bool IsWatched(void) const
static QMap< QString, uint32_t > QueryInUseMap(void)
uint64_t QueryBookmark(void) const
Gets any bookmark position in database, unless the ignore bookmark flag is set.
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
void SaveBookmark(uint64_t frame)
Clears any existing bookmark in DB and if frame is greater than 0 sets a new bookmark.
void SaveDeletePendingFlag(bool deleteFlag)
Set "deletepending" field in "recorded" table to "deleteFlag".
void SetPathname(const QString &pn)
Holds information on a TV Program one might wish to record.
void ForgetHistory(void)
Forget the recording of a program so it will be recorded again.
void ApplyRecordRecGroupChange(const QString &newrecgroup)
Sets the recording group, both in this RecordingInfo and in the database.
uint64_t GetFilesize(void) const override
Internal representation of a recording rule, mirrors the record table.
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
virtual int IncrRef(void)
Increments reference count.
static QMutex s_renamelock
void SlaveConnected(const RecordingList &slavelist)
bool GetAllPending(RecList &retList, int recRuleId=0) const
void AddChildInput(uint parentid, uint childid)
void FillRecordListFromDB(uint recordid=0)
void ReschedulePlace(const QString &why)
void RescheduleCheck(const RecordingInfo &recinfo, const QString &why)
static void GetAllScheduled(QStringList &strList, SchedSortColumn sortBy=kSortTitle, bool ascending=true)
Returns all scheduled programs serialized into a QStringList.
void getConflicting(RecordingInfo *pginfo, QStringList &strlist)
RecStatus::Type GetRecStatus(const ProgramInfo &pginfo)
void RescheduleMatch(uint recordid, uint sourceid, uint mplexid, const QDateTime &maxstarttime, const QString &why)
void Reschedule(const QStringList &request)
void SlaveDisconnected(uint cardid)
QMap< QString, ProgramInfo * > GetRecording(void) const override
void GetNextLiveTVDir(uint cardid)
void AddRecording(const RecordingInfo &pi)
void SetMainServer(MainServer *ms)
void UpdateRecStatus(RecordingInfo *pginfo)
static QList< QHostAddress > DefaultListen(void)
bool listen(QList< QHostAddress > addrs, quint16 port, bool requireall=true, PoolServerType type=kTCPServer)
void setProxy(const QNetworkProxy &proxy)
void Init(const QString &group="Default", const QString &hostname="", bool allowFallback=true)
Initilizes the groupname, hostname, and dirlist.
QStringList GetFileInfo(const QString &filename)
QString FindFile(const QString &filename)
QStringList GetFileInfoList(const QString &Path)
QString FindNextDirMostFree(void)
QStringList GetFileList(const QString &Path, bool recursive=false)
static QString GetRelativePathname(const QString &filename)
Returns the relative pathname of a file by comparing the filename against all Storage Group directori...
This is the coordinating class of the Recorder Subsystem.
static QReadWriteLock s_inputsLock
@ GENERIC_EXIT_SOCKET_ERROR
Socket error.
QString GetPlaybackURL(ProgramInfo *pginfo, bool storePath)
QVector< FileSystemInfo > FileSystemInfoList
Manages a collection of images.
static const iso6937table * d
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
LogLevel_t logLevelGet(const QString &level)
Map a log level name back to the enumerated value.
void logPropagateCalc(void)
Generate the logPropagateArgs global with the latest logging level, mask, etc to propagate to all of ...
static QString make_safe(const QString &str)
static constexpr std::chrono::milliseconds PRT_TIMEOUT
Milliseconds to wait for an existing thread from process request thread pool.
static constexpr int PRT_STARTUP_THREAD_COUNT
Number of threads in process request thread pool at startup.
static bool comp_livetvorder(const InputInfo &a, const InputInfo &b)
static QString cleanup(const QString &str)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QString GetShareDir(void)
QString GetAppBinDir(void)
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
bool getMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
Returns memory statistics in megabytes.
loadArray getLoadAvgs(void)
Returns the system load averages.
bool MythRemoveDirectory(QDir &aDir)
bool getUptime(std::chrono::seconds &uptime)
Returns uptime statistics.
QString getSymlinkTarget(const QString &start_file, QStringList *intermediaries, unsigned maxLinks)
QString FileHash(const QString &filename)
std::array< double, 3 > loadArray
Convenience inline random number generator functions.
std::deque< RecordingInfo * > RecList
@ kMSDontBlockInputDevs
avoid blocking LIRC & Joystick Menu
@ kMSProcessEvents
process events while waiting
@ kMSRunBackground
run child in the background
@ kMSDontDisableDrawing
avoid disabling UI drawing
@ kMSAutoCleanup
automatically delete if backgrounded
void SendMythSystemPlayEvent(const QString &msg, const ProgramInfo *pginfo)
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
MBASE_PUBLIC QStringList ToStringList(const FileSystemInfoList &fsInfos)
MBASE_PUBLIC FileSystemInfoList FromStringList(const QStringList &list)
MBASE_PUBLIC void Consolidate(FileSystemInfoList &disks, bool merge, int64_t fuzz, const QString &total_name={})
QString current_iso_string(bool stripped)
Returns current Date and Time in UTC as a string.
std::chrono::seconds secsInPast(const QDateTime &past)
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(int64_t seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
uint32_t MythRandom()
generate 32 random bits
int calc_utc_offset(void)
QString getTimeZoneID(void)
Returns the zoneinfo time zone ID or as much time zone information as possible.
bool delete_file_immediately(const QString &filename, bool followLinks, bool checkexists)
bool LoadFromRecorded(ProgramList &destination, bool possiblyInProgressRecordingsOnly, const QMap< QString, uint32_t > &inUseMap, const QMap< QString, bool > &isJobRunning, const QMap< QString, ProgramInfo * > &recMap, int sort, const QString &sortBy, bool ignoreLiveTV, bool ignoreDeleted)
static constexpr int8_t NUMPROGRAMLINES
bool LoadFromScheduler(AutoDeleteDeque< TYPE * > &destination, bool &hasConflicts, const QString &altTable="", int recordid=-1)
const QString kTruncatingDeleteInUseID
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.
static QString fs1(QT_TRANSLATE_NOOP("SchedFilterEditor", "Identifiable episode"))
BrowseDirection
Used to request ProgramInfo for channel browsing.
ChannelChangeDirection
ChannelChangeDirection is an enumeration of possible channel changing directions.
@ kState_RecordingOnly
Recording Only is a TVRec only state for when we are recording a program, but there is no one current...
@ kState_WatchingLiveTV
Watching LiveTV is the state for when we are watching a recording and the user has control over the c...
@ kState_Error
Error State, if we ever try to enter this state errored is set.
@ kState_WatchingRecording
Watching Recording is the state for when we are watching an in progress recording,...
@ kState_ChangingState
This is a placeholder state which we never actually enter, but is returned by GetState() when we are ...
@ kPictureAttribute_Contrast
@ kPictureAttribute_Brightness
@ kPictureAttribute_Colour