15#include "libmythbase/mythconfig.h"
18#if QT_VERSION >= QT_VERSION_CHECK(6,0,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)
1059 if (listline.size() >= 2)
1060 halt_cmd = listline[1];
1062 if (!halt_cmd.isEmpty())
1064 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
1065 "Going down now as of Mainserver request!");
1074 else if (command ==
"BACKEND_MESSAGE")
1076 const QString& message = listline[1];
1077 QStringList extra( listline[2] );
1078 for (
int i = 3; i < listline.size(); i++)
1079 extra << listline[i];
1083 else if ((command ==
"DOWNLOAD_FILE") ||
1084 (command ==
"DOWNLOAD_FILE_NOW"))
1086 if (listline.size() != 4)
1091 else if (command ==
"REFRESH_BACKEND")
1093 LOG(VB_GENERAL, LOG_INFO ,
LOC +
"Reloading backend settings");
1096 else if (command ==
"OK")
1098 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Got 'OK' out of sequence.");
1100 else if (command ==
"UNKNOWN_COMMAND")
1102 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Got 'UNKNOWN_COMMAND' out of sequence.");
1106 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unknown command: " + command);
1110 QStringList strlist;
1111 strlist <<
"UNKNOWN_COMMAND";
1124 QStringList broadcast;
1125 QSet<QString> receivers;
1143 auto *me =
dynamic_cast<MythEvent *
>(e);
1147 QString message = me->
Message();
1149 if ((message ==
"PREVIEW_SUCCESS" || message ==
"PREVIEW_QUEUED") &&
1150 me->ExtraDataCount() >= 5)
1153 uint recordingID = me->ExtraData(0).toUInt();
1154 const QString&
filename = me->ExtraData(1);
1155 const QString& msg = me->ExtraData(2);
1156 const QString& datetime = me->ExtraData(3);
1158 if (message ==
"PREVIEW_QUEUED")
1160 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1161 QString(
"Preview Queued: '%1' '%2'")
1167 ok = ok &&
file.open(QIODevice::ReadOnly);
1171 QByteArray data =
file.readAll();
1172 QStringList extra(
"OK");
1173 extra.push_back(QString::number(recordingID));
1174 extra.push_back(msg);
1175 extra.push_back(datetime);
1176 extra.push_back(QString::number(data.size()));
1177#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1178 quint16 checksum = qChecksum(data.constData(), data.size());
1180 quint16 checksum = qChecksum(data);
1182 extra.push_back(QString::number(checksum));
1183 extra.push_back(QString(data.toBase64()));
1185 for (
uint i = 4 ; i < (
uint) me->ExtraDataCount(); i++)
1187 const QString& token = me->ExtraData(i);
1188 extra.push_back(token);
1192 receivers.insert(*it);
1197 if (receivers.empty())
1199 LOG(VB_GENERAL, LOG_ERR,
LOC +
1200 "PREVIEW_SUCCESS but no receivers.");
1204 broadcast.push_back(
"BACKEND_MESSAGE");
1205 broadcast.push_back(
"GENERATED_PIXMAP");
1210 message =
"PREVIEW_FAILED";
1216 if (message ==
"PREVIEW_FAILED" && me->ExtraDataCount() >= 5)
1218 const QString& pginfokey = me->ExtraData(0);
1219 const QString& msg = me->ExtraData(2);
1221 QStringList extra(
"ERROR");
1222 extra.push_back(pginfokey);
1223 extra.push_back(msg);
1224 for (
uint i = 4 ; i < (
uint) me->ExtraDataCount(); i++)
1226 const QString& token = me->ExtraData(i);
1227 extra.push_back(token);
1231 receivers.insert(*it);
1236 if (receivers.empty())
1238 LOG(VB_GENERAL, LOG_ERR,
LOC +
1239 "PREVIEW_FAILED but no receivers.");
1243 broadcast.push_back(
"BACKEND_MESSAGE");
1244 broadcast.push_back(
"GENERATED_PIXMAP");
1248 if (me->Message().startsWith(
"AUTO_EXPIRE"))
1250 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1251 if (tokens.size() != 3)
1253 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad AUTO_EXPIRE message");
1277 QString msg = QString(
"Cannot find program info for '%1', "
1278 "while attempting to Auto-Expire.")
1279 .arg(me->Message());
1280 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
1286 if (me->Message().startsWith(
"QUERY_NEXT_LIVETV_DIR") &&
m_sched)
1288 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1289 if (tokens.size() != 2)
1291 LOG(VB_GENERAL, LOG_ERR,
LOC +
1292 QString(
"Bad %1 message").arg(tokens[0]));
1300 if (me->Message().startsWith(
"STOP_RECORDING"))
1302 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1303 if (tokens.size() < 3 || tokens.size() > 3)
1305 LOG(VB_GENERAL, LOG_ERR,
LOC +
1306 QString(
"Bad STOP_RECORDING message: %1")
1307 .arg(me->Message()));
1320 LOG(VB_GENERAL, LOG_ERR,
LOC +
1321 QString(
"Cannot find program info for '%1' while "
1322 "attempting to stop recording.").arg(me->Message()));
1328 if ((me->Message().startsWith(
"DELETE_RECORDING")) ||
1329 (me->Message().startsWith(
"FORCE_DELETE_RECORDING")))
1331 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1332 if (tokens.size() < 3 || tokens.size() > 5)
1334 LOG(VB_GENERAL, LOG_ERR,
LOC +
1335 QString(
"Bad %1 message").arg(tokens[0]));
1339 bool force = (tokens.size() >= 4) && (tokens[3] ==
"FORCE");
1340 bool forget = (tokens.size() >= 5) && (tokens[4] ==
"FORGET");
1347 if (tokens[0] ==
"FORCE_DELETE_RECORDING")
1354 LOG(VB_GENERAL, LOG_ERR,
LOC +
1355 QString(
"Cannot find program info for '%1' while "
1356 "attempting to delete.").arg(me->Message()));
1362 if (me->Message().startsWith(
"UNDELETE_RECORDING"))
1364 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1365 if (tokens.size() < 3 || tokens.size() > 3)
1367 LOG(VB_GENERAL, LOG_ERR,
LOC +
1368 QString(
"Bad UNDELETE_RECORDING message: %1")
1369 .arg(me->Message()));
1382 LOG(VB_GENERAL, LOG_ERR,
LOC +
1383 QString(
"Cannot find program info for '%1' while "
1384 "attempting to undelete.").arg(me->Message()));
1390 if (me->Message().startsWith(
"ADD_CHILD_INPUT"))
1392 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1395 LOG(VB_GENERAL, LOG_ERR,
LOC +
1396 "ADD_CHILD_INPUT event received in slave context");
1398 else if (tokens.size() != 2)
1400 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad ADD_CHILD_INPUT message");
1409 if (me->Message().startsWith(
"RESCHEDULE_RECORDINGS") &&
m_sched)
1411 const QStringList& request = me->ExtraDataList();
1416 if (me->Message().startsWith(
"SCHEDULER_ADD_RECORDING") &&
m_sched)
1421 LOG(VB_GENERAL, LOG_ERR,
LOC +
1422 "Bad SCHEDULER_ADD_RECORDING message");
1430 if (me->Message().startsWith(
"UPDATE_RECORDING_STATUS") &&
m_sched)
1432 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1433 if (tokens.size() != 6)
1435 LOG(VB_GENERAL, LOG_ERR,
LOC +
1436 "Bad UPDATE_RECORDING_STATUS message");
1440 uint cardid = tokens[1].toUInt();
1441 uint chanid = tokens[2].toUInt();
1446 recstatus, recendts);
1452 if (me->Message().startsWith(
"LIVETV_EXITED"))
1454 const QString& chainid = me->ExtraData();
1462 if (me->Message() ==
"CLEAR_SETTINGS_CACHE")
1465 if (me->Message().startsWith(
"RESET_IDLETIME") &&
m_sched)
1468 if (me->Message() ==
"LOCAL_RECONNECT_TO_MASTER")
1471 if (me->Message() ==
"LOCAL_SLAVE_BACKEND_ENCODERS_OFFLINE")
1474 if (me->Message().startsWith(
"LOCAL_"))
1477 if (me->Message() ==
"CREATE_THUMBNAILS")
1480 if (me->Message() ==
"IMAGE_GET_METADATA")
1483 std::unique_ptr<MythEvent> mod_me {
nullptr};
1484 if (me->Message().startsWith(
"MASTER_UPDATE_REC_INFO"))
1486 QStringList tokens = me->Message().simplified().split(
" ");
1487 uint recordedid = 0;
1488 if (tokens.size() >= 2)
1489 recordedid = tokens[1].toUInt();
1490 if (recordedid == 0)
1504 mod_me = std::make_unique<MythEvent>(
"RECORDING_LIST_CHANGE UPDATE", list);
1512 if (me->Message().startsWith(
"DOWNLOAD_FILE"))
1514 QStringList extraDataList = me->ExtraDataList();
1515 QString localFile = extraDataList[1];
1516 QFile
file(localFile);
1517 QStringList tokens = me->Message().simplified().split(
" ");
1525 if ((tokens.size() >= 2) && (tokens[1] ==
"FINISHED"))
1528 mod_me = std::make_unique<MythEvent>(me->Message(), extraDataList);
1531 if (broadcast.empty())
1533 broadcast.push_back(
"BACKEND_MESSAGE");
1534 if (mod_me !=
nullptr)
1536 broadcast.push_back(mod_me->Message());
1537 broadcast += mod_me->ExtraDataList();
1541 broadcast.push_back(me->Message());
1542 broadcast += me->ExtraDataList();
1547 if (!broadcast.empty())
1550 std::vector<PlaybackSock *> localPBSList;
1555 localPBSList.push_back(
pbs);
1559 bool sendGlobal =
false;
1560 if (
m_ismaster && broadcast[1].startsWith(
"GLOBAL_"))
1562 broadcast[1].replace(
"GLOBAL_",
"LOCAL_");
1563 MythEvent me(broadcast[1], broadcast[2]);
1569 QSet<PlaybackSock*> sentSet;
1571 bool isSystemEvent = broadcast[1].startsWith(
"SYSTEM_EVENT ");
1574 std::vector<PlaybackSock*>::const_iterator iter;
1575 for (iter = localPBSList.begin(); iter != localPBSList.end(); ++iter)
1579 if (sentSet.contains(
pbs) ||
pbs->IsDisconnected())
1582 if (!receivers.empty() && !receivers.contains(
pbs->getHostname()))
1585 sentSet.insert(
pbs);
1587 bool reallysendit =
false;
1589 if (broadcast[1] ==
"CLEAR_SETTINGS_CACHE")
1592 (
pbs->isSlaveBackend() ||
pbs->wantsEvents()))
1593 reallysendit =
true;
1595 else if (sendGlobal)
1597 if (
pbs->isSlaveBackend())
1598 reallysendit =
true;
1600 else if (
pbs->wantsEvents())
1602 reallysendit =
true;
1609 if (!
pbs->wantsSystemEvents())
1613 if (!
pbs->wantsOnlySystemEvents())
1615 if (sentSetSystemEvent.contains(
pbs->getHostname()))
1618 sentSetSystemEvent <<
pbs->getHostname();
1621 else if (
pbs->wantsOnlySystemEvents())
1633 for (iter = localPBSList.begin(); iter != localPBSList.end(); ++iter)
1651 QStringList retlist;
1652 const QString&
version = slist[1];
1653 if (
version != MYTH_PROTO_VERSION)
1655 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1656 "MainServer::HandleVersion - Client speaks protocol version " +
1657 version +
" but we speak " + MYTH_PROTO_VERSION +
'!');
1658 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1664 if (slist.size() < 3)
1666 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1667 "MainServer::HandleVersion - Client did not pass protocol "
1668 "token. Refusing connection!");
1669 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1675 const QString& token = slist[2];
1676 if (token != QString::fromUtf8(MYTH_PROTO_TOKEN))
1678 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1679 QString(
"MainServer::HandleVersion - Client sent incorrect "
1680 "protocol token \"%1\" for protocol version. Refusing "
1681 "connection!").arg(token));
1682 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1688 retlist <<
"ACCEPT" << MYTH_PROTO_VERSION;
1717 QStringList retlist(
"OK" );
1718 QStringList errlist(
"ERROR" );
1720 if (commands.size() < 3 || commands.size() > 6)
1723 if (commands.size() == 2)
1724 info = QString(
" %1").arg(commands[1]);
1726 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Received malformed ANN%1 query")
1729 errlist <<
"malformed_ann_query";
1737 if (
pbs->getSocket() == socket)
1739 LOG(VB_GENERAL, LOG_WARNING,
LOC +
1740 QString(
"Client %1 is trying to announce a socket "
1750 if (commands[1] ==
"Playback" || commands[1] ==
"Monitor" ||
1751 commands[1] ==
"Frontend")
1753 if (commands.size() < 4)
1755 LOG(VB_GENERAL, LOG_ERR,
LOC +
1756 QString(
"Received malformed ANN %1 query")
1759 errlist <<
"malformed_ann_query";
1776 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"MainServer::ANN %1")
1778 LOG(VB_GENERAL, LOG_INFO,
LOC +
1779 QString(
"adding: %1(%2) as a client (events: %3)")
1781 .arg(quintptr(socket),0,16)
1783 pbs->setBlockShutdown((commands[1] ==
"Playback") ||
1784 (commands[1] ==
"Frontend"));
1786 if (commands[1] ==
"Frontend")
1788 pbs->SetAsFrontend();
1790 frontend->m_name = commands[2];
1805 else if (commands[1] ==
"MediaServer")
1807 if (commands.size() < 3)
1809 LOG(VB_GENERAL, LOG_ERR,
LOC +
1810 "Received malformed ANN MediaServer query");
1811 errlist <<
"malformed_ann_query";
1820 pbs->setAsMediaServer();
1821 pbs->setBlockShutdown(
false);
1826 QString(
"CLIENT_CONNECTED HOSTNAME %1").arg(commands[2]));
1828 else if (commands[1] ==
"SlaveBackend")
1830 if (commands.size() < 4)
1832 LOG(VB_GENERAL, LOG_ERR,
LOC +
1833 QString(
"Received malformed ANN %1 query")
1835 errlist <<
"malformed_ann_query";
1847 LOG(VB_GENERAL, LOG_INFO,
LOC +
1848 QString(
"adding: %1 as a slave backend server")
1850 pbs->setAsSlaveBackend();
1851 pbs->setIP(commands[3]);
1856 QStringList::const_iterator sit = slist.
cbegin()+1;
1857 while (sit != slist.cend())
1860 if (!recinfo->GetChanID())
1870 bool wasAsleep =
true;
1874 if (elink->GetHostName() == commands[2])
1876 if (! (elink->IsWaking() || elink->IsAsleep()))
1878 elink->SetSocket(
pbs);
1886 QString message = QString(
"LOCAL_SLAVE_BACKEND_ONLINE %2")
1891 pbs->setBlockShutdown(
false);
1896 QString(
"SLAVE_CONNECTED HOSTNAME %1").arg(commands[2]));
1898 else if (commands[1] ==
"FileTransfer")
1900 if (slist.size() < 3)
1902 LOG(VB_GENERAL, LOG_ERR,
LOC +
1903 "Received malformed FileTransfer command");
1904 errlist <<
"malformed_filetransfer_command";
1909 LOG(VB_NETWORK, LOG_INFO,
LOC +
1910 "MainServer::HandleAnnounce FileTransfer");
1911 LOG(VB_NETWORK, LOG_INFO,
LOC +
1912 QString(
"adding: %1 as a remote file transfer") .arg(commands[2]));
1913 QStringList::const_iterator it = slist.cbegin();
1914 QString path = *(++it);
1915 QString wantgroup = *(++it);
1917 QStringList checkfiles;
1919 for (++it; it != slist.cend(); ++it)
1923 bool writemode =
false;
1924 bool usereadahead =
true;
1925 std::chrono::milliseconds timeout_ms = 2s;
1926 if (commands.size() > 3)
1927 writemode = (commands[3].toInt() != 0);
1929 if (commands.size() > 4)
1930 usereadahead = (commands[4].toInt() != 0);
1932 if (commands.size() > 5)
1933 timeout_ms = std::chrono::milliseconds(commands[5].toInt());
1937 if (wantgroup.isEmpty())
1938 wantgroup =
"Default";
1944 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to determine directory "
1945 "to write to in FileTransfer write command");
1946 errlist <<
"filetransfer_directory_not_found";
1953 LOG(VB_GENERAL, LOG_ERR,
LOC +
1954 QString(
"FileTransfer write filename is empty in path '%1'.")
1956 errlist <<
"filetransfer_filename_empty";
1961 if ((path.contains(
"/../")) ||
1962 (path.startsWith(
"../")))
1964 LOG(VB_GENERAL, LOG_ERR,
LOC +
1965 QString(
"FileTransfer write filename '%1' does not pass "
1966 "sanity checks.") .arg(path));
1967 errlist <<
"filetransfer_filename_dangerous";
1981 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Empty filename, cowardly aborting!");
1982 errlist <<
"filetransfer_filename_empty";
1991 LOG(VB_GENERAL, LOG_ERR,
LOC +
1992 QString(
"FileTransfer filename '%1' is actually a directory, "
1993 "cannot transfer.") .arg(
filename));
1994 errlist <<
"filetransfer_filename_is_a_directory";
2001 QString dirPath = finfo.absolutePath();
2005 if (!qdir.mkpath(dirPath))
2007 LOG(VB_GENERAL, LOG_ERR,
LOC +
2008 QString(
"FileTransfer filename '%1' is in a "
2009 "subdirectory which does not exist, and can "
2010 "not be created.") .arg(
filename));
2011 errlist <<
"filetransfer_unable_to_create_subdirectory";
2031 LOG(VB_GENERAL, LOG_ERR,
LOC +
2032 QString(
"Can't open %1").arg(
filename));
2033 errlist <<
"filetransfer_unable_to_open_file";
2040 LOG(VB_GENERAL, LOG_INFO,
LOC +
2041 QString(
"adding: %1(%2) as a file transfer")
2043 .arg(quintptr(socket),0,16));
2053 if (!checkfiles.empty())
2056 QDir dir = fi.absoluteDir();
2057 for (
const auto &
file : std::as_const(checkfiles))
2059 if (dir.exists(
file) &&
2060 ((
file).endsWith(
".srt") ||
2093 QStringList strList(
"ERROR");
2108 bool do_write =
false;
2123 LOG(VB_GENERAL, LOG_ERR,
LOC +
2124 "SendResponse: Unable to write to client socket, as it's no "
2140 QString playbackhost =
pbs->getHostname();
2142 QMap<QString,ProgramInfo*> recMap;
2147 QMap<QString,bool> isJobRunning =
2153 if ((
type ==
"Ascending") || (
type ==
"Play"))
2155 else if ((
type ==
"Descending") || (
type ==
"Delete"))
2160 destination, (
type ==
"Recording"),
2161 inUseMap, isJobRunning, recMap, sort);
2163 QMap<QString,ProgramInfo*>::iterator mit = recMap.begin();
2164 for (; mit != recMap.end(); mit = recMap.erase(mit))
2167 QStringList outputlist(QString::number(destination.
size()));
2168 QMap<QString, int> backendPortMap;
2172 for (
auto* proginfo : destination)
2183 proginfo->GetBasename()));
2184 if (!proginfo->GetFilesize())
2187 if (tmpURL.startsWith(
'/'))
2189 QFile checkFile(tmpURL);
2190 if (!tmpURL.isEmpty() && checkFile.exists())
2192 proginfo->SetFilesize(checkFile.size());
2193 if (proginfo->GetRecordingEndTime() <
2196 proginfo->SaveFilesize(proginfo->GetFilesize());
2205 if (proginfo->GetPathname().isEmpty())
2207 LOG(VB_GENERAL, LOG_ERR,
LOC +
2208 QString(
"HandleQueryRecordings() "
2209 "Couldn't find backend for:\n\t\t\t%1")
2212 proginfo->SetFilesize(0);
2213 proginfo->SetPathname(
"file not found");
2218 if (!proginfo->GetFilesize())
2222 LOG(VB_GENERAL, LOG_ERR,
LOC +
2223 "MainServer::HandleQueryRecordings()"
2224 "\n\t\t\tCould not fill program info "
2229 if (proginfo->GetRecordingEndTime() <
2232 proginfo->SaveFilesize(proginfo->GetFilesize());
2241 if (!backendPortMap.contains(
hostname))
2253 proginfo->ToStringList(outputlist);
2266 if (slist.size() < 3)
2268 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad QUERY_RECORDING query");
2273 QString command = slist[1].toUpper();
2276 if (command ==
"BASENAME")
2280 else if (command ==
"TIMESLOT")
2282 if (slist.size() < 4)
2284 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad QUERY_RECORDING query");
2289 pginfo =
new ProgramInfo(slist[2].toUInt(), recstartts);
2292 QStringList strlist;
2313 const QString& playbackhost = slist[1];
2315 QStringList::const_iterator it = slist.cbegin() + 2;
2330 const QFileInfo
info(lpath);
2334 QStringList strlist;
2352 std::this_thread::sleep_for(3s + std::chrono::microseconds(
MythRandom(0, 2000)));
2357 QString logInfo = QString(
"recording id %1 (chanid %2 at %3)")
2362 QString name = QString(
"deleteThread%1%2").arg(getpid()).arg(
MythRandom());
2368 QString msg = QString(
"ERROR opening database connection for Delete "
2369 "Thread for chanid %1 recorded at %2. Program "
2370 "will NOT be deleted.")
2373 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2383 QString msg = QString(
"ERROR retrieving program info when trying to "
2384 "delete program for chanid %1 recorded at %2. "
2385 "Recording will NOT be deleted.")
2388 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2398 if ((!checkFile.exists()) && pginfo.
GetFilesize() &&
2401 LOG(VB_GENERAL, LOG_ERR,
LOC +
2402 QString(
"ERROR when trying to delete file: %1. File "
2403 "doesn't exist. Database metadata will not be removed.")
2421 bool errmsg =
false;
2436 if ((fd < 0) && checkFile.exists())
2442 std::this_thread::sleep_for(2s);
2443 if (checkFile.exists())
2449 LOG(VB_GENERAL, LOG_ERR,
LOC +
2450 QString(
"Error deleting file: %1. Keeping metadata in database.")
2465 QStringList nameFilters;
2466 nameFilters.push_back(fInfo.fileName() +
"*.png");
2467 nameFilters.push_back(fInfo.fileName() +
"*.jpg");
2468 nameFilters.push_back(fInfo.fileName() +
".tmp");
2469 nameFilters.push_back(fInfo.fileName() +
".old");
2470 nameFilters.push_back(fInfo.fileName() +
".map");
2471 nameFilters.push_back(fInfo.fileName() +
".tmp.map");
2472 nameFilters.push_back(fInfo.baseName() +
".srt");
2474 QDir dir (fInfo.path());
2475 QFileInfoList miscFiles = dir.entryInfoList(nameFilters);
2477 for (
const auto &
file : std::as_const(miscFiles))
2479 QString sFileName =
file.absoluteFilePath();
2491 if (slowDeletes && fd >= 0)
2497 QString logInfo = QString(
"recording id %1 filename %2")
2500 LOG(VB_GENERAL, LOG_NOTICE,
"DeleteRecordedFiles - " + logInfo);
2504 query.
prepare(
"SELECT basename, hostname, storagegroup FROM recordedfile "
2505 "WHERE recordedid = :RECORDEDID;");
2508 if (!query.
exec() || !query.
size())
2511 LOG(VB_GENERAL, LOG_ERR,
LOC +
2512 QString(
"Error querying recordedfiles for %1.") .arg(logInfo));
2515 while (query.
next())
2517 QString basename = query.
value(0).toString();
2520 bool deleteInDB =
false;
2522 if (basename == QFileInfo(ds->
m_filename).fileName())
2551 update.
prepare(
"DELETE FROM recordedfile "
2552 "WHERE recordedid = :RECORDEDID "
2553 "AND basename = :BASENAME ;");
2555 update.
bindValue(
":BASENAME", basename);
2559 LOG(VB_GENERAL, LOG_ERR,
LOC +
2560 QString(
"Error querying recordedfile (%1) for %2.")
2561 .arg(query.
value(1).toString(), logInfo));
2569 QString logInfo = QString(
"recording id %1 (chanid %2 at %3)")
2573 LOG(VB_GENERAL, LOG_NOTICE,
"DoDeleteINDB - " + logInfo);
2576 query.
prepare(
"DELETE FROM recorded WHERE recordedid = :RECORDEDID AND "
2581 if (!query.
exec() || !query.
size())
2584 LOG(VB_GENERAL, LOG_ERR,
LOC +
2585 QString(
"Error deleting recorded entry for %1.") .arg(logInfo));
2588 std::this_thread::sleep_for(1s);
2591 QString msg = QString(
"RECORDING_LIST_CHANGE DELETE %1")
2596 std::this_thread::sleep_for(3s);
2598 query.
prepare(
"DELETE FROM recordedmarkup "
2599 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2606 LOG(VB_GENERAL, LOG_ERR,
LOC +
2607 QString(
"Error deleting recordedmarkup for %1.") .arg(logInfo));
2610 query.
prepare(
"DELETE FROM recordedseek "
2611 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2618 LOG(VB_GENERAL, LOG_ERR,
LOC +
2619 QString(
"Error deleting recordedseek for %1.")
2634 bool deleteBrokenSymlinks)
2638 QString linktext =
"";
2639 QByteArray fname =
filename.toLocal8Bit();
2642 LOG(VB_FILE, LOG_INFO,
LOC +
2643 QString(
"About to unlink/delete file: '%1'")
2644 .arg(fname.constData()));
2646 QString errmsg = QString(
"Delete Error '%1'").arg(fname.constData());
2647 if (finfo.isSymLink())
2650 QByteArray alink = linktext.toLocal8Bit();
2651 errmsg += QString(
" -> '%2'").arg(alink.constData());
2654 if (followLinks && finfo.isSymLink())
2656 if (!finfo.exists() && deleteBrokenSymlinks)
2657 unlink(fname.constData());
2663 unlink(fname.constData());
2666 else if (!finfo.isSymLink())
2673 int err = unlink(fname.constData());
2678 if (fd < 0 && open_errno != EISDIR)
2679 LOG(VB_GENERAL, LOG_ERR,
LOC + errmsg +
ENO);
2695 QByteArray fname =
filename.toLocal8Bit();
2696 QString msg = QString(
"Error deleting '%1'").arg(fname.constData());
2697 int fd = open(fname.constData(), O_WRONLY);
2701 if (errno == EISDIR)
2706 LOG(VB_GENERAL, LOG_ERR, msg +
" could not delete directory " +
ENO);
2712 LOG(VB_GENERAL, LOG_ERR, msg +
" could not open " +
ENO);
2716 else if (unlink(fname.constData()))
2718 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
" could not unlink " +
ENO);
2735 const QString &
filename, off_t fsize)
2748 query.
prepare(
"SELECT COUNT(cardid) FROM capturecard;");
2750 cards = query.
value(0).toInt();
2754 constexpr std::chrono::milliseconds sleep_time = 500ms;
2755 const size_t min_tps = 8LL * 1024 * 1024;
2756 const auto calc_tps = (size_t) (cards * 1.2 * (22200000LL / 8.0));
2757 const size_t tps = std::max(min_tps, calc_tps);
2758 const auto increment = (size_t) (tps * (sleep_time.count() * 0.001F));
2760 LOG(VB_FILE, LOG_INFO,
LOC +
2761 QString(
"Truncating '%1' by %2 MB every %3 milliseconds")
2763 .arg(increment / (1024.0 * 1024.0), 0,
'f', 2)
2764 .arg(sleep_time.count()));
2766 GetMythDB()->GetDBManager()->PurgeIdleConnections(
false);
2772 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"Truncating '%1' to %2 MB")
2773 .arg(
filename).arg(fsize / (1024.0 * 1024.0), 0,
'f', 2));
2776 int err = ftruncate(fd, fsize);
2779 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error truncating '%1'")
2783 return 0 ==
close(fd);
2788 if (pginfo && ((count % 100) == 0))
2793 std::this_thread::sleep_for(sleep_time);
2796 bool ok = (0 ==
close(fd));
2801 LOG(VB_FILE, LOG_INFO,
LOC +
2802 QString(
"Finished truncating '%1'").arg(
filename));
2812 pbssock =
pbs->getSocket();
2814 QStringList::const_iterator it = slist.cbegin() + 1;
2836 result = iter.key();
2841 QStringList outputlist( QString::number(result) );
2848 QStringList::const_iterator it = slist.cbegin() + 1;
2860 bool hasConflicts =
false;
2862 for (
auto *pInfo : schedList)
2880 pbssock =
pbs->getSocket();
2903 (*m_encoderList)[num]->StopRecording();
2911 QStringList outputlist(
"0" );
2936 recnum = iter.key();
2943 std::this_thread::sleep_for(100us);
2959 QStringList outputlist( QString::number(recnum) );
2966 bool forceMetadataDelete,
2974 qDebug() <<
"HandleDeleteRecording(chanid, starttime) Empty Recording ID";
2981 pbssock =
pbs->getSocket();
2983 QStringList outputlist( QString::number(0) );
2993 bool forceMetadataDelete)
2995 QStringList::const_iterator it = slist.cbegin() + 1;
3000 qDebug() <<
"HandleDeleteRecording(QStringList) Empty Recording ID";
3009 bool forceMetadataDelete,
bool lexpirer,
bool forgetHistory)
3011 int resultCode = -1;
3014 pbssock =
pbs->getSocket();
3016 bool justexpire = lexpirer ?
false :
3024 LOG(VB_GENERAL, LOG_ERR,
LOC +
3025 QString(
"ERROR when trying to delete file for %1. Unable "
3026 "to determine filename of recording.")
3032 QStringList outputlist(QString::number(resultCode));
3042 if (justexpire && !forceMetadataDelete &&
3051 QStringList outputlist( QString::number(0) );
3075 QStringList outputlist( QString::number(num) );
3085 bool fileExists = checkFile.exists();
3088 QFile checkFileUTF8(QString::fromUtf8(
filename.toLatin1().constData()));
3089 fileExists = checkFileUTF8.exists();
3098 if (fileExists || !recinfo.
GetFilesize() || forceMetadataDelete)
3104 qDebug() <<
"DoHandleDeleteRecording() Empty Recording ID";
3111 forceMetadataDelete);
3112 deleteThread->start();
3117 QString logInfo = QString(
"chanid %1")
3121 LOG(VB_GENERAL, LOG_ERR,
LOC +
3122 QString(
"ERROR when trying to delete file: %1. File doesn't "
3123 "exist. Database metadata will not be removed.")
3130 QStringList outputlist( QString::number(resultCode) );
3142 if (fileExists || !recinfo.
GetFilesize() || forceMetadataDelete)
3145 QString(
"REC_DELETED CHANID %1 STARTTIME %2")
3155 if (slist.size() == 3)
3164 QStringList::const_iterator it = slist.cbegin()+1;
3178 pbssock =
pbs->getSocket();
3192 QStringList outputlist( QString::number(ret) );
3229 result = QStringList(QString::number(1));
3233 result = QStringList(QString::number(0));
3252 LOG(VB_GENERAL, LOG_INFO,
LOC +
"HandleAddChildInput: Already locked");
3256 LOG(VB_GENERAL, LOG_INFO,
LOC +
3257 QString(
"HandleAddChildInput: Handling input %1").arg(inputid));
3267 LOG(VB_GENERAL, LOG_ERR,
LOC +
3268 QString(
"HandleAddChildInput: "
3269 "Failed to add child to input %1").arg(inputid));
3275 LOG(VB_GENERAL, LOG_INFO,
LOC +
3276 QString(
"HandleAddChildInput: Added child input %1").arg(childid));
3284 auto *tv =
new TVRec(childid);
3285 if (!tv || !tv->Init())
3287 LOG(VB_GENERAL, LOG_ERR,
LOC +
3288 QString(
"HandleAddChildInput: "
3289 "Failed to initialize input %1").arg(childid));
3298 (*m_encoderList)[childid] = enc;
3305 LOG(VB_GENERAL, LOG_ERR,
LOC +
3306 QString(
"HandleAddChildInput: "
3307 "Failed to add remote input %1").arg(childid));
3317 (*m_encoderList)[childid] = enc;
3326 auto *tv =
new TVRec(inputid);
3327 if (!tv || !tv->Init())
3329 LOG(VB_GENERAL, LOG_ERR,
LOC +
3330 QString(
"HandleAddChildInput: "
3331 "Failed to initialize input %1").arg(inputid));
3339 (*m_encoderList)[inputid] = enc;
3345 LOG(VB_GENERAL, LOG_INFO,
LOC +
3346 QString(
"HandleAddChildInput: "
3347 "Successfully handled input %1").arg(inputid));
3354 QStringList::const_iterator it = slist.cbegin() + 1;
3361 pbssock =
pbs->getSocket();
3364 QStringList outputlist( QString::number(0) );
3376 QStringList strlist;
3379 if (!sleepCmd.isEmpty())
3383 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
3384 "Received GO_TO_SLEEP command from master, running SleepCommand.");
3389 strlist <<
"ERROR: SleepCommand is empty";
3390 LOG(VB_GENERAL, LOG_ERR,
LOC +
3391 "ERROR: in HandleGoToSleep(), but no SleepCommand found!");
3407 QStringList strlist;
3441 QStringList strlist;
3460 QStringList shortlist;
3461 if (strlist.size() < 4)
3463 shortlist << QString(
"0");
3464 shortlist << QString(
"0");
3468 unsigned int index = (
uint)(strlist.size()) - 2;
3469 shortlist << strlist[index++];
3470 shortlist << strlist[index++];
3486 QStringList strlist;
3488#if defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
3489 strlist <<
"0" <<
"0" <<
"0";
3495 strlist <<
"getloadavg() failed";
3499 strlist << QString::number(loads[0])
3500 << QString::number(loads[1])
3501 << QString::number(loads[2]);
3516 QStringList strlist;
3517 std::chrono::seconds uptime = 0s;
3520 strlist << QString::number(uptime.count());
3524 strlist <<
"Could not determine uptime.";
3538 QStringList strlist;
3553 QStringList strlist;
3559 if (
getMemStats(totalMB, freeMB, totalVM, freeVM))
3561 strlist << QString::number(totalMB) << QString::number(freeMB)
3562 << QString::number(totalVM) << QString::number(freeVM);
3567 strlist <<
"Could not determine memory stats.";
3581 QStringList strlist;
3596 bool checkSlaves = slist[1].toInt() != 0;
3598 QStringList::const_iterator it = slist.cbegin() + 2;
3614 QStringList outputlist( QString::number(
static_cast<int>(
exists)) );
3634 QStringList strlist( QString::number(
static_cast<int>(
exists)) );
3646 QString storageGroup =
"Default";
3651 switch (slist.size()) {
3653 if (!slist[3].isEmpty())
3657 if (slist[2].isEmpty())
3658 storageGroup = slist[2];
3666 LOG(VB_GENERAL, LOG_ERR,
LOC +
3667 QString(
"ERROR checking for file, filename '%1' "
3668 "fails sanity checks").arg(
filename));
3675 LOG(VB_GENERAL, LOG_ERR,
LOC +
3676 "ERROR, invalid input count for QUERY_FILE_HASH");
3713 const QString&
filename = slist[1];
3714 QString storageGroup =
"Default";
3715 QStringList retlist;
3717 if (slist.size() > 2)
3718 storageGroup = slist[2];
3724 LOG(VB_GENERAL, LOG_ERR,
LOC +
3725 QString(
"ERROR checking for file, filename '%1' "
3726 "fails sanity checks").arg(
filename));
3732 if (storageGroup.isEmpty())
3733 storageGroup =
"Default";
3739 if (!fullname.isEmpty())
3742 retlist << fullname;
3744 struct stat fileinfo {};
3745 if (stat(fullname.toLocal8Bit().constData(), &fileinfo) >= 0)
3747 retlist << QString::number(fileinfo.st_dev);
3748 retlist << QString::number(fileinfo.st_ino);
3749 retlist << QString::number(fileinfo.st_mode);
3750 retlist << QString::number(fileinfo.st_nlink);
3751 retlist << QString::number(fileinfo.st_uid);
3752 retlist << QString::number(fileinfo.st_gid);
3753 retlist << QString::number(fileinfo.st_rdev);
3754 retlist << QString::number(fileinfo.st_size);
3759 retlist << QString::number(fileinfo.st_blksize);
3760 retlist << QString::number(fileinfo.st_blocks);
3762 retlist << QString::number(fileinfo.st_atime);
3763 retlist << QString::number(fileinfo.st_mtime);
3764 retlist << QString::number(fileinfo.st_ctime);
3778 query.
prepare(
"SELECT MAX(endtime) FROM program WHERE manualid = 0;");
3788 QDateTime GuideDataThrough;
3790 QStringList strlist;
3794 if (GuideDataThrough.isNull())
3795 strlist << QString(
"0000-00-00 00:00");
3797 strlist << GuideDataThrough.toString(
"yyyy-MM-dd hh:mm");
3803 const QString& tmptable,
int recordid)
3807 QStringList strList;
3811 if (tmptable.isEmpty())
3823 query.
prepare(
"SELECT NULL FROM record "
3824 "WHERE recordid = :RECID;");
3830 record->m_recordID = recordid;
3831 if (record->Load() &&
3837 query.
prepare(
"DELETE FROM program WHERE manualid = :RECID;");
3847 strList << QString::number(0);
3848 strList << QString::number(0);
3858 QStringList strList;
3863 strList << QString::number(0);
3873 QStringList::const_iterator it = slist.cbegin() + 1;
3876 QStringList strlist;
3881 strlist << QString::number(0);
3890 QStringList strList;
3895 strList << QString::number(0);
3904 QStringList strList;
3906 if ((sList.size() < 4) || (sList.size() > 5))
3908 LOG(VB_GENERAL, LOG_ERR,
LOC +
3909 QString(
"HandleSGGetFileList: Invalid Request. %1")
3910 .arg(sList.join(
"[]:[]")));
3911 strList <<
"EMPTY LIST";
3917 const QString& wantHost = sList.at(1);
3918 QHostAddress wantHostaddr(wantHost);
3919 const QString& groupname = sList.at(2);
3920 const QString& path = sList.at(3);
3921 bool fileNamesOnly =
false;
3923 if (sList.size() >= 5)
3924 fileNamesOnly = (sList.at(4).toInt() != 0);
3926 bool slaveUnreachable =
false;
3928 LOG(VB_FILE, LOG_INFO,
LOC +
3929 QString(
"HandleSGGetFileList: group = %1 host = %2 "
3930 " path = %3 wanthost = %4")
3931 .arg(groupname, host, path, wantHost));
3935 if ((host.toLower() == wantHost.toLower()) ||
3936 (!addr.isEmpty() && addr == wantHostaddr.toString()))
3939 LOG(VB_FILE, LOG_INFO,
LOC +
"HandleSGGetFileList: Getting local info");
3950 LOG(VB_FILE, LOG_INFO,
LOC +
3951 "HandleSGGetFileList: Getting remote info");
3955 slaveUnreachable =
false;
3959 LOG(VB_FILE, LOG_INFO,
LOC +
3960 QString(
"HandleSGGetFileList: Failed to grab slave socket "
3961 ": %1 :").arg(wantHost));
3962 slaveUnreachable =
true;
3967 if (slaveUnreachable)
3968 strList <<
"SLAVE UNREACHABLE: " << host;
3970 if (strList.isEmpty() || (strList.at(0) ==
"0"))
3971 strList <<
"EMPTY LIST";
3981 QString storageGroup = slist[2];
3983 bool allowFallback =
true;
3984 bool useRegex =
false;
3985 QStringList fileList;
3987 if (!QHostAddress(
hostname).isNull())
3989 LOG(VB_GENERAL, LOG_ERR, QString(
"Mainserver: QUERY_FINDFILE called "
3990 "with IP (%1) instead of hostname. "
3991 "This is invalid.").arg(
hostname));
3997 if (storageGroup.isEmpty())
3998 storageGroup =
"Default";
4003 LOG(VB_GENERAL, LOG_ERR,
LOC +
4004 QString(
"ERROR QueryFindFile, filename '%1' "
4005 "fails sanity checks").arg(
filename));
4006 fileList <<
"ERROR: Bad/Missing Filename";
4011 if (slist.size() >= 5)
4012 useRegex = (slist[4].toInt() > 0);
4014 if (slist.size() >= 6)
4015 allowFallback = (slist[5].toInt() > 0);
4017 LOG(VB_FILE, LOG_INFO,
LOC +
4018 QString(
"Looking for file '%1' on host '%2' in group '%3' (useregex: %4, allowfallback: %5")
4032 QStringList files = sgroup.
GetFileList(
'/' + fi.path());
4034 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Looking in dir '%1' for '%2'")
4035 .arg(fi.path(), fi.fileName()));
4037 for (
int x = 0; x < files.size(); x++)
4039 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Found '%1 - %2'").arg(x).arg(files[x]));
4042 QStringList filteredFiles = files.filter(QRegularExpression(fi.fileName()));
4043 for (
const QString&
file : std::as_const(filteredFiles))
4047 fi.path() +
'/' +
file,
4063 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Checking remote host '%1' for file").arg(
hostname));
4071 if (!slaveFiles.isEmpty() && slaveFiles[0] !=
"NOT FOUND" && !slaveFiles[0].startsWith(
"ERROR: "))
4072 fileList += slaveFiles;
4078 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Slave '%1' was unreachable").arg(
hostname));
4079 fileList << QString(
"ERROR: SLAVE UNREACHABLE: %1").arg(
hostname);
4087 if (
m_ismaster && fileList.isEmpty() && allowFallback)
4092 QString sql =
"SELECT DISTINCT hostname "
4093 "FROM storagegroup "
4094 "WHERE groupname = :GROUP "
4095 "AND hostname != :HOSTNAME";
4097 query.
bindValue(
":GROUP", storageGroup);
4103 fileList <<
"ERROR: failed to get host list";
4119 QStringList files = sgroup.
GetFileList(
'/' + fi.path());
4121 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Looking in dir '%1' for '%2'")
4122 .arg(fi.path(), fi.fileName()));
4124 for (
int x = 0; x < files.size(); x++)
4126 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Found '%1 - %2'").arg(x).arg(files[x]));
4129 QStringList filteredFiles = files.filter(QRegularExpression(fi.fileName()));
4131 for (
const QString&
file : std::as_const(filteredFiles))
4135 fi.path() +
'/' +
file,
4142 if (!fname.isEmpty())
4157 if (!slaveFiles.isEmpty() && slaveFiles[0] !=
"NOT FOUND" && !slaveFiles[0].startsWith(
"ERROR: "))
4158 fileList += slaveFiles;
4164 if (!fileList.isEmpty())
4169 if (fileList.isEmpty())
4171 fileList <<
"NOT FOUND";
4172 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"File was not found"));
4176 for (
int x = 0; x < fileList.size(); x++)
4178 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"File %1 was found at: '%2'").arg(x).arg(fileList[0]));
4191 QStringList strList;
4193 if (sList.size() < 4)
4195 LOG(VB_GENERAL, LOG_ERR,
LOC +
4196 QString(
"HandleSGFileQuery: Invalid Request. %1")
4197 .arg(sList.join(
"[]:[]")));
4198 strList <<
"EMPTY LIST";
4204 const QString& wantHost = sList.at(1);
4205 QHostAddress wantHostaddr(wantHost);
4206 const QString& groupname = sList.at(2);
4207 const QString&
filename = sList.at(3);
4209 bool allowFallback =
true;
4210 if (sList.size() >= 5)
4211 allowFallback = (sList.at(4).toInt() > 0);
4212 LOG(VB_FILE, LOG_ERR, QString(
"HandleSGFileQuery - allowFallback: %1").arg(allowFallback));
4214 bool slaveUnreachable =
false;
4216 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"HandleSGFileQuery: %1")
4221 if ((host.toLower() == wantHost.toLower()) ||
4222 (!addr.isEmpty() && addr == wantHostaddr.toString()))
4224 LOG(VB_FILE, LOG_INFO,
LOC +
"HandleSGFileQuery: Getting local info");
4233 LOG(VB_FILE, LOG_INFO,
LOC +
4234 "HandleSGFileQuery: Getting remote info");
4237 slaveUnreachable =
false;
4241 LOG(VB_FILE, LOG_INFO,
LOC +
4242 QString(
"HandleSGFileQuery: Failed to grab slave socket : %1 :")
4244 slaveUnreachable =
true;
4249 if (slaveUnreachable)
4250 strList <<
"SLAVE UNREACHABLE: " << wantHost;
4252 if (strList.count() == 0 || (strList.at(0) ==
"0"))
4253 strList <<
"EMPTY LIST";
4261 QString pbshost =
pbs->getHostname();
4263 QStringList strlist;
4272 if ((cardid != -1) && (cardid != elink->GetInputID()))
4275 if (elink->IsLocal())
4278 enchost = elink->GetHostName();
4280 if ((enchost == pbshost) &&
4281 (elink->IsConnected()) &&
4282 (!elink->IsBusy()) &&
4283 (!elink->IsTunerLocked()))
4297 QString msg = QString(
"Cardid %1 LOCKed for external use on %2.")
4298 .arg(retval).arg(pbshost);
4299 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
4302 query.
prepare(
"SELECT videodevice, audiodevice, "
4305 "WHERE cardid = :CARDID ;");
4311 strlist << QString::number(retval)
4312 << query.
value(0).toString()
4313 << query.
value(1).toString()
4314 << query.
value(2).toString();
4322 LOG(VB_GENERAL, LOG_ERR,
LOC +
4323 "MainServer::LockTuner(): Could not find "
4324 "card info in database");
4329 strlist <<
"-2" <<
"" <<
"" <<
"";
4335 strlist <<
"-1" <<
"" <<
"" <<
"";
4342 QStringList strlist;
4349 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleFreeTuner() " +
4350 QString(
"Unknown encoder: %1").arg(cardid));
4351 strlist <<
"FAILED";
4358 QString msg = QString(
"Cardid %1 FREED from external use on %2.")
4359 .arg(cardid).arg(
pbs->getHostname());
4360 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
4380 uint excluded_input)
4382 LOG(VB_CHANNEL, LOG_INFO,
4383 LOC + QString(
"Excluding input %1")
4384 .arg(excluded_input));
4387 std::vector<InputInfo> busyinputs;
4388 std::vector<InputInfo> freeinputs;
4389 QMap<uint, QSet<uint> > groupids;
4397 info.m_inputId = elink->GetInputID();
4399 if (!elink->IsConnected() || elink->IsTunerLocked())
4401 LOG(VB_CHANNEL, LOG_INFO,
4402 LOC + QString(
"Input %1 is locked or not connected")
4403 .arg(
info.m_inputId));
4407 std::vector<uint> infogroups;
4409 for (
uint group : infogroups)
4410 groupids[
info.m_inputId].insert(group);
4413 if (
info.m_inputId != excluded_input && elink->IsBusy(&busyinfo))
4415 LOG(VB_CHANNEL, LOG_DEBUG,
4416 LOC + QString(
"Input %1 is busy on %2/%3")
4420 busyinputs.push_back(
info);
4422 else if (
info.m_liveTvOrder)
4424 LOG(VB_CHANNEL, LOG_DEBUG,
4425 LOC + QString(
"Input %1 is free")
4426 .arg(
info.m_inputId));
4427 freeinputs.push_back(
info);
4434 for (
auto & busyinfo : busyinputs)
4436 auto freeiter = freeinputs.begin();
4437 while (freeiter != freeinputs.end())
4441 if ((groupids[busyinfo.m_inputId] & groupids[freeinfo.
m_inputId])
4448 if (busyinfo.m_sourceId == freeinfo.
m_sourceId)
4450 LOG(VB_CHANNEL, LOG_DEBUG,
4451 LOC + QString(
"Input %1 is limited to %2/%3 by input %4")
4452 .arg(freeinfo.
m_inputId).arg(busyinfo.m_chanId)
4453 .arg(busyinfo.m_mplexId).arg(busyinfo.m_inputId));
4454 freeinfo.
m_chanId = busyinfo.m_chanId;
4455 freeinfo.
m_mplexId = busyinfo.m_mplexId;
4460 LOG(VB_CHANNEL, LOG_DEBUG,
4461 LOC + QString(
"Input %1 is unavailable by input %2")
4462 .arg(freeinfo.
m_inputId).arg(busyinfo.m_inputId));
4463 freeiter = freeinputs.erase(freeiter);
4469 QStringList strlist;
4470 for (
auto & input : freeinputs)
4472 LOG(VB_CHANNEL, LOG_INFO,
4473 LOC + QString(
"Input %1 is available on %2/%3")
4474 .arg(input.m_inputId).arg(input.m_chanId)
4475 .arg(input.m_mplexId));
4476 input.ToStringList(strlist);
4479 if (strlist.empty())
4504 if (commands.size() < 2 || slist.size() < 2)
4507 int recnum = commands[1].toInt();
4514 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleRecorderQuery() " +
4515 QString(
"Unknown encoder: %1").arg(recnum));
4516 QStringList retlist(
"bad" );
4522 const QString& command = slist[1];
4524 QStringList retlist;
4529 LOG(VB_GENERAL, LOG_ERR,
LOC +
" MainServer::HandleRecorderQuery() " +
4530 QString(
"Command %1 for unconnected encoder %2")
4531 .arg(command).arg(recnum));
4537 if (command ==
"IS_RECORDING")
4541 else if (command ==
"GET_FRAMERATE")
4545 else if (command ==
"GET_FRAMES_WRITTEN")
4549 else if (command ==
"GET_FILE_POSITION")
4553 else if (command ==
"GET_MAX_BITRATE")
4557 else if (command ==
"GET_CURRENT_RECORDING")
4562 info->ToStringList(retlist);
4572 else if (command ==
"GET_KEYFRAME_POS")
4574 long long desired = slist[2].toLongLong();
4577 else if (command ==
"FILL_POSITION_MAP")
4579 int64_t start = slist[2].toLongLong();
4580 int64_t end = slist[3].toLongLong();
4589 for (
auto it = map.cbegin(); it != map.cend(); ++it)
4591 retlist += QString::number(it.key());
4592 retlist += QString::number(*it);
4594 if (retlist.empty())
4598 else if (command ==
"FILL_DURATION_MAP")
4600 int64_t start = slist[2].toLongLong();
4601 int64_t end = slist[3].toLongLong();
4610 for (
auto it = map.cbegin(); it != map.cend(); ++it)
4612 retlist += QString::number(it.key());
4613 retlist += QString::number(*it);
4615 if (retlist.empty())
4619 else if (command ==
"GET_RECORDING")
4634 else if (command ==
"FRONTEND_READY")
4639 else if (command ==
"CANCEL_NEXT_RECORDING")
4641 const QString& cancel = slist[2];
4642 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
4643 QString(
"Received: CANCEL_NEXT_RECORDING %1").arg(cancel));
4647 else if (command ==
"SPAWN_LIVETV")
4649 const QString& chainid = slist[2];
4660 enc->
SpawnLiveTV(chain, slist[3].toInt() != 0, slist[4]);
4663 else if (command ==
"STOP_LIVETV")
4680 else if (command ==
"PAUSE")
4685 else if (command ==
"FINISH_RECORDING")
4690 else if (command ==
"SET_LIVE_RECORDING")
4692 int recording = slist[2].toInt();
4696 else if (command ==
"GET_INPUT")
4699 ret = (ret.isEmpty()) ?
"UNKNOWN" : ret;
4702 else if (command ==
"SET_INPUT")
4704 const QString& input = slist[2];
4705 QString ret = enc->
SetInput(input);
4706 ret = (ret.isEmpty()) ?
"UNKNOWN" : ret;
4709 else if (command ==
"TOGGLE_CHANNEL_FAVORITE")
4711 const QString& changroup = slist[2];
4715 else if (command ==
"CHANGE_CHANNEL")
4721 else if (command ==
"SET_CHANNEL")
4723 const QString& name = slist[2];
4727 else if (command ==
"SET_SIGNAL_MONITORING_RATE")
4729 auto rate = std::chrono::milliseconds(slist[2].toInt());
4730 int notifyFrontend = slist[3].toInt();
4732 retlist << QString::number(oldrate.count());
4734 else if (command ==
"GET_COLOUR")
4737 retlist << QString::number(ret);
4739 else if (command ==
"GET_CONTRAST")
4742 retlist << QString::number(ret);
4744 else if (command ==
"GET_BRIGHTNESS")
4747 retlist << QString::number(ret);
4749 else if (command ==
"GET_HUE")
4752 retlist << QString::number(ret);
4754 else if (command ==
"CHANGE_COLOUR")
4756 int type = slist[2].toInt();
4757 bool up = slist[3].toInt() != 0;
4760 retlist << QString::number(ret);
4762 else if (command ==
"CHANGE_CONTRAST")
4764 int type = slist[2].toInt();
4765 bool up = slist[3].toInt() != 0;
4768 retlist << QString::number(ret);
4770 else if (command ==
"CHANGE_BRIGHTNESS")
4772 int type= slist[2].toInt();
4773 bool up = slist[3].toInt() != 0;
4776 retlist << QString::number(ret);
4778 else if (command ==
"CHANGE_HUE")
4780 int type= slist[2].toInt();
4781 bool up = slist[3].toInt() != 0;
4784 retlist << QString::number(ret);
4786 else if (command ==
"CHECK_CHANNEL")
4788 const QString& name = slist[2];
4789 retlist << QString::number((
int)(enc->
CheckChannel(name)));
4791 else if (command ==
"SHOULD_SWITCH_CARD")
4793 const QString& chanid = slist[2];
4796 else if (command ==
"CHECK_CHANNEL_PREFIX")
4798 QString needed_spacer;
4799 const QString&
prefix = slist[2];
4800 uint complete_valid_channel_on_rec = 0;
4801 bool is_extra_char_useful =
false;
4804 prefix, complete_valid_channel_on_rec,
4805 is_extra_char_useful, needed_spacer);
4807 retlist << QString::number((
int)match);
4808 retlist << QString::number(complete_valid_channel_on_rec);
4809 retlist << QString::number((
int)is_extra_char_useful);
4810 retlist << ((needed_spacer.isEmpty()) ? QString(
"X") : needed_spacer);
4812 else if (command ==
"GET_NEXT_PROGRAM_INFO" && (slist.size() >= 6))
4814 QString channelname = slist[2];
4815 uint chanid = slist[3].toUInt();
4817 QString starttime = slist[5];
4820 QString subtitle =
"";
4822 QString category =
"";
4823 QString endtime =
"";
4824 QString callsign =
"";
4825 QString iconpath =
"";
4826 QString seriesid =
"";
4827 QString programid =
"";
4830 title, subtitle, desc, category, starttime,
4831 endtime, callsign, iconpath, channelname, chanid,
4832 seriesid, programid);
4843 retlist << QString::number(chanid);
4847 else if (command ==
"GET_CHANNEL_INFO")
4849 uint chanid = slist[2].toUInt();
4851 QString callsign =
"";
4852 QString channum =
"";
4853 QString channame =
"";
4857 callsign, channum, channame, xmltv);
4859 retlist << QString::number(chanid);
4860 retlist << QString::number(sourceid);
4868 LOG(VB_GENERAL, LOG_ERR,
LOC +
4869 QString(
"Unknown command: %1").arg(command));
4881 int recnum = commands[1].toInt();
4888 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleSetNextLiveTVDir() " +
4889 QString(
"Unknown encoder: %1").arg(recnum));
4890 QStringList retlist(
"bad" );
4899 QStringList retlist(
"OK" );
4907 uint chanid = slist[1].toUInt();
4908 uint sourceid = slist[2].toUInt();
4909 QString oldcnum =
cleanup(slist[3]);
4910 QString callsign =
cleanup(slist[4]);
4911 QString channum =
cleanup(slist[5]);
4912 QString channame =
cleanup(slist[6]);
4913 QString xmltv =
cleanup(slist[7]);
4915 QStringList retlist;
4916 if (!chanid || !sourceid)
4928 ok &= encoder->SetChannelInfo(chanid, sourceid, oldcnum,
4929 callsign, channum, channame, xmltv);
4934 retlist << ((ok) ?
"1" :
"0");
4943 int recnum = commands[1].toInt();
4944 QStringList retlist;
4951 LOG(VB_GENERAL, LOG_ERR,
LOC +
4952 QString(
"HandleRemoteEncoder(cmd %1) ").arg(slist[1]) +
4953 QString(
"Unknown encoder: %1").arg(recnum));
4962 const QString& command = slist[1];
4964 if (command ==
"GET_STATE")
4966 retlist << QString::number((
int)enc->
GetState());
4968 else if (command ==
"GET_SLEEPSTATUS")
4972 else if (command ==
"GET_FLAGS")
4974 retlist << QString::number(enc->
GetFlags());
4976 else if (command ==
"IS_BUSY")
4978 std::chrono::seconds time_buffer = 5s;
4979 if (slist.size() >= 3)
4980 time_buffer = std::chrono::seconds(slist[2].toInt());
4982 retlist << QString::number((
int)enc->
IsBusy(&busy_input, time_buffer));
4985 else if (command ==
"MATCHES_RECORDING" &&
4988 QStringList::const_iterator it = slist.cbegin() + 2;
4993 else if (command ==
"START_RECORDING" &&
4996 QStringList::const_iterator it = slist.cbegin() + 2;
5003 else if (command ==
"GET_RECORDING_STATUS")
5007 else if (command ==
"RECORD_PENDING" &&
5010 auto secsleft = std::chrono::seconds(slist[2].toInt());
5011 int haslater = slist[3].toInt();
5012 QStringList::const_iterator it = slist.cbegin() + 4;
5019 else if (command ==
"CANCEL_NEXT_RECORDING" &&
5020 (slist.size() >= 3))
5022 bool cancel = (
bool) slist[2].toInt();
5026 else if (command ==
"STOP_RECORDING")
5031 else if (command ==
"GET_MAX_BITRATE")
5035 else if (command ==
"GET_CURRENT_RECORDING")
5040 info->ToStringList(retlist);
5063 if (
pbs->isMediaServer())
5074 QStringList retlist;
5076 retlist.push_front(QString::number(retlist.size()));
5083 QStringList retlist;
5084 const QString& queryhostname = slist[1];
5089 if (slave !=
nullptr)
5109 size_t totalKBperMin = 0;
5114 if (!enc->IsConnected() || !enc->IsBusy())
5117 long long maxBitrate = enc->GetMaxBitrate();
5119 maxBitrate = 19500000LL;
5120 long long thisKBperMin = (((size_t)maxBitrate)*((size_t)15))>>11;
5121 totalKBperMin += thisKBperMin;
5122 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Cardid %1: max bitrate %2 KB/min")
5123 .arg(enc->GetInputID()).arg(thisKBperMin));
5127 LOG(VB_FILE, LOG_INFO,
LOC +
5128 QString(
"Maximal bitrate of busy encoders is %1 KB/min")
5129 .arg(totalKBperMin));
5131 return totalKBperMin;
5138 QString allHostList;
5142 QMap <QString, bool> backendsCounted;
5143 std::list<PlaybackSock *> localPlaybackList;
5149 if ((
pbs->IsDisconnected()) ||
5150 (!
pbs->isMediaServer()) ||
5152 (backendsCounted.contains(
pbs->getHostname())))
5155 backendsCounted[
pbs->getHostname()] =
true;
5157 localPlaybackList.push_back(
pbs);
5158 allHostList +=
"," +
pbs->getHostname();
5163 for (
auto &
pbs : localPlaybackList) {
5164 fsInfos <<
pbs->GetDiskSpace();
5173 maxWriteFiveSec = std::max((int64_t)2048, maxWriteFiveSec);
5192 QStringList strlist;
5200 for (
auto & fsInfo : fsInfos)
5202 fsInfo.setFSysID(-1);
5205 LOG(VB_SCHEDULE | VB_FILE, LOG_DEBUG,
LOC +
5206 "Determining unique filesystems");
5209 maxWriteFiveSec = std::max((
size_t)2048, maxWriteFiveSec);
5215 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5216 "--- GetFilesystemInfos directory list start ---");
5217 for (
const auto&
fs1 : std::as_const(fsInfos))
5220 QString(
"Dir: %1:%2")
5221 .arg(
fs1.getHostname(),
fs1.getPath());
5222 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC + msg) ;
5223 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5224 QString(
" Location: %1")
5225 .arg(
fs1.isLocal() ?
"Local" :
"Remote"));
5226 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5227 QString(
" fsID : %1")
5228 .arg(
fs1.getFSysID()));
5229 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5230 QString(
" dirID : %1")
5231 .arg(
fs1.getGroupID()));
5232 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5233 QString(
" BlkSize : %1")
5234 .arg(
fs1.getBlockSize()));
5235 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5236 QString(
" TotalKB : %1")
5237 .arg(
fs1.getTotalSpace()));
5238 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5239 QString(
" UsedKB : %1")
5240 .arg(
fs1.getUsedSpace()));
5241 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5242 QString(
" FreeKB : %1")
5243 .arg(
fs1.getFreeSpace()));
5245 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5246 "--- GetFilesystemInfos directory list end ---");
5255 const QString &src,
const QString &dst)
5258 QStringList retlist;
5260 if (src.isEmpty() || dst.isEmpty()
5261 || src.contains(
"..") || dst.contains(
".."))
5263 LOG(VB_GENERAL, LOG_ERR,
LOC +
5264 QString(
"HandleMoveFile: ERROR moving file '%1' -> '%2', "
5265 "a path fails sanity checks").arg(src, dst));
5266 retlist <<
"0" <<
"Invalid path";
5271 QString srcAbs = sgroup.
FindFile(src);
5272 if (srcAbs.isEmpty())
5274 LOG(VB_GENERAL, LOG_ERR,
LOC +
5275 QString(
"HandleMoveFile: Unable to find %1").arg(src));
5276 retlist <<
"0" <<
"Source file not found";
5284 QString dstAbs = sgroup.
FindFile(dst);
5285 if (!dstAbs.isEmpty() && QFileInfo(dstAbs).isFile())
5287 LOG(VB_GENERAL, LOG_ERR,
LOC +
5288 QString(
"HandleMoveFile: Destination exists at %1").arg(dstAbs));
5289 retlist <<
"0" <<
"Destination file exists";
5295 int sgPathSize = srcAbs.size() - src.size();
5296 dstAbs = srcAbs.mid(0, sgPathSize) + dst;
5310 LOG(VB_FILE, LOG_INFO, QString(
"MainServer::RenameThread: Renaming %1 -> %2")
5313 QStringList retlist;
5314 QFileInfo fi(
m_dst);
5316 if (QDir().mkpath(fi.path()) && QFile::rename(
m_src,
m_dst))
5322 retlist <<
"0" <<
"Rename failed";
5323 LOG(VB_FILE, LOG_ERR,
"MainServer::DoRenameThread: Rename failed");
5356 QStringList retlist;
5362 LOG(VB_GENERAL, LOG_ERR,
LOC +
5363 QString(
"ERROR deleting file, filename '%1' "
5364 "fails sanity checks").arg(
filename));
5375 if (fullfile.isEmpty()) {
5376 LOG(VB_GENERAL, LOG_ERR,
LOC +
5377 QString(
"Unable to find %1 in HandleDeleteFile()") .arg(
filename));
5386 QFile checkFile(fullfile);
5393 const QFileInfo
info(fullfile);
5397 if ((fd < 0) && checkFile.exists())
5399 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error deleting file: %1.")
5419 auto *truncateThread =
new TruncateThread(
this, fullfile, fd, size);
5420 truncateThread->run();
5431 const QString &starttime,
5436 pbssock =
pbs->getSocket();
5439 frm_dir_map_t::const_iterator it;
5441 QStringList retlist;
5444 const ProgramInfo pginfo(chanid.toUInt(), recstartdt);
5453 for (it = markMap.cbegin(); it != markMap.cend(); ++it)
5456 QString intstr = QString(
"%1").arg(*it);
5458 retlist << QString::number(it.key());
5463 retlist.prepend(QString(
"%1").arg(rowcnt));
5472 const QString &starttime,
5487 const QString &starttime,
5503 const QString &starttime,
5514 pbssock =
pbs->getSocket();
5518 chanid.toUInt(), recstartts);
5520 QStringList retlist;
5521 retlist << QString::number(bookmark);
5540 pbssock =
pbs->getSocket();
5542 const QString& chanid = tokens[1];
5543 const QString& starttime = tokens[2];
5544 long long bookmark = tokens[3].toLongLong();
5547 QStringList retlist;
5558 retlist <<
"FAILED";
5572 pbssock =
pbs->getSocket();
5574 const QString&
hostname = tokens[1];
5575 const QString& setting = tokens[2];
5576 QStringList retlist;
5580 retlist << retvalue;
5588 bool synchronous = (command[0] ==
"DOWNLOAD_FILE_NOW");
5589 const QString& srcURL = command[1];
5590 const QString& storageGroup = command[2];
5595 QStringList retlist;
5599 pbssock =
pbs->getSocket();
5603 QFileInfo finfo(srcURL);
5607 if (outDir.isEmpty())
5609 LOG(VB_GENERAL, LOG_ERR,
LOC +
5610 QString(
"Unable to determine directory "
5611 "to write to in %1 write command").arg(command[0]));
5612 retlist <<
"downloadfile_directory_not_found";
5621 LOG(VB_GENERAL, LOG_ERR,
LOC +
5622 QString(
"ERROR: %1 write filename '%2' does not pass "
5623 "sanity checks.") .arg(command[0],
filename));
5624 retlist <<
"downloadfile_filename_dangerous";
5667 pbssock =
pbs->getSocket();
5669 const QString&
hostname = tokens[1];
5670 const QString& setting = tokens[2];
5671 const QString& svalue = tokens[3];
5672 QStringList retlist;
5687 QStringList retlist;
5709 QStringList strlist;
5715 QString sql =
"SELECT DISTINCT hostname "
5716 "FROM storagegroup "
5717 "WHERE groupname = 'Music'";
5729 LOG(VB_GENERAL, LOG_INFO,
LOC +
5730 QString(
"HandleScanMusic: running filescanner on master BE '%1'").arg(
hostname));
5742 LOG(VB_GENERAL, LOG_INFO,
LOC +
5743 QString(
"HandleScanMusic: asking slave '%1' to run file scanner").arg(
hostname));
5749 LOG(VB_GENERAL, LOG_INFO,
LOC +
5750 QString(
"HandleScanMusic: Failed to grab slave socket on '%1'").arg(
hostname));
5759 LOG(VB_GENERAL, LOG_INFO,
LOC +
5760 QString(
"HandleScanMusic: running filescanner on slave BE '%1'")
5778 QStringList strlist;
5782 const QString&
hostname = slist[1];
5790 LOG(VB_GENERAL, LOG_INFO,
LOC +
5791 QString(
"HandleMusicTagUpdateVolatile: asking slave '%1' to update the metadata").arg(
hostname));
5801 LOG(VB_GENERAL, LOG_INFO,
LOC +
5802 QString(
"HandleMusicTagUpdateVolatile: Failed to grab slave socket on '%1'").arg(
hostname));
5804 strlist <<
"ERROR: slave not found";
5813 QStringList paramList;
5814 paramList.append(QString(
"--songid='%1'").arg(slist[2]));
5815 paramList.append(QString(
"--rating='%1'").arg(slist[3]));
5816 paramList.append(QString(
"--playcount='%1'").arg(slist[4]));
5817 paramList.append(QString(
"--lastplayed='%1'").arg(slist[5]));
5819 QString command =
GetAppBinDir() +
"mythutil --updatemeta " + paramList.join(
" ");
5821 LOG(VB_GENERAL, LOG_INFO,
LOC +
5822 QString(
"HandleMusicTagUpdateVolatile: running %1'").arg(command));
5838 QStringList strlist;
5842 const QString&
hostname = slist[1];
5850 LOG(VB_GENERAL, LOG_INFO,
LOC +
5851 QString(
"HandleMusicCalcTrackLen: asking slave '%1' to update the track length").arg(
hostname));
5861 LOG(VB_GENERAL, LOG_INFO,
LOC +
5862 QString(
"HandleMusicCalcTrackLen: Failed to grab slave socket on '%1'").arg(
hostname));
5864 strlist <<
"ERROR: slave not found";
5873 QStringList paramList;
5874 paramList.append(QString(
"--songid='%1'").arg(slist[2]));
5876 QString command =
GetAppBinDir() +
"mythutil --calctracklen " + paramList.join(
" ");
5878 LOG(VB_GENERAL, LOG_INFO,
LOC +
5879 QString(
"HandleMusicCalcTrackLen: running %1'").arg(command));
5896 QStringList strlist;
5900 const QString&
hostname = slist[1];
5908 LOG(VB_GENERAL, LOG_INFO,
LOC +
5909 QString(
"HandleMusicTagUpdateMetadata: asking slave '%1' "
5910 "to update the metadata").arg(
hostname));
5920 LOG(VB_GENERAL, LOG_INFO,
LOC +
5921 QString(
"HandleMusicTagUpdateMetadata: Failed to grab "
5922 "slave socket on '%1'").arg(
hostname));
5924 strlist <<
"ERROR: slave not found";
5933 int songID = slist[2].toInt();
5939 LOG(VB_GENERAL, LOG_ERR,
LOC +
5940 QString(
"HandleMusicTagUpdateMetadata: "
5941 "Cannot find metadata for trackid: %1")
5944 strlist <<
"ERROR: track not found";
5957 LOG(VB_GENERAL, LOG_ERR,
LOC +
5958 QString(
"HandleMusicTagUpdateMetadata: "
5959 "Failed to write to tag for trackid: %1")
5962 strlist <<
"ERROR: write to tag failed";
5982 QStringList strlist;
5986 const QString&
hostname = slist[1];
5994 LOG(VB_GENERAL, LOG_INFO,
LOC +
5995 QString(
"HandleMusicFindAlbumArt: asking slave '%1' "
5996 "to update the albumart").arg(
hostname));
6006 LOG(VB_GENERAL, LOG_INFO,
LOC +
6007 QString(
"HandleMusicFindAlbumArt: Failed to grab "
6008 "slave socket on '%1'").arg(
hostname));
6010 strlist <<
"ERROR: slave not found";
6019 int songID = slist[2].toInt();
6020 bool updateDatabase = (slist[3].toInt() == 1);
6026 LOG(VB_GENERAL, LOG_ERR,
LOC +
6027 QString(
"HandleMusicFindAlbumArt: "
6028 "Cannot find metadata for trackid: %1").arg(songID));
6030 strlist <<
"ERROR: track not found";
6040 QDir dir = fi.absoluteDir();
6043 "*.png;*.jpg;*.jpeg;*.gif;*.bmp");
6044 dir.setNameFilters(nameFilter.split(
";"));
6046 QStringList files = dir.entryList();
6051 fi.setFile(mdata->
Filename(
false));
6052 QString startDir = fi.path();
6054 for (
const QString&
file : std::as_const(files))
6058 image->m_filename = startDir +
'/' + fi.fileName();
6060 image->m_embedded =
false;
6062 image->m_description =
"";
6063 images->addImage(image);
6075 for (
int x = 0; x < artList.count(); x++)
6079 images->addImage(image);
6087 LOG(VB_GENERAL, LOG_ERR,
LOC +
6088 QString(
"HandleMusicFindAlbumArt: "
6089 "Failed to find a tagger for trackid: %1").arg(songID));
6094 images->dumpToDatabase();
6097 strlist.append(QString(
"%1").arg(images->getImageCount()));
6099 for (
uint x = 0; x < images->getImageCount(); x++)
6102 strlist.append(QString(
"%1").arg(image->
m_id));
6103 strlist.append(QString(
"%1").arg((
int)image->
m_imageType));
6104 strlist.append(QString(
"%1").arg(
static_cast<int>(image->
m_embedded)));
6112 QStringList paramList;
6113 paramList.append(QString(
"--songid='%1'").arg(mdata->
ID()));
6114 paramList.append(QString(
"--imagetype='%1'").arg(image->
m_imageType));
6116 QString command =
GetAppBinDir() +
"mythutil --extractimage " + paramList.join(
" ");
6134 QStringList strlist;
6138 const QString&
hostname = slist[1];
6139 const QString& songid = slist[2];
6140 const QString& imagetype = slist[3];
6148 LOG(VB_GENERAL, LOG_INFO,
LOC +
6149 QString(
"HandleMusicTagGetImage: asking slave '%1' to "
6150 "extract the image").arg(
hostname));
6160 LOG(VB_GENERAL, LOG_INFO,
LOC +
6161 QString(
"HandleMusicTagGetImage: Failed to grab slave "
6166 QStringList paramList;
6167 paramList.append(QString(
"--songid='%1'").arg(songid));
6168 paramList.append(QString(
"--imagetype='%1'").arg(imagetype));
6170 QString command =
GetAppBinDir() +
"mythutil --extractimage " + paramList.join(
" ");
6188 QStringList strlist;
6192 const QString&
hostname = slist[1];
6200 LOG(VB_GENERAL, LOG_INFO,
LOC +
6201 QString(
"HandleMusicTagChangeImage: asking slave '%1' "
6202 "to update the metadata").arg(
hostname));
6212 LOG(VB_GENERAL, LOG_INFO,
LOC +
6213 QString(
"HandleMusicTagChangeImage: Failed to grab "
6214 "slave socket on '%1'").arg(
hostname));
6216 strlist <<
"ERROR: slave not found";
6224 int songID = slist[2].toInt();
6225 auto oldType = (
ImageType)slist[3].toInt();
6226 auto newType = (
ImageType)slist[4].toInt();
6233 LOG(VB_GENERAL, LOG_ERR,
LOC +
6234 QString(
"HandleMusicTagChangeImage: "
6235 "Cannot find metadata for trackid: %1")
6238 strlist <<
"ERROR: track not found";
6279 LOG(VB_GENERAL, LOG_ERR,
"HandleMusicTagChangeImage: failed to change image type");
6281 strlist <<
"ERROR: failed to change image type";
6299 image->
m_filename = fi.path() + QString(
"/%1-%2.jpg")
6313 QStringList paramList;
6314 paramList.append(QString(
"--songid='%1'").arg(mdata->
ID()));
6315 paramList.append(QString(
"--imagetype='%1'").arg(image->
m_imageType));
6317 QString command =
GetAppBinDir() +
"mythutil --extractimage " + paramList.join(
" ");
6330 image->
m_filename = fi.absolutePath() + QString(
"/%1.jpg")
6355 QStringList strlist;
6359 const QString&
hostname = slist[1];
6367 LOG(VB_GENERAL, LOG_INFO,
LOC +
6368 QString(
"HandleMusicTagAddImage: asking slave '%1' "
6369 "to add the image").arg(
hostname));
6379 LOG(VB_GENERAL, LOG_INFO,
LOC +
6380 QString(
"HandleMusicTagAddImage: Failed to grab "
6381 "slave socket on '%1'").arg(
hostname));
6383 strlist <<
"ERROR: slave not found";
6392 int songID = slist[2].toInt();
6393 const QString&
filename = slist[3];
6394 auto imageType = (
ImageType) slist[4].toInt();
6400 LOG(VB_GENERAL, LOG_ERR,
LOC +
6401 QString(
"HandleMusicTagAddImage: Cannot find metadata for trackid: %1")
6404 strlist <<
"ERROR: track not found";
6416 LOG(VB_GENERAL, LOG_ERR,
LOC +
6417 "HandleMusicTagAddImage: failed to find a tagger for track");
6419 strlist <<
"ERROR: tagger not found";
6430 LOG(VB_GENERAL, LOG_ERR,
LOC +
6431 "HandleMusicTagAddImage: asked to write album art to the tag "
6432 "but the tagger doesn't support it!");
6434 strlist <<
"ERROR: embedded images not supported by tag";
6445 bool isDirectoryImage =
false;
6448 if (imageFilename.isEmpty())
6452 imageFilename = fi.absolutePath() +
'/' +
filename;
6453 isDirectoryImage =
true;
6458 LOG(VB_GENERAL, LOG_ERR,
LOC +
6459 QString(
"HandleMusicTagAddImage: cannot find image file %1").arg(
filename));
6461 strlist <<
"ERROR: failed to find image file";
6477 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleMusicTagAddImage: failed to write album art to tag");
6479 strlist <<
"ERROR: failed to write album art to tag";
6484 if (!isDirectoryImage)
6485 QFile::remove(imageFilename);
6493 if (!isDirectoryImage)
6494 QFile::remove(imageFilename);
6510 QStringList strlist;
6514 const QString&
hostname = slist[1];
6522 LOG(VB_GENERAL, LOG_INFO,
LOC +
6523 QString(
"HandleMusicTagRemoveImage: asking slave '%1' "
6524 "to remove the image").arg(
hostname));
6534 LOG(VB_GENERAL, LOG_INFO,
LOC +
6535 QString(
"HandleMusicTagRemoveImage: Failed to grab "
6536 "slave socket on '%1'").arg(
hostname));
6538 strlist <<
"ERROR: slave not found";
6546 int songID = slist[2].toInt();
6547 int imageID = slist[3].toInt();
6554 LOG(VB_GENERAL, LOG_ERR,
LOC +
6555 QString(
"HandleMusicTagRemoveImage: Cannot find metadata for trackid: %1")
6558 strlist <<
"ERROR: track not found";
6570 LOG(VB_GENERAL, LOG_ERR,
LOC +
6571 "HandleMusicTagRemoveImage: failed to find a tagger for track");
6573 strlist <<
"ERROR: tagger not found";
6584 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleMusicTagRemoveImage: asked to remove album art "
6585 "from the tag but the tagger doesn't support it!");
6587 strlist <<
"ERROR: embedded images not supported by tag";
6600 LOG(VB_GENERAL, LOG_ERR,
LOC +
6601 QString(
"HandleMusicTagRemoveImage: Cannot find image for imageid: %1")
6604 strlist <<
"ERROR: image not found";
6616 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleMusicTagRemoveImage: failed to remove album art from tag");
6618 strlist <<
"ERROR: failed to remove album art from tag";
6637 QStringList strlist;
6641 const QString&
hostname = slist[1];
6642 const QString& songid = slist[2];
6643 const QString& grabberName = slist[3];
6644 QString artist =
"";
6648 if (slist.size() == 7)
6661 LOG(VB_GENERAL, LOG_INFO,
LOC +
6662 QString(
"HandleMusicFindLyrics: asking slave '%1' to "
6673 LOG(VB_GENERAL, LOG_INFO,
LOC +
6674 QString(
"HandleMusicFindLyrics: Failed to grab slave "
6679 QStringList paramList;
6680 paramList.append(QString(
"--songid='%1'").arg(songid));
6681 paramList.append(QString(
"--grabber='%1'").arg(grabberName));
6683 if (!artist.isEmpty())
6684 paramList.append(QString(
"--artist=\"%1\"").arg(artist));
6686 if (!album.isEmpty())
6687 paramList.append(QString(
"--album=\"%1\"").arg(album));
6689 if (!title.isEmpty())
6690 paramList.append(QString(
"--title=\"%1\"").arg(title));
6692 QString command =
GetAppBinDir() +
"mythutil --findlyrics " + paramList.join(
" ");
6726 QStringList strlist;
6730 QString scriptDir =
GetShareDir() +
"metadata/Music/lyrics";
6735 LOG(VB_GENERAL, LOG_ERR, QString(
"Cannot find lyric scripts directory: %1").arg(scriptDir));
6736 strlist << QString(
"ERROR: Cannot find lyric scripts directory: %1").arg(scriptDir);
6744 d.setFilter(QDir::Files | QDir::NoDotAndDotDot);
6745 d.setNameFilters(QStringList(
"*.py"));
6746 QFileInfoList list =
d.entryInfoList();
6749 LOG(VB_GENERAL, LOG_ERR, QString(
"Cannot find any lyric scripts in: %1").arg(scriptDir));
6750 strlist << QString(
"ERROR: Cannot find any lyric scripts in: %1").arg(scriptDir);
6758 QStringList scripts;
6759 for (
const auto & fi : std::as_const(list))
6761 LOG(VB_FILE, LOG_NOTICE, QString(
"Found lyric script at: %1").arg(fi.filePath()));
6762 scripts.append(fi.filePath());
6765 QStringList grabbers;
6768 for (
int x = 0; x < scripts.count(); x++)
6770 QStringList
args { scripts.at(x),
"-v" };
6772 p.start(PYTHON_EXE,
args);
6773 p.waitForFinished(-1);
6774 QString result =
p.readAllStandardOutput();
6776 QDomDocument domDoc;
6777#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
6780 int errorColumn = 0;
6782 if (!domDoc.setContent(result,
false, &errorMsg, &errorLine, &errorColumn))
6784 LOG(VB_GENERAL, LOG_ERR,
6785 QString(
"FindLyrics: Could not parse version from %1").arg(scripts.at(x)) +
6786 QString(
"\n\t\t\tError at line: %1 column: %2 msg: %3").arg(errorLine).arg(errorColumn).arg(errorMsg));
6790 auto parseResult = domDoc.setContent(result);
6793 LOG(VB_GENERAL, LOG_ERR,
6794 QString(
"FindLyrics: Could not parse version from %1")
6795 .arg(scripts.at(x)) +
6796 QString(
"\n\t\t\tError at line: %1 column: %2 msg: %3")
6797 .arg(parseResult.errorLine).arg(parseResult.errorColumn)
6798 .arg(parseResult.errorMessage));
6803 QDomNodeList itemList = domDoc.elementsByTagName(
"grabber");
6804 QDomNode itemNode = itemList.item(0);
6806 grabbers.append(itemNode.namedItem(QString(
"name")).toElement().text());
6813 for (
int x = 0; x < grabbers.count(); x++)
6814 strlist.append(grabbers.at(x));
6825 QStringList strlist;
6829 const QString&
hostname = slist[1];
6830 int songID = slist[2].toInt();
6838 LOG(VB_GENERAL, LOG_INFO,
LOC +
6839 QString(
"HandleMusicSaveLyrics: asking slave '%1' to "
6850 LOG(VB_GENERAL, LOG_INFO,
LOC +
6851 QString(
"HandleMusicSaveLyrics: Failed to grab slave "
6859 LOG(VB_GENERAL, LOG_ERR, QString(
"Cannot find metadata for trackid: %1").arg(songID));
6860 strlist << QString(
"ERROR: Cannot find metadata for trackid: %1").arg(songID);
6868 QString lyricsFile =
GetConfDir() + QString(
"/MythMusic/Lyrics/%1.txt").arg(songID);
6872 QFile::remove(lyricsFile);
6875 QFile
file(QLatin1String(qPrintable(lyricsFile)));
6877 if (
file.open(QIODevice::WriteOnly))
6879 QTextStream stream(&
file);
6880 for (
int x = 3; x < slist.count(); x++)
6881 stream << slist.at(x);
6893 QStringList &commands,
6898 int recnum = commands[1].toInt();
6899 const QString& command = slist[1];
6901 QStringList retlist;
6907 if (command ==
"DONE")
6915 LOG(VB_GENERAL, LOG_ERR,
LOC +
6916 QString(
"Unknown file transfer socket: %1").arg(recnum));
6917 retlist << QString(
"ERROR: Unknown file transfer socket: %1")
6929 if (command ==
"REQUEST_BLOCK")
6931 int size = slist[2].toInt();
6935 else if (command ==
"WRITE_BLOCK")
6937 int size = slist[2].toInt();
6939 retlist << QString::number(ft->
WriteBlock(size));
6941 else if (command ==
"SEEK")
6943 long long pos = slist[2].toLongLong();
6944 int whence = slist[3].toInt();
6945 long long curpos = slist[4].toLongLong();
6947 long long ret = ft->
Seek(curpos, pos, whence);
6948 retlist << QString::number(ret);
6950 else if (command ==
"IS_OPEN")
6952 bool isopen = ft->
isOpen();
6954 retlist << QString::number(static_cast<int>(isopen));
6956 else if (command ==
"REOPEN")
6958 retlist << QString::number(static_cast<int>(ft->
ReOpen(slist[2])));
6960 else if (command ==
"DONE")
6965 else if (command ==
"SET_TIMEOUT")
6967 bool fast = slist[2].toInt() != 0;
6971 else if (command ==
"REQUEST_SIZE")
6979 LOG(VB_GENERAL, LOG_ERR,
LOC +
6980 QString(
"Unknown command: %1").arg(command));
6981 retlist <<
"ERROR" <<
"invalid_call";
6995 QStringList::const_iterator it = slist.cbegin() + 1;
7007 retval = iter.key();
7013 QStringList strlist( QString::number(retval) );
7030 strlist <<
"nohost";
7042 int recordernum = slist[1].toInt();
7044 QStringList strlist;
7067 strlist <<
"nohost";
7076 if (slist.size() < 2)
7081 const QString& message = slist[1];
7082 QStringList extra_data;
7083 for (
uint i = 2; i < (
uint) slist.size(); i++)
7084 extra_data.push_back(slist[i]);
7086 if (extra_data.empty())
7097 QStringList retlist(
"OK" );
7105 QStringList retlist;
7107 const QString& newverbose = slist[1];
7108 int len = newverbose.length();
7114 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
7115 QString(
"Verbose mask changed, new mask is: %1").arg(
verboseString));
7121 LOG(VB_GENERAL, LOG_ERR,
LOC +
7122 QString(
"Invalid SET_VERBOSE string: '%1'").arg(newverbose));
7123 retlist <<
"Failed";
7132 QStringList retlist;
7133 const QString& newstring = slist[1];
7134 LogLevel_t newlevel = LOG_UNKNOWN;
7136 int len = newstring.length();
7140 if (newlevel != LOG_UNKNOWN)
7144 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
7145 QString(
"Log level changed, new level is: %1")
7152 if (newlevel == LOG_UNKNOWN)
7154 LOG(VB_GENERAL, LOG_ERR,
LOC +
7155 QString(
"Invalid SET_VERBOSE string: '%1'").arg(newstring));
7156 retlist <<
"Failed";
7166 int RecordingsInProgress = 0;
7167 int LiveTVRecordingsInProgress = 0;
7168 QStringList retlist;
7173 if (elink->IsBusyRecording()) {
7174 RecordingsInProgress++;
7177 if (
info &&
info->GetRecordingGroup() ==
"LiveTV")
7178 LiveTVRecordingsInProgress++;
7185 retlist << QString::number(RecordingsInProgress);
7186 retlist << QString::number(LiveTVRecordingsInProgress);
7195 if (slist.size() < 3)
7197 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Too few params in pixmap request");
7198 QStringList outputlist(
"ERROR");
7199 outputlist +=
"TOO_FEW_PARAMS";
7204 bool time_fmt_sec =
true;
7205 std::chrono::seconds time = std::chrono::seconds::max();
7206 long long frame = -1;
7210 bool has_extra_data =
false;
7212 QString token = slist[1];
7213 if (token.isEmpty())
7215 LOG(VB_GENERAL, LOG_ERR,
LOC +
7216 "Failed to parse pixmap request. Token absent");
7217 QStringList outputlist(
"ERROR");
7218 outputlist +=
"TOKEN_ABSENT";
7223 QStringList::const_iterator it = slist.cbegin() + 2;
7224 QStringList::const_iterator end = slist.cend();
7229 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to parse pixmap request. "
7230 "ProgramInfo missing pathname");
7231 QStringList outputlist(
"BAD");
7232 outputlist +=
"NO_PATHNAME";
7236 if (token.toLower() ==
"do_not_care")
7238 token = QString(
"%1:%2")
7241 if (it != slist.cend())
7242 (time_fmt_sec = ((*it).toLower() ==
"s")), ++it;
7243 if (it != slist.cend())
7246 time = std::chrono::seconds((*it).toLongLong()), ++it;
7248 frame = (*it).toLongLong(), ++it;
7250 if (it != slist.cend())
7251 (outputfile = *it), ++it;
7252 outputfile = (outputfile ==
"<EMPTY>") ? QString() : outputfile;
7253 if (it != slist.cend())
7255 width = (*it).toInt(&ok); ++it;
7256 width = (ok) ? width : -1;
7258 if (it != slist.cend())
7260 height = (*it).toInt(&ok); ++it;
7261 height = (ok) ? height : -1;
7262 has_extra_data =
true;
7264 QSize outputsize = QSize(width, height);
7268 auto pos_text = (time != std::chrono::seconds::max())
7269 ? QString::number(time.count()) +
"s"
7270 : QString::number(frame) +
"f";
7271 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
7272 QString(
"HandleGenPreviewPixmap got extra data\n\t\t\t"
7275 .arg(width).arg(height).arg(outputfile));
7290 QStringList outputlist;
7293 if (time != std::chrono::seconds::max())
7296 token, &pginfo, time, -1, outputfile, outputsize);
7301 token, &pginfo, std::chrono::seconds::max(), frame, outputfile, outputsize);
7311 if (outputlist.empty() || outputlist[0] !=
"OK")
7317 LOG(VB_GENERAL, LOG_ERR,
LOC +
7318 QString(
"HandleGenPreviewPixmap() "
7319 "Couldn't find backend for:\n\t\t\t%1")
7325 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleGenPreviewPixmap: Unable to "
7326 "find file locally, unable to make preview image.");
7327 QStringList outputlist(
"ERROR" );
7328 outputlist +=
"FILE_INACCESSIBLE";
7336 if (time != std::chrono::seconds::max()) {
7338 pginfo, outputsize, outputfile, time, -1, token);
7341 pginfo, outputsize, outputfile, -1s, frame, token);
7349 QStringList outputlist(
"OK");
7350 if (!outputfile.isEmpty())
7351 outputlist += outputfile;
7359 QStringList::const_iterator it = slist.cbegin() + 1;
7364 QStringList strlist;
7377 strlist = (slavetime.isValid()) ?
7378 QStringList(QString::number(slavetime.toSecsSinceEpoch())) :
7385 LOG(VB_GENERAL, LOG_ERR,
LOC +
7386 QString(
"HandlePixmapLastModified() "
7387 "Couldn't find backend for:\n\t\t\t%1")
7393 LOG(VB_GENERAL, LOG_ERR,
LOC +
7394 "MainServer: HandlePixmapLastModified: Unable to "
7395 "find file locally, unable to get last modified date.");
7396 QStringList outputlist(
"BAD" );
7407 QDateTime lastmodified = finfo.lastModified();
7408 if (lastmodified.isValid())
7409 strlist = QStringList(QString::number(lastmodified.toSecsSinceEpoch()));
7411 strlist = QStringList(QString::number(UINT_MAX));
7415 strlist = QStringList(
"BAD" );
7424 QStringList strlist;
7429 strlist = QStringList(
"ERROR");
7430 strlist +=
"1: Parameter list too short";
7435 QDateTime cachemodified;
7436 if (!slist[1].isEmpty() && (slist[1].toInt() != -1))
7441 int max_file_size = slist[2].toInt();
7443 QStringList::const_iterator it = slist.begin() + 3;
7448 strlist = QStringList(
"ERROR");
7449 strlist +=
"2: Invalid ProgramInfo";
7460 size_t fsize = finfo.size();
7461 QDateTime lastmodified = finfo.lastModified();
7462 bool out_of_date = !cachemodified.isValid() ||
7463 (lastmodified > cachemodified);
7465 if (out_of_date && (fsize > 0) && ((ssize_t)fsize < max_file_size))
7469 bool open_ok =
file.open(QIODevice::ReadOnly);
7471 data =
file.readAll();
7473 if (!data.isEmpty())
7475 LOG(VB_FILE, LOG_INFO,
LOC +
7476 QString(
"Read preview file '%1'")
7478 if (lastmodified.isValid())
7479 strlist += QString::number(lastmodified.toSecsSinceEpoch());
7481 strlist += QString::number(UINT_MAX);
7482 strlist += QString::number(data.size());
7483#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
7484 quint16 checksum = qChecksum(data.constData(), data.size());
7486 quint16 checksum = qChecksum(data);
7488 strlist += QString::number(checksum);
7489 strlist += QString(data.toBase64());
7493 LOG(VB_GENERAL, LOG_ERR,
LOC +
7494 QString(
"Failed to read preview file '%1'")
7497 strlist = QStringList(
"ERROR");
7499 QString(
"3: Failed to read preview file '%1'%2")
7501 (open_ok) ?
"" :
" open failed");
7504 else if (out_of_date && (max_file_size > 0))
7506 if (fsize >= (
size_t) max_file_size)
7508 strlist = QStringList(
"WARNING");
7509 strlist += QString(
"1: Preview file too big %1 > %2")
7510 .arg(fsize).arg(max_file_size);
7514 strlist = QStringList(
"ERROR");
7515 strlist +=
"4: Preview file is invalid";
7520 if (lastmodified.isValid())
7521 strlist += QString::number(lastmodified.toSecsSinceEpoch());
7523 strlist += QString::number(UINT_MAX);
7537 strlist = QStringList(
"ERROR");
7539 "5: Could not locate mythbackend that made this recording";
7548 if (!strlist.empty())
7555 strlist = QStringList(
"WARNING");
7556 strlist +=
"2: Could not locate requested file";
7562 QStringList retlist(
"OK" );
7568 pbs->setBlockShutdown(blockShutdown);
7571 QStringList retlist(
"OK" );
7616 QList<uint> disconnectedSlaves;
7628 MythEvent me(
"LOCAL_RECONNECT_TO_MASTER");
7634 disconnectedSlaves.clear();
7635 bool needsReschedule =
false;
7639 LOG(VB_GENERAL, LOG_ERR,
LOC +
7640 QString(
"Slave backend: %1 no longer connected")
7641 .arg(
pbs->getHostname()));
7643 bool isFallingAsleep =
true;
7647 if (elink->GetSocket() ==
pbs)
7649 if (!elink->IsFallingAsleep())
7650 isFallingAsleep =
false;
7652 elink->SetSocket(
nullptr);
7654 disconnectedSlaves.push_back(elink->GetInputID());
7658 if (
m_sched && !isFallingAsleep)
7659 needsReschedule =
true;
7661 QString message = QString(
"LOCAL_SLAVE_BACKEND_OFFLINE %1")
7662 .arg(
pbs->getHostname());
7670 QString(
"SLAVE_DISCONNECTED HOSTNAME %1")
7671 .arg(
pbs->getHostname()));
7680 if (chain !=
nullptr)
7691 std::this_thread::sleep_for(500us);
7693 if (enc->IsBusy() &&
7694 enc->GetChainID() == chain->
GetID())
7705 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 sock(%2) '%3' disconnected")
7706 .arg(
pbs->getBlockShutdown() ?
"Playback" :
"Monitor")
7707 .arg(quintptr(socket),0,16)
7708 .arg(
pbs->getHostname()) );
7709 pbs->SetDisconnected();
7714 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Playback sock still exists?");
7722 if (!disconnectedSlaves.isEmpty())
7731 MythEvent me(
"LOCAL_CONNECTION_CLOSED");
7745 LOG(VB_GENERAL, LOG_INFO, QString(
"BEFileTransfer sock(%1) disconnected")
7746 .arg(quintptr(socket),0,16) );
7758 LOG(VB_GENERAL, LOG_INFO, QString(
"Control sock(%1) disconnected")
7759 .arg(quintptr(socket),0,16) );
7769 LOG(VB_GENERAL, LOG_WARNING,
LOC +
7770 QString(
"Unknown socket closing MythSocket(0x%1)")
7771 .arg((intptr_t)socket,0,16));
7784 if (
pbs->isSlaveBackend() &&
7807 if (
pbs->isMediaServer() &&
7823 { return sock == pbs->getSocket(); });
7831 if (
id == ft->getSocket()->GetSocketDescriptor())
7840 if (sock == ft->getSocket())
7850 if (chain->GetID() ==
id)
7860 if (chain->IsHostSocket(sock))
7870 if (chain->ProgramIsAt(pginfo) >= 0)
7890 std::vector<LiveTVChain*> newChains;
7895 newChains.push_back(entry);
7905 if (closeApplication)
7911 QString lpath = QString(path);
7913 if (lpath.section(
'/', -2, -2) ==
"channels")
7916 QString
file = lpath.section(
'/', -1);
7920 query.
prepare(
"SELECT icon FROM channel "
7921 "WHERE deleted IS NULL AND icon LIKE :FILENAME ;");
7926 lpath = query.
value(0).toString();
7935 lpath = lpath.section(
'/', -1);
7937 QString fpath = lpath;
7938 if (fpath.endsWith(
".png"))
7939 fpath = fpath.left(fpath.length() - 4);
7945 if (pburl.startsWith(
"/"))
7947 lpath = pburl.section(
'/', 0, -2) +
"/" + lpath;
7948 LOG(VB_FILE, LOG_INFO,
LOC +
7949 QString(
"Local file path: %1").arg(lpath));
7953 LOG(VB_GENERAL, LOG_ERR,
LOC +
7954 QString(
"ERROR: LocalFilePath unable to find local "
7955 "path for '%1', found '%2' instead.")
7956 .arg(lpath, pburl));
7960 else if (!lpath.isEmpty())
7963 QString opath = lpath;
7966 if (!wantgroup.isEmpty())
7968 sgroup.
Init(wantgroup);
7969 lpath = QString(path);
7973 lpath = QFileInfo(lpath).fileName();
7976 QString tmpFile = sgroup.
FindFile(lpath);
7977 if (!tmpFile.isEmpty())
7980 LOG(VB_FILE, LOG_INFO,
LOC +
7981 QString(
"LocalFilePath(%1 '%2'), found file through "
7982 "exhaustive search at '%3'")
7983 .arg(path, opath, lpath));
7987 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"ERROR: LocalFilePath "
7988 "unable to find local path for '%1'.") .arg(path));
8004 auto *masterServerSock =
new MythSocket(-1,
this);
8009 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
8010 QString(
"Connecting to master server: %1:%2")
8011 .arg(server).arg(port));
8013 if (!masterServerSock->ConnectToHost(server, port))
8015 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
8016 "Connection to master server timed out.");
8018 masterServerSock->DecrRef();
8022 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Connected successfully");
8024 QString str = QString(
"ANN SlaveBackend %1 %2")
8028 QStringList strlist( str );
8033 elink->CancelNextRecording(
true);
8051 masterServerSock->SetReadyReadCallbackEnabled(
false);
8052 if (!masterServerSock->SendReceiveStringList(strlist, 1) ||
8053 (strlist[0] ==
"ERROR"))
8055 masterServerSock->DecrRef();
8056 masterServerSock =
nullptr;
8057 if (strlist.empty())
8059 LOG(VB_GENERAL, LOG_ERR,
LOC +
8060 "Failed to open master server socket, timeout");
8064 LOG(VB_GENERAL, LOG_ERR,
LOC +
8065 "Failed to open master server socket" +
8066 ((strlist.size() >= 2) ?
8067 QString(
", error was %1").arg(strlist[1]) :
8068 QString(
", remote error")));
8073 masterServerSock->SetReadyReadCallbackEnabled(
true);
8088 bool foundClient =
false;
8098 if ((*it)->isSlaveBackend())
8103 if (onlyBlockingClients && !(*it)->getBlockShutdown())
8111 return (foundClient);
8120 QStringList bcast(
"SHUTDOWN_NOW" );
8127 if (
pbs->isSlaveBackend())
8128 pbs->getSocket()->WriteStringList(bcast);
8138 bool needsReschedule =
event.ExtraData(0).toUInt() != 0U;
8139 for (
int i = 1; i <
event.ExtraDataCount(); i++)
8142 if (needsReschedule)
8148 const QList<uint> &offlineEncoderIDs,
bool needsReschedule)
8150 QStringList extraData;
8151 extraData.push_back(
8152 QString::number(
static_cast<uint>(needsReschedule)));
8154 QList<uint>::const_iterator it;
8155 for (it = offlineEncoderIDs.begin(); it != offlineEncoderIDs.end(); ++it)
8156 extraData.push_back(QString::number(*it));
8158 MythEvent me(
"LOCAL_SLAVE_BACKEND_ENCODERS_OFFLINE", extraData);
8164#if CONFIG_SYSTEMD_NOTIFY
8165 QStringList status2;
8168 status2 << QString(
"Master backend.");
8170 status2 << QString(
"Slave backend.");
8175 int playback = 0, frontend = 0, monitor = 0, slave = 0, media = 0;
8181 if (
pbs->IsDisconnected())
8183 if (
pbs->isSlaveBackend())
8185 else if (
pbs->isMediaServer())
8187 else if (
pbs->IsFrontend())
8189 else if (
pbs->getBlockShutdown())
8194 status2 << QString(
"Connections: Pl %1, Fr %2, Mo %3, Sl %4, MS %5, FT %6, Co %7")
8195 .arg(playback).arg(frontend).arg(monitor).arg(slave).arg(media)
8206 if (not elink->IsLocal())
8208 switch (elink->GetState())
8227 for (
auto & recording : recordings)
8235 while (!recordings.empty())
8239 recordings.pop_back();
8243 QString(
"Recordings: active %1, scheduled %2")
8244 .arg(active).arg(scheduled);
8248 QString status(
"STATUS=" + status2.join(
' '));
8249 (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