15#include "libmythbase/mythconfig.h"
20#if CONFIG_SYSTEMD_NOTIFY
21#include <systemd/sd-daemon.h>
26#include <QCoreApplication>
30#include <QWaitCondition>
31#include <QWriteLocker>
33#include <QRegularExpression>
37#include <QNetworkInterface>
38#include <QNetworkProxy>
39#include <QHostAddress>
54#include "libmythbase/mythversion.h"
85static constexpr std::chrono::milliseconds
PRT_TIMEOUT { 10ms };
89#define LOC QString("MainServer: ")
90#define LOC_WARN QString("MainServer, Warning: ")
91#define LOC_ERR QString("MainServer, Error: ")
96 bool followLinks,
bool checkexists)
100 bool success1 =
true;
101 bool success2 =
true;
103 LOG(VB_FILE, LOG_INFO,
LOC +
104 QString(
"About to delete file: %1").arg(
filename));
108 if (finfo.isSymLink())
112 QFile target(linktext);
113 success1 = target.remove();
116 LOG(VB_GENERAL, LOG_ERR,
LOC +
117 QString(
"Error deleting '%1' -> '%2'")
122 if (!checkexists || checkFile.exists())
124 success2 = checkFile.remove();
127 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error deleting '%1': %2")
131 return success1 && success2;
196 QMutexLocker locker(&
m_lock);
206 m_wait.wait(locker.mutex(), left.count());
212 QMutexLocker locker(&
m_lock);
237 QMap<int, EncoderLink *> *_tvList,
239 m_encoderList(_tvList),
241 m_ismaster(master), m_threadPool(
"ProcessRequestPool"),
242 m_sched(
sched), m_expirer(_expirer)
264 bool v4IsSet = !config_v4.isNull();
269 bool v6IsSet = !config_v6.isNull();
271 if (v6IsSet && !listenAddrs.contains(config_v6))
272 LOG(VB_GENERAL, LOG_WARNING,
LOC +
273 "Unable to find IPv6 address to bind");
275 if (v4IsSet && !listenAddrs.contains(config_v4))
276 LOG(VB_GENERAL, LOG_WARNING,
LOC +
277 "Unable to find IPv4 address to bind");
279 if ((v4IsSet && !listenAddrs.contains(config_v4))
280 && (v6IsSet && !listenAddrs.contains(config_v6))
283 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to find either IPv4 or IPv6 "
284 "address we can bind to, exiting");
434 auto *ms =
new MythSocket(socketDescriptor,
this);
435 if (ms->IsConnected())
447 QCoreApplication::processEvents();
455 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"No data on sock %1")
469 QStringList listline;
472 if (!
pbs->ReadStringList(listline) || listline.empty())
475 LOG(VB_GENERAL, LOG_INFO,
"No data in ProcessRequestWork()");
480 else if (!bIsControl)
487 LOG(VB_GENERAL, LOG_INFO,
LOC +
"No data in ProcessRequestWork()");
491 QString line = listline[0];
493 line = line.simplified();
494 QStringList tokens = line.split(
' ', Qt::SkipEmptyParts);
495 QString command = tokens[0];
497 if (command ==
"MYTH_PROTO_VERSION")
499 if (tokens.size() < 2)
505 if (command ==
"ANN")
510 if (command ==
"DONE")
521 LOG(VB_GENERAL, LOG_ERR,
LOC +
"ProcessRequest unknown socket");
527 if (command ==
"QUERY_FILETRANSFER")
529 if (tokens.size() != 2)
534 else if (command ==
"QUERY_RECORDINGS")
536 if (tokens.size() != 2)
541 else if (command ==
"QUERY_RECORDING")
545 else if (command ==
"GO_TO_SLEEP")
549 else if (command ==
"QUERY_FREE_SPACE")
553 else if (command ==
"QUERY_FREE_SPACE_LIST")
557 else if (command ==
"QUERY_FREE_SPACE_SUMMARY")
561 else if (command ==
"QUERY_LOAD")
565 else if (command ==
"QUERY_UPTIME")
569 else if (command ==
"QUERY_HOSTNAME")
573 else if (command ==
"QUERY_MEMSTATS")
577 else if (command ==
"QUERY_TIME_ZONE")
581 else if (command ==
"QUERY_CHECKFILE")
585 else if (command ==
"QUERY_FILE_EXISTS")
587 if (listline.size() < 2)
592 else if (command ==
"QUERY_FINDFILE")
594 if (listline.size() < 4)
599 else if (command ==
"QUERY_FILE_HASH")
601 if (listline.size() < 3)
606 else if (command ==
"QUERY_GUIDEDATATHROUGH")
610 else if (command ==
"DELETE_FILE")
612 if (listline.size() < 3)
617 else if (command ==
"MOVE_FILE")
619 if (listline.size() < 4)
624 else if (command ==
"STOP_RECORDING")
628 else if (command ==
"CHECK_RECORDING")
632 else if (command ==
"DELETE_RECORDING")
634 if (3 <= tokens.size() && tokens.size() <= 5)
636 bool force = (tokens.size() >= 4) && (tokens[3] ==
"FORCE");
637 bool forget = (tokens.size() >= 5) && (tokens[4] ==
"FORGET");
645 else if (command ==
"FORCE_DELETE_RECORDING")
649 else if (command ==
"UNDELETE_RECORDING")
653 else if (command ==
"ADD_CHILD_INPUT")
658 LOG(VB_GENERAL, LOG_ERR,
LOC +
659 "ADD_CHILD_INPUT command received in master context");
660 reslist << QString(
"ERROR: Called in master context");
662 else if (tokens.size() != 2)
664 reslist <<
"ERROR: Bad ADD_CHILD_INPUT request";
672 reslist << QString(
"ERROR: Failed to add child input");
676 else if (command ==
"RESCHEDULE_RECORDINGS")
678 listline.pop_front();
681 else if (command ==
"FORGET_RECORDING")
685 else if (command ==
"QUERY_GETALLPENDING")
687 if (tokens.size() == 1)
689 else if (tokens.size() == 2)
694 else if (command ==
"QUERY_GETALLSCHEDULED")
698 else if (command ==
"QUERY_GETCONFLICTING")
702 else if (command ==
"QUERY_GETEXPIRING")
706 else if (command ==
"QUERY_SG_GETFILELIST")
710 else if (command ==
"QUERY_SG_FILEQUERY")
714 else if (command ==
"GET_FREE_INPUT_INFO")
716 if (tokens.size() != 2)
721 else if (command ==
"QUERY_RECORDER")
723 if (tokens.size() != 2)
728 else if ((command ==
"QUERY_RECORDING_DEVICE") ||
729 (command ==
"QUERY_RECORDING_DEVICES"))
733 else if (command ==
"SET_NEXT_LIVETV_DIR")
735 if (tokens.size() != 3)
740 else if (command ==
"SET_CHANNEL_INFO")
744 else if (command ==
"QUERY_REMOTEENCODER")
746 if (tokens.size() != 2)
751 else if (command ==
"GET_RECORDER_FROM_NUM")
755 else if (command ==
"GET_RECORDER_NUM")
759 else if (command ==
"QUERY_GENPIXMAP2")
763 else if (command ==
"QUERY_PIXMAP_LASTMODIFIED")
767 else if (command ==
"QUERY_PIXMAP_GET_IF_MODIFIED")
771 else if (command ==
"QUERY_ISRECORDING")
775 else if (command ==
"MESSAGE")
777 if ((listline.size() >= 2) && (listline[1].startsWith(
"SET_VERBOSE")))
779 else if ((listline.size() >= 2) &&
780 (listline[1].startsWith(
"SET_LOG_LEVEL")))
785 else if (command ==
"FILL_PROGRAM_INFO")
789 else if (command ==
"LOCK_TUNER")
791 if (tokens.size() == 1)
793 else if (tokens.size() == 2)
798 else if (command ==
"FREE_TUNER")
800 if (tokens.size() != 2)
805 else if (command ==
"QUERY_ACTIVE_BACKENDS")
809 else if (command ==
"QUERY_IS_ACTIVE_BACKEND")
811 if (tokens.size() != 1)
816 else if (command ==
"QUERY_COMMBREAK")
818 if (tokens.size() != 3)
823 else if (command ==
"QUERY_CUTLIST")
825 if (tokens.size() != 3)
830 else if (command ==
"QUERY_BOOKMARK")
832 if (tokens.size() != 3)
837 else if (command ==
"SET_BOOKMARK")
839 if (tokens.size() != 4)
844 else if (command ==
"QUERY_SETTING")
846 if (tokens.size() != 3)
851 else if (command ==
"SET_SETTING")
853 if (tokens.size() != 4)
858 else if (command ==
"SCAN_VIDEOS")
862 else if (command ==
"SCAN_MUSIC")
866 else if (command ==
"MUSIC_TAG_UPDATE_VOLATILE")
868 if (listline.size() != 6)
873 else if (command ==
"MUSIC_CALC_TRACK_LENGTH")
875 if (listline.size() != 3)
880 else if (command ==
"MUSIC_TAG_UPDATE_METADATA")
882 if (listline.size() != 3)
887 else if (command ==
"MUSIC_FIND_ALBUMART")
889 if (listline.size() != 4)
894 else if (command ==
"MUSIC_TAG_GETIMAGE")
896 if (listline.size() < 4)
901 else if (command ==
"MUSIC_TAG_ADDIMAGE")
903 if (listline.size() < 5)
908 else if (command ==
"MUSIC_TAG_REMOVEIMAGE")
910 if (listline.size() < 4)
915 else if (command ==
"MUSIC_TAG_CHANGEIMAGE")
917 if (listline.size() < 5)
922 else if (command ==
"MUSIC_LYRICS_FIND")
924 if (listline.size() < 3)
929 else if (command ==
"MUSIC_LYRICS_GETGRABBERS")
933 else if (command ==
"MUSIC_LYRICS_SAVE")
935 if (listline.size() < 3)
940 else if (command ==
"IMAGE_SCAN")
943 QStringList reply = (listline.size() == 2)
945 : QStringList(
"ERROR") <<
"Bad: " << listline;
949 else if (command ==
"IMAGE_COPY")
952 QStringList reply = (listline.size() >= 2)
954 : QStringList(
"ERROR") <<
"Bad: " << listline;
958 else if (command ==
"IMAGE_MOVE")
961 QStringList reply = (listline.size() == 4)
963 HandleDbMove(listline[1], listline[2], listline[3])
964 : QStringList(
"ERROR") <<
"Bad: " << listline;
968 else if (command ==
"IMAGE_DELETE")
971 QStringList reply = (listline.size() == 2)
973 : QStringList(
"ERROR") <<
"Bad: " << listline;
977 else if (command ==
"IMAGE_HIDE")
980 QStringList reply = (listline.size() == 3)
982 HandleHide(listline[1].toInt() != 0, listline[2])
983 : QStringList(
"ERROR") <<
"Bad: " << listline;
987 else if (command ==
"IMAGE_TRANSFORM")
990 QStringList reply = (listline.size() == 3)
992 HandleTransform(listline[1].toInt(), listline[2])
993 : QStringList(
"ERROR") <<
"Bad: " << listline;
997 else if (command ==
"IMAGE_RENAME")
1000 QStringList reply = (listline.size() == 3)
1002 : QStringList(
"ERROR") <<
"Bad: " << listline;
1006 else if (command ==
"IMAGE_CREATE_DIRS")
1009 QStringList reply = (listline.size() >= 4)
1011 HandleDirs(listline[1], listline[2].toInt() != 0, listline.mid(3))
1012 : QStringList(
"ERROR") <<
"Bad: " << listline;
1016 else if (command ==
"IMAGE_COVER")
1019 QStringList reply = (listline.size() == 3)
1021 HandleCover(listline[1].toInt(), listline[2].toInt())
1022 : QStringList(
"ERROR") <<
"Bad: " << listline;
1026 else if (command ==
"IMAGE_IGNORE")
1029 QStringList reply = (listline.size() == 2)
1031 : QStringList(
"ERROR") <<
"Bad: " << listline;
1035 else if (command ==
"ALLOW_SHUTDOWN")
1037 if (tokens.size() != 1)
1042 else if (command ==
"BLOCK_SHUTDOWN")
1044 if (tokens.size() != 1)
1049 else if (command ==
"SHUTDOWN_NOW")
1051 if (tokens.size() != 1)
1056 if (listline.size() >= 2)
1057 halt_cmd = listline[1];
1059 if (!halt_cmd.isEmpty())
1061 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
1062 "Going down now as of Mainserver request!");
1071 else if (command ==
"BACKEND_MESSAGE")
1073 const QString& message = listline[1];
1074 QStringList extra( listline[2] );
1075 for (
int i = 3; i < listline.size(); i++)
1076 extra << listline[i];
1080 else if ((command ==
"DOWNLOAD_FILE") ||
1081 (command ==
"DOWNLOAD_FILE_NOW"))
1083 if (listline.size() != 4)
1088 else if (command ==
"REFRESH_BACKEND")
1090 LOG(VB_GENERAL, LOG_INFO ,
LOC +
"Reloading backend settings");
1093 else if (command ==
"OK")
1095 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Got 'OK' out of sequence.");
1097 else if (command ==
"UNKNOWN_COMMAND")
1099 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Got 'UNKNOWN_COMMAND' out of sequence.");
1103 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unknown command: " + command);
1107 QStringList strlist;
1108 strlist <<
"UNKNOWN_COMMAND";
1121 QStringList broadcast;
1122 QSet<QString> receivers;
1140 auto *me =
dynamic_cast<MythEvent *
>(e);
1144 QString message = me->
Message();
1146 if ((message ==
"PREVIEW_SUCCESS" || message ==
"PREVIEW_QUEUED") &&
1147 me->ExtraDataCount() >= 5)
1150 uint recordingID = me->ExtraData(0).toUInt();
1151 const QString&
filename = me->ExtraData(1);
1152 const QString& msg = me->ExtraData(2);
1153 const QString& datetime = me->ExtraData(3);
1155 if (message ==
"PREVIEW_QUEUED")
1157 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1158 QString(
"Preview Queued: '%1' '%2'")
1164 ok = ok &&
file.open(QIODevice::ReadOnly);
1168 QByteArray data =
file.readAll();
1169 QStringList extra(
"OK");
1170 extra.push_back(QString::number(recordingID));
1171 extra.push_back(msg);
1172 extra.push_back(datetime);
1173 extra.push_back(QString::number(data.size()));
1174#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1175 quint16 checksum = qChecksum(data.constData(), data.size());
1177 quint16 checksum = qChecksum(data);
1179 extra.push_back(QString::number(checksum));
1180 extra.push_back(QString(data.toBase64()));
1182 for (
uint i = 4 ; i < (
uint) me->ExtraDataCount(); i++)
1184 const QString& token = me->ExtraData(i);
1185 extra.push_back(token);
1189 receivers.insert(*it);
1194 if (receivers.empty())
1196 LOG(VB_GENERAL, LOG_ERR,
LOC +
1197 "PREVIEW_SUCCESS but no receivers.");
1201 broadcast.push_back(
"BACKEND_MESSAGE");
1202 broadcast.push_back(
"GENERATED_PIXMAP");
1207 message =
"PREVIEW_FAILED";
1213 if (message ==
"PREVIEW_FAILED" && me->ExtraDataCount() >= 5)
1215 const QString& pginfokey = me->ExtraData(0);
1216 const QString& msg = me->ExtraData(2);
1218 QStringList extra(
"ERROR");
1219 extra.push_back(pginfokey);
1220 extra.push_back(msg);
1221 for (
uint i = 4 ; i < (
uint) me->ExtraDataCount(); i++)
1223 const QString& token = me->ExtraData(i);
1224 extra.push_back(token);
1228 receivers.insert(*it);
1233 if (receivers.empty())
1235 LOG(VB_GENERAL, LOG_ERR,
LOC +
1236 "PREVIEW_FAILED but no receivers.");
1240 broadcast.push_back(
"BACKEND_MESSAGE");
1241 broadcast.push_back(
"GENERATED_PIXMAP");
1245 if (me->Message().startsWith(
"AUTO_EXPIRE"))
1247 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1248 if (tokens.size() != 3)
1250 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad AUTO_EXPIRE message");
1274 QString msg = QString(
"Cannot find program info for '%1', "
1275 "while attempting to Auto-Expire.")
1276 .arg(me->Message());
1277 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
1283 if (me->Message().startsWith(
"QUERY_NEXT_LIVETV_DIR") &&
m_sched)
1285 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1286 if (tokens.size() != 2)
1288 LOG(VB_GENERAL, LOG_ERR,
LOC +
1289 QString(
"Bad %1 message").arg(tokens[0]));
1297 if (me->Message().startsWith(
"STOP_RECORDING"))
1299 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1300 if (tokens.size() < 3 || tokens.size() > 3)
1302 LOG(VB_GENERAL, LOG_ERR,
LOC +
1303 QString(
"Bad STOP_RECORDING message: %1")
1304 .arg(me->Message()));
1317 LOG(VB_GENERAL, LOG_ERR,
LOC +
1318 QString(
"Cannot find program info for '%1' while "
1319 "attempting to stop recording.").arg(me->Message()));
1325 if ((me->Message().startsWith(
"DELETE_RECORDING")) ||
1326 (me->Message().startsWith(
"FORCE_DELETE_RECORDING")))
1328 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1329 if (tokens.size() < 3 || tokens.size() > 5)
1331 LOG(VB_GENERAL, LOG_ERR,
LOC +
1332 QString(
"Bad %1 message").arg(tokens[0]));
1336 bool force = (tokens.size() >= 4) && (tokens[3] ==
"FORCE");
1337 bool forget = (tokens.size() >= 5) && (tokens[4] ==
"FORGET");
1344 if (tokens[0] ==
"FORCE_DELETE_RECORDING")
1351 LOG(VB_GENERAL, LOG_ERR,
LOC +
1352 QString(
"Cannot find program info for '%1' while "
1353 "attempting to delete.").arg(me->Message()));
1359 if (me->Message().startsWith(
"UNDELETE_RECORDING"))
1361 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1362 if (tokens.size() < 3 || tokens.size() > 3)
1364 LOG(VB_GENERAL, LOG_ERR,
LOC +
1365 QString(
"Bad UNDELETE_RECORDING message: %1")
1366 .arg(me->Message()));
1379 LOG(VB_GENERAL, LOG_ERR,
LOC +
1380 QString(
"Cannot find program info for '%1' while "
1381 "attempting to undelete.").arg(me->Message()));
1387 if (me->Message().startsWith(
"ADD_CHILD_INPUT"))
1389 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1392 LOG(VB_GENERAL, LOG_ERR,
LOC +
1393 "ADD_CHILD_INPUT event received in slave context");
1395 else if (tokens.size() != 2)
1397 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad ADD_CHILD_INPUT message");
1406 if (me->Message().startsWith(
"RESCHEDULE_RECORDINGS") &&
m_sched)
1408 const QStringList& request = me->ExtraDataList();
1413 if (me->Message().startsWith(
"SCHEDULER_ADD_RECORDING") &&
m_sched)
1418 LOG(VB_GENERAL, LOG_ERR,
LOC +
1419 "Bad SCHEDULER_ADD_RECORDING message");
1427 if (me->Message().startsWith(
"UPDATE_RECORDING_STATUS") &&
m_sched)
1429 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1430 if (tokens.size() != 6)
1432 LOG(VB_GENERAL, LOG_ERR,
LOC +
1433 "Bad UPDATE_RECORDING_STATUS message");
1437 uint cardid = tokens[1].toUInt();
1438 uint chanid = tokens[2].toUInt();
1443 recstatus, recendts);
1449 if (me->Message().startsWith(
"LIVETV_EXITED"))
1451 const QString& chainid = me->ExtraData();
1459 if (me->Message() ==
"CLEAR_SETTINGS_CACHE")
1462 if (me->Message().startsWith(
"RESET_IDLETIME") &&
m_sched)
1465 if (me->Message() ==
"LOCAL_RECONNECT_TO_MASTER")
1468 if (me->Message() ==
"LOCAL_SLAVE_BACKEND_ENCODERS_OFFLINE")
1471 if (me->Message().startsWith(
"LOCAL_"))
1474 if (me->Message() ==
"CREATE_THUMBNAILS")
1477 if (me->Message() ==
"IMAGE_GET_METADATA")
1480 std::unique_ptr<MythEvent> mod_me {
nullptr};
1481 if (me->Message().startsWith(
"MASTER_UPDATE_REC_INFO"))
1483 QStringList tokens = me->Message().simplified().split(
" ");
1484 uint recordedid = 0;
1485 if (tokens.size() >= 2)
1486 recordedid = tokens[1].toUInt();
1487 if (recordedid == 0)
1501 mod_me = std::make_unique<MythEvent>(
"RECORDING_LIST_CHANGE UPDATE", list);
1509 if (me->Message().startsWith(
"DOWNLOAD_FILE"))
1511 QStringList extraDataList = me->ExtraDataList();
1512 QString localFile = extraDataList[1];
1513 QFile
file(localFile);
1514 QStringList tokens = me->Message().simplified().split(
" ");
1522 if ((tokens.size() >= 2) && (tokens[1] ==
"FINISHED"))
1525 mod_me = std::make_unique<MythEvent>(me->Message(), extraDataList);
1528 if (broadcast.empty())
1530 broadcast.push_back(
"BACKEND_MESSAGE");
1531 if (mod_me !=
nullptr)
1533 broadcast.push_back(mod_me->Message());
1534 broadcast += mod_me->ExtraDataList();
1538 broadcast.push_back(me->Message());
1539 broadcast += me->ExtraDataList();
1544 if (!broadcast.empty())
1547 std::vector<PlaybackSock *> localPBSList;
1552 localPBSList.push_back(
pbs);
1556 bool sendGlobal =
false;
1557 if (
m_ismaster && broadcast[1].startsWith(
"GLOBAL_"))
1559 broadcast[1].replace(
"GLOBAL_",
"LOCAL_");
1560 MythEvent me(broadcast[1], broadcast[2]);
1566 QSet<PlaybackSock*> sentSet;
1568 bool isSystemEvent = broadcast[1].startsWith(
"SYSTEM_EVENT ");
1571 std::vector<PlaybackSock*>::const_iterator iter;
1572 for (iter = localPBSList.begin(); iter != localPBSList.end(); ++iter)
1576 if (sentSet.contains(
pbs) ||
pbs->IsDisconnected())
1579 if (!receivers.empty() && !receivers.contains(
pbs->getHostname()))
1582 sentSet.insert(
pbs);
1584 bool reallysendit =
false;
1586 if (broadcast[1] ==
"CLEAR_SETTINGS_CACHE")
1589 (
pbs->isSlaveBackend() ||
pbs->wantsEvents()))
1590 reallysendit =
true;
1592 else if (sendGlobal)
1594 if (
pbs->isSlaveBackend())
1595 reallysendit =
true;
1597 else if (
pbs->wantsEvents())
1599 reallysendit =
true;
1606 if (!
pbs->wantsSystemEvents())
1610 if (!
pbs->wantsOnlySystemEvents())
1612 if (sentSetSystemEvent.contains(
pbs->getHostname()))
1615 sentSetSystemEvent <<
pbs->getHostname();
1618 else if (
pbs->wantsOnlySystemEvents())
1630 for (iter = localPBSList.begin(); iter != localPBSList.end(); ++iter)
1648 QStringList retlist;
1649 const QString&
version = slist[1];
1650 if (
version != MYTH_PROTO_VERSION)
1652 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1653 "MainServer::HandleVersion - Client speaks protocol version " +
1654 version +
" but we speak " + MYTH_PROTO_VERSION +
'!');
1655 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1661 if (slist.size() < 3)
1663 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1664 "MainServer::HandleVersion - Client did not pass protocol "
1665 "token. Refusing connection!");
1666 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1672 const QString& token = slist[2];
1673 if (token != QString::fromUtf8(MYTH_PROTO_TOKEN))
1675 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1676 QString(
"MainServer::HandleVersion - Client sent incorrect "
1677 "protocol token \"%1\" for protocol version. Refusing "
1678 "connection!").arg(token));
1679 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1685 retlist <<
"ACCEPT" << MYTH_PROTO_VERSION;
1714 QStringList retlist(
"OK" );
1715 QStringList errlist(
"ERROR" );
1717 if (commands.size() < 3 || commands.size() > 6)
1720 if (commands.size() == 2)
1721 info = QString(
" %1").arg(commands[1]);
1723 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Received malformed ANN%1 query")
1726 errlist <<
"malformed_ann_query";
1734 if (
pbs->getSocket() == socket)
1736 LOG(VB_GENERAL, LOG_WARNING,
LOC +
1737 QString(
"Client %1 is trying to announce a socket "
1747 if (commands[1] ==
"Playback" || commands[1] ==
"Monitor" ||
1748 commands[1] ==
"Frontend")
1750 if (commands.size() < 4)
1752 LOG(VB_GENERAL, LOG_ERR,
LOC +
1753 QString(
"Received malformed ANN %1 query")
1756 errlist <<
"malformed_ann_query";
1773 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"MainServer::ANN %1")
1775 LOG(VB_GENERAL, LOG_INFO,
LOC +
1776 QString(
"adding: %1(%2) as a client (events: %3)")
1778 .arg(quintptr(socket),0,16)
1780 pbs->setBlockShutdown((commands[1] ==
"Playback") ||
1781 (commands[1] ==
"Frontend"));
1783 if (commands[1] ==
"Frontend")
1785 pbs->SetAsFrontend();
1787 frontend->m_name = commands[2];
1802 else if (commands[1] ==
"MediaServer")
1804 if (commands.size() < 3)
1806 LOG(VB_GENERAL, LOG_ERR,
LOC +
1807 "Received malformed ANN MediaServer query");
1808 errlist <<
"malformed_ann_query";
1817 pbs->setAsMediaServer();
1818 pbs->setBlockShutdown(
false);
1823 QString(
"CLIENT_CONNECTED HOSTNAME %1").arg(commands[2]));
1825 else if (commands[1] ==
"SlaveBackend")
1827 if (commands.size() < 4)
1829 LOG(VB_GENERAL, LOG_ERR,
LOC +
1830 QString(
"Received malformed ANN %1 query")
1832 errlist <<
"malformed_ann_query";
1844 LOG(VB_GENERAL, LOG_INFO,
LOC +
1845 QString(
"adding: %1 as a slave backend server")
1847 pbs->setAsSlaveBackend();
1848 pbs->setIP(commands[3]);
1853 QStringList::const_iterator sit = slist.
cbegin()+1;
1854 while (sit != slist.cend())
1857 if (!recinfo->GetChanID())
1867 bool wasAsleep =
true;
1871 if (elink->GetHostName() == commands[2])
1873 if (! (elink->IsWaking() || elink->IsAsleep()))
1875 elink->SetSocket(
pbs);
1883 QString message = QString(
"LOCAL_SLAVE_BACKEND_ONLINE %2")
1888 pbs->setBlockShutdown(
false);
1893 QString(
"SLAVE_CONNECTED HOSTNAME %1").arg(commands[2]));
1895 else if (commands[1] ==
"FileTransfer")
1897 if (slist.size() < 3)
1899 LOG(VB_GENERAL, LOG_ERR,
LOC +
1900 "Received malformed FileTransfer command");
1901 errlist <<
"malformed_filetransfer_command";
1906 LOG(VB_NETWORK, LOG_INFO,
LOC +
1907 "MainServer::HandleAnnounce FileTransfer");
1908 LOG(VB_NETWORK, LOG_INFO,
LOC +
1909 QString(
"adding: %1 as a remote file transfer") .arg(commands[2]));
1910 QStringList::const_iterator it = slist.cbegin();
1911 QString path = *(++it);
1912 QString wantgroup = *(++it);
1914 QStringList checkfiles;
1916 for (++it; it != slist.cend(); ++it)
1920 bool writemode =
false;
1921 bool usereadahead =
true;
1922 std::chrono::milliseconds timeout_ms = 2s;
1923 if (commands.size() > 3)
1924 writemode = (commands[3].toInt() != 0);
1926 if (commands.size() > 4)
1927 usereadahead = (commands[4].toInt() != 0);
1929 if (commands.size() > 5)
1930 timeout_ms = std::chrono::milliseconds(commands[5].toInt());
1934 if (wantgroup.isEmpty())
1935 wantgroup =
"Default";
1941 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to determine directory "
1942 "to write to in FileTransfer write command");
1943 errlist <<
"filetransfer_directory_not_found";
1950 LOG(VB_GENERAL, LOG_ERR,
LOC +
1951 QString(
"FileTransfer write filename is empty in path '%1'.")
1953 errlist <<
"filetransfer_filename_empty";
1958 if ((path.contains(
"/../")) ||
1959 (path.startsWith(
"../")))
1961 LOG(VB_GENERAL, LOG_ERR,
LOC +
1962 QString(
"FileTransfer write filename '%1' does not pass "
1963 "sanity checks.") .arg(path));
1964 errlist <<
"filetransfer_filename_dangerous";
1978 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Empty filename, cowardly aborting!");
1979 errlist <<
"filetransfer_filename_empty";
1988 LOG(VB_GENERAL, LOG_ERR,
LOC +
1989 QString(
"FileTransfer filename '%1' is actually a directory, "
1990 "cannot transfer.") .arg(
filename));
1991 errlist <<
"filetransfer_filename_is_a_directory";
1998 QString dirPath = finfo.absolutePath();
2002 if (!qdir.mkpath(dirPath))
2004 LOG(VB_GENERAL, LOG_ERR,
LOC +
2005 QString(
"FileTransfer filename '%1' is in a "
2006 "subdirectory which does not exist, and can "
2007 "not be created.") .arg(
filename));
2008 errlist <<
"filetransfer_unable_to_create_subdirectory";
2028 LOG(VB_GENERAL, LOG_ERR,
LOC +
2029 QString(
"Can't open %1").arg(
filename));
2030 errlist <<
"filetransfer_unable_to_open_file";
2037 LOG(VB_GENERAL, LOG_INFO,
LOC +
2038 QString(
"adding: %1(%2) as a file transfer")
2040 .arg(quintptr(socket),0,16));
2050 if (!checkfiles.empty())
2053 QDir dir = fi.absoluteDir();
2054 for (
const auto &
file : std::as_const(checkfiles))
2056 if (dir.exists(
file) &&
2057 ((
file).endsWith(
".srt") ||
2090 QStringList strList(
"ERROR");
2105 bool do_write =
false;
2120 LOG(VB_GENERAL, LOG_ERR,
LOC +
2121 "SendResponse: Unable to write to client socket, as it's no "
2137 QString playbackhost =
pbs->getHostname();
2139 QMap<QString,ProgramInfo*> recMap;
2144 QMap<QString,bool> isJobRunning =
2150 if ((
type ==
"Ascending") || (
type ==
"Play"))
2152 else if ((
type ==
"Descending") || (
type ==
"Delete"))
2157 destination, (
type ==
"Recording"),
2158 inUseMap, isJobRunning, recMap, sort);
2160 QMap<QString,ProgramInfo*>::iterator mit = recMap.begin();
2161 for (; mit != recMap.end(); mit = recMap.erase(mit))
2164 QStringList outputlist(QString::number(destination.
size()));
2165 QMap<QString, int> backendPortMap;
2169 for (
auto* proginfo : destination)
2180 proginfo->GetBasename()));
2181 if (!proginfo->GetFilesize())
2184 if (tmpURL.startsWith(
'/'))
2186 QFile checkFile(tmpURL);
2187 if (!tmpURL.isEmpty() && checkFile.exists())
2189 proginfo->SetFilesize(checkFile.size());
2190 if (proginfo->GetRecordingEndTime() <
2193 proginfo->SaveFilesize(proginfo->GetFilesize());
2202 if (proginfo->GetPathname().isEmpty())
2204 LOG(VB_GENERAL, LOG_ERR,
LOC +
2205 QString(
"HandleQueryRecordings() "
2206 "Couldn't find backend for:\n\t\t\t%1")
2209 proginfo->SetFilesize(0);
2210 proginfo->SetPathname(
"file not found");
2215 if (!proginfo->GetFilesize())
2219 LOG(VB_GENERAL, LOG_ERR,
LOC +
2220 "MainServer::HandleQueryRecordings()"
2221 "\n\t\t\tCould not fill program info "
2226 if (proginfo->GetRecordingEndTime() <
2229 proginfo->SaveFilesize(proginfo->GetFilesize());
2238 if (!backendPortMap.contains(
hostname))
2250 proginfo->ToStringList(outputlist);
2263 if (slist.size() < 3)
2265 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad QUERY_RECORDING query");
2270 QString command = slist[1].toUpper();
2273 if (command ==
"BASENAME")
2277 else if (command ==
"TIMESLOT")
2279 if (slist.size() < 4)
2281 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad QUERY_RECORDING query");
2286 pginfo =
new ProgramInfo(slist[2].toUInt(), recstartts);
2289 QStringList strlist;
2310 const QString& playbackhost = slist[1];
2312 QStringList::const_iterator it = slist.cbegin() + 2;
2327 const QFileInfo
info(lpath);
2331 QStringList strlist;
2349 std::this_thread::sleep_for(3s + std::chrono::microseconds(
MythRandom(0, 2000)));
2354 QString logInfo = QString(
"recording id %1 (chanid %2 at %3)")
2359 QString name = QString(
"deleteThread%1%2").arg(getpid()).arg(
MythRandom());
2365 QString msg = QString(
"ERROR opening database connection for Delete "
2366 "Thread for chanid %1 recorded at %2. Program "
2367 "will NOT be deleted.")
2370 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2380 QString msg = QString(
"ERROR retrieving program info when trying to "
2381 "delete program for chanid %1 recorded at %2. "
2382 "Recording will NOT be deleted.")
2385 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2395 if ((!checkFile.exists()) && pginfo.
GetFilesize() &&
2398 LOG(VB_GENERAL, LOG_ERR,
LOC +
2399 QString(
"ERROR when trying to delete file: %1. File "
2400 "doesn't exist. Database metadata will not be removed.")
2418 bool errmsg =
false;
2433 if ((fd < 0) && checkFile.exists())
2439 std::this_thread::sleep_for(2s);
2440 if (checkFile.exists())
2446 LOG(VB_GENERAL, LOG_ERR,
LOC +
2447 QString(
"Error deleting file: %1. Keeping metadata in database.")
2462 QStringList nameFilters;
2463 nameFilters.push_back(fInfo.fileName() +
"*.png");
2464 nameFilters.push_back(fInfo.fileName() +
"*.jpg");
2465 nameFilters.push_back(fInfo.fileName() +
".tmp");
2466 nameFilters.push_back(fInfo.fileName() +
".old");
2467 nameFilters.push_back(fInfo.fileName() +
".map");
2468 nameFilters.push_back(fInfo.fileName() +
".tmp.map");
2469 nameFilters.push_back(fInfo.baseName() +
".srt");
2471 QDir dir (fInfo.path());
2472 QFileInfoList miscFiles = dir.entryInfoList(nameFilters);
2474 for (
const auto &
file : std::as_const(miscFiles))
2476 QString sFileName =
file.absoluteFilePath();
2488 if (slowDeletes && fd >= 0)
2494 QString logInfo = QString(
"recording id %1 filename %2")
2497 LOG(VB_GENERAL, LOG_NOTICE,
"DeleteRecordedFiles - " + logInfo);
2501 query.
prepare(
"SELECT basename, hostname, storagegroup FROM recordedfile "
2502 "WHERE recordedid = :RECORDEDID;");
2505 if (!query.
exec() || !query.
size())
2508 LOG(VB_GENERAL, LOG_ERR,
LOC +
2509 QString(
"Error querying recordedfiles for %1.") .arg(logInfo));
2512 while (query.
next())
2514 QString basename = query.
value(0).toString();
2517 bool deleteInDB =
false;
2519 if (basename == QFileInfo(ds->
m_filename).fileName())
2548 update.
prepare(
"DELETE FROM recordedfile "
2549 "WHERE recordedid = :RECORDEDID "
2550 "AND basename = :BASENAME ;");
2552 update.
bindValue(
":BASENAME", basename);
2556 LOG(VB_GENERAL, LOG_ERR,
LOC +
2557 QString(
"Error querying recordedfile (%1) for %2.")
2558 .arg(query.
value(1).toString(), logInfo));
2566 QString logInfo = QString(
"recording id %1 (chanid %2 at %3)")
2570 LOG(VB_GENERAL, LOG_NOTICE,
"DoDeleteINDB - " + logInfo);
2573 query.
prepare(
"DELETE FROM recorded WHERE recordedid = :RECORDEDID AND "
2578 if (!query.
exec() || !query.
size())
2581 LOG(VB_GENERAL, LOG_ERR,
LOC +
2582 QString(
"Error deleting recorded entry for %1.") .arg(logInfo));
2585 std::this_thread::sleep_for(1s);
2588 QString msg = QString(
"RECORDING_LIST_CHANGE DELETE %1")
2593 std::this_thread::sleep_for(3s);
2595 query.
prepare(
"DELETE FROM recordedmarkup "
2596 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2603 LOG(VB_GENERAL, LOG_ERR,
LOC +
2604 QString(
"Error deleting recordedmarkup for %1.") .arg(logInfo));
2607 query.
prepare(
"DELETE FROM recordedseek "
2608 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2615 LOG(VB_GENERAL, LOG_ERR,
LOC +
2616 QString(
"Error deleting recordedseek for %1.")
2631 bool deleteBrokenSymlinks)
2635 QString linktext =
"";
2636 QByteArray fname =
filename.toLocal8Bit();
2639 LOG(VB_FILE, LOG_INFO,
LOC +
2640 QString(
"About to unlink/delete file: '%1'")
2641 .arg(fname.constData()));
2643 QString errmsg = QString(
"Delete Error '%1'").arg(fname.constData());
2644 if (finfo.isSymLink())
2647 QByteArray alink = linktext.toLocal8Bit();
2648 errmsg += QString(
" -> '%2'").arg(alink.constData());
2651 if (followLinks && finfo.isSymLink())
2653 if (!finfo.exists() && deleteBrokenSymlinks)
2654 unlink(fname.constData());
2660 unlink(fname.constData());
2663 else if (!finfo.isSymLink())
2670 int err = unlink(fname.constData());
2675 if (fd < 0 && open_errno != EISDIR)
2676 LOG(VB_GENERAL, LOG_ERR,
LOC + errmsg +
ENO);
2692 QByteArray fname =
filename.toLocal8Bit();
2693 QString msg = QString(
"Error deleting '%1'").arg(fname.constData());
2694 int fd = open(fname.constData(), O_WRONLY);
2698 if (errno == EISDIR)
2703 LOG(VB_GENERAL, LOG_ERR, msg +
" could not delete directory " +
ENO);
2709 LOG(VB_GENERAL, LOG_ERR, msg +
" could not open " +
ENO);
2713 else if (unlink(fname.constData()))
2715 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
" could not unlink " +
ENO);
2732 const QString &
filename, off_t fsize)
2745 query.
prepare(
"SELECT COUNT(cardid) FROM capturecard;");
2747 cards = query.
value(0).toInt();
2751 constexpr std::chrono::milliseconds sleep_time = 500ms;
2752 const size_t min_tps = 8LL * 1024 * 1024;
2753 const auto calc_tps = (size_t) (cards * 1.2 * (22200000LL / 8.0));
2754 const size_t tps = std::max(min_tps, calc_tps);
2755 const auto increment = (size_t) (tps * (sleep_time.count() * 0.001F));
2757 LOG(VB_FILE, LOG_INFO,
LOC +
2758 QString(
"Truncating '%1' by %2 MB every %3 milliseconds")
2760 .arg(increment / (1024.0 * 1024.0), 0,
'f', 2)
2761 .arg(sleep_time.count()));
2763 GetMythDB()->GetDBManager()->PurgeIdleConnections(
false);
2769 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"Truncating '%1' to %2 MB")
2770 .arg(
filename).arg(fsize / (1024.0 * 1024.0), 0,
'f', 2));
2773 int err = ftruncate(fd, fsize);
2776 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error truncating '%1'")
2780 return 0 ==
close(fd);
2785 if (pginfo && ((count % 100) == 0))
2790 std::this_thread::sleep_for(sleep_time);
2793 bool ok = (0 ==
close(fd));
2798 LOG(VB_FILE, LOG_INFO,
LOC +
2799 QString(
"Finished truncating '%1'").arg(
filename));
2809 pbssock =
pbs->getSocket();
2811 QStringList::const_iterator it = slist.cbegin() + 1;
2833 result = iter.key();
2838 QStringList outputlist( QString::number(result) );
2845 QStringList::const_iterator it = slist.cbegin() + 1;
2857 bool hasConflicts =
false;
2859 for (
auto *pInfo : schedList)
2877 pbssock =
pbs->getSocket();
2900 (*m_encoderList)[num]->StopRecording();
2908 QStringList outputlist(
"0" );
2933 recnum = iter.key();
2940 std::this_thread::sleep_for(100us);
2956 QStringList outputlist( QString::number(recnum) );
2963 bool forceMetadataDelete,
2971 qDebug() <<
"HandleDeleteRecording(chanid, starttime) Empty Recording ID";
2978 pbssock =
pbs->getSocket();
2980 QStringList outputlist( QString::number(0) );
2990 bool forceMetadataDelete)
2992 QStringList::const_iterator it = slist.cbegin() + 1;
2997 qDebug() <<
"HandleDeleteRecording(QStringList) Empty Recording ID";
3006 bool forceMetadataDelete,
bool lexpirer,
bool forgetHistory)
3008 int resultCode = -1;
3011 pbssock =
pbs->getSocket();
3013 bool justexpire = lexpirer ?
false :
3021 LOG(VB_GENERAL, LOG_ERR,
LOC +
3022 QString(
"ERROR when trying to delete file for %1. Unable "
3023 "to determine filename of recording.")
3029 QStringList outputlist(QString::number(resultCode));
3039 if (justexpire && !forceMetadataDelete &&
3048 QStringList outputlist( QString::number(0) );
3072 QStringList outputlist( QString::number(num) );
3082 bool fileExists = checkFile.exists();
3085 QFile checkFileUTF8(QString::fromUtf8(
filename.toLatin1().constData()));
3086 fileExists = checkFileUTF8.exists();
3095 if (fileExists || !recinfo.
GetFilesize() || forceMetadataDelete)
3101 qDebug() <<
"DoHandleDeleteRecording() Empty Recording ID";
3108 forceMetadataDelete);
3109 deleteThread->start();
3114 QString logInfo = QString(
"chanid %1")
3118 LOG(VB_GENERAL, LOG_ERR,
LOC +
3119 QString(
"ERROR when trying to delete file: %1. File doesn't "
3120 "exist. Database metadata will not be removed.")
3127 QStringList outputlist( QString::number(resultCode) );
3139 if (fileExists || !recinfo.
GetFilesize() || forceMetadataDelete)
3142 QString(
"REC_DELETED CHANID %1 STARTTIME %2")
3152 if (slist.size() == 3)
3161 QStringList::const_iterator it = slist.cbegin()+1;
3175 pbssock =
pbs->getSocket();
3189 QStringList outputlist( QString::number(ret) );
3226 result = QStringList(QString::number(1));
3230 result = QStringList(QString::number(0));
3249 LOG(VB_GENERAL, LOG_INFO,
LOC +
"HandleAddChildInput: Already locked");
3253 LOG(VB_GENERAL, LOG_INFO,
LOC +
3254 QString(
"HandleAddChildInput: Handling input %1").arg(inputid));
3264 LOG(VB_GENERAL, LOG_ERR,
LOC +
3265 QString(
"HandleAddChildInput: "
3266 "Failed to add child to input %1").arg(inputid));
3272 LOG(VB_GENERAL, LOG_INFO,
LOC +
3273 QString(
"HandleAddChildInput: Added child input %1").arg(childid));
3281 auto *tv =
new TVRec(childid);
3282 if (!tv || !tv->Init())
3284 LOG(VB_GENERAL, LOG_ERR,
LOC +
3285 QString(
"HandleAddChildInput: "
3286 "Failed to initialize input %1").arg(childid));
3295 (*m_encoderList)[childid] = enc;
3302 LOG(VB_GENERAL, LOG_ERR,
LOC +
3303 QString(
"HandleAddChildInput: "
3304 "Failed to add remote input %1").arg(childid));
3314 (*m_encoderList)[childid] = enc;
3323 auto *tv =
new TVRec(inputid);
3324 if (!tv || !tv->Init())
3326 LOG(VB_GENERAL, LOG_ERR,
LOC +
3327 QString(
"HandleAddChildInput: "
3328 "Failed to initialize input %1").arg(inputid));
3336 (*m_encoderList)[inputid] = enc;
3342 LOG(VB_GENERAL, LOG_INFO,
LOC +
3343 QString(
"HandleAddChildInput: "
3344 "Successfully handled input %1").arg(inputid));
3351 QStringList::const_iterator it = slist.cbegin() + 1;
3358 pbssock =
pbs->getSocket();
3361 QStringList outputlist( QString::number(0) );
3373 QStringList strlist;
3376 if (!sleepCmd.isEmpty())
3380 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
3381 "Received GO_TO_SLEEP command from master, running SleepCommand.");
3386 strlist <<
"ERROR: SleepCommand is empty";
3387 LOG(VB_GENERAL, LOG_ERR,
LOC +
3388 "ERROR: in HandleGoToSleep(), but no SleepCommand found!");
3404 QStringList strlist;
3438 QStringList strlist;
3457 QStringList shortlist;
3458 if (strlist.size() < 4)
3460 shortlist << QString(
"0");
3461 shortlist << QString(
"0");
3465 unsigned int index = (
uint)(strlist.size()) - 2;
3466 shortlist << strlist[index++];
3467 shortlist << strlist[index++];
3483 QStringList strlist;
3485#if defined(_WIN32) || defined(Q_OS_ANDROID)
3486 strlist <<
"0" <<
"0" <<
"0";
3492 strlist <<
"getloadavg() failed";
3496 strlist << QString::number(loads[0])
3497 << QString::number(loads[1])
3498 << QString::number(loads[2]);
3513 QStringList strlist;
3514 std::chrono::seconds uptime = 0s;
3517 strlist << QString::number(uptime.count());
3521 strlist <<
"Could not determine uptime.";
3535 QStringList strlist;
3550 QStringList strlist;
3556 if (
getMemStats(totalMB, freeMB, totalVM, freeVM))
3558 strlist << QString::number(totalMB) << QString::number(freeMB)
3559 << QString::number(totalVM) << QString::number(freeVM);
3564 strlist <<
"Could not determine memory stats.";
3578 QStringList strlist;
3593 bool checkSlaves = slist[1].toInt() != 0;
3595 QStringList::const_iterator it = slist.cbegin() + 2;
3611 QStringList outputlist( QString::number(
static_cast<int>(
exists)) );
3631 QStringList strlist( QString::number(
static_cast<int>(
exists)) );
3643 QString storageGroup =
"Default";
3648 switch (slist.size()) {
3650 if (!slist[3].isEmpty())
3654 if (slist[2].isEmpty())
3655 storageGroup = slist[2];
3663 LOG(VB_GENERAL, LOG_ERR,
LOC +
3664 QString(
"ERROR checking for file, filename '%1' "
3665 "fails sanity checks").arg(
filename));
3672 LOG(VB_GENERAL, LOG_ERR,
LOC +
3673 "ERROR, invalid input count for QUERY_FILE_HASH");
3710 const QString&
filename = slist[1];
3711 QString storageGroup =
"Default";
3712 QStringList retlist;
3714 if (slist.size() > 2)
3715 storageGroup = slist[2];
3721 LOG(VB_GENERAL, LOG_ERR,
LOC +
3722 QString(
"ERROR checking for file, filename '%1' "
3723 "fails sanity checks").arg(
filename));
3729 if (storageGroup.isEmpty())
3730 storageGroup =
"Default";
3736 if (!fullname.isEmpty())
3739 retlist << fullname;
3741 struct stat fileinfo {};
3742 if (stat(fullname.toLocal8Bit().constData(), &fileinfo) >= 0)
3744 retlist << QString::number(fileinfo.st_dev);
3745 retlist << QString::number(fileinfo.st_ino);
3746 retlist << QString::number(fileinfo.st_mode);
3747 retlist << QString::number(fileinfo.st_nlink);
3748 retlist << QString::number(fileinfo.st_uid);
3749 retlist << QString::number(fileinfo.st_gid);
3750 retlist << QString::number(fileinfo.st_rdev);
3751 retlist << QString::number(fileinfo.st_size);
3756 retlist << QString::number(fileinfo.st_blksize);
3757 retlist << QString::number(fileinfo.st_blocks);
3759 retlist << QString::number(fileinfo.st_atime);
3760 retlist << QString::number(fileinfo.st_mtime);
3761 retlist << QString::number(fileinfo.st_ctime);
3775 query.
prepare(
"SELECT MAX(endtime) FROM program WHERE manualid = 0;");
3785 QDateTime GuideDataThrough;
3787 QStringList strlist;
3791 if (GuideDataThrough.isNull())
3792 strlist << QString(
"0000-00-00 00:00");
3794 strlist << GuideDataThrough.toString(
"yyyy-MM-dd hh:mm");
3800 const QString& tmptable,
int recordid)
3804 QStringList strList;
3808 if (tmptable.isEmpty())
3820 query.
prepare(
"SELECT NULL FROM record "
3821 "WHERE recordid = :RECID;");
3827 record->m_recordID = recordid;
3828 if (record->Load() &&
3834 query.
prepare(
"DELETE FROM program WHERE manualid = :RECID;");
3844 strList << QString::number(0);
3845 strList << QString::number(0);
3855 QStringList strList;
3860 strList << QString::number(0);
3870 QStringList::const_iterator it = slist.cbegin() + 1;
3873 QStringList strlist;
3878 strlist << QString::number(0);
3887 QStringList strList;
3892 strList << QString::number(0);
3901 QStringList strList;
3903 if ((sList.size() < 4) || (sList.size() > 5))
3905 LOG(VB_GENERAL, LOG_ERR,
LOC +
3906 QString(
"HandleSGGetFileList: Invalid Request. %1")
3907 .arg(sList.join(
"[]:[]")));
3908 strList <<
"EMPTY LIST";
3914 const QString& wantHost = sList.at(1);
3915 QHostAddress wantHostaddr(wantHost);
3916 const QString& groupname = sList.at(2);
3917 const QString& path = sList.at(3);
3918 bool fileNamesOnly =
false;
3920 if (sList.size() >= 5)
3921 fileNamesOnly = (sList.at(4).toInt() != 0);
3923 bool slaveUnreachable =
false;
3925 LOG(VB_FILE, LOG_INFO,
LOC +
3926 QString(
"HandleSGGetFileList: group = %1 host = %2 "
3927 " path = %3 wanthost = %4")
3928 .arg(groupname, host, path, wantHost));
3932 if ((host.toLower() == wantHost.toLower()) ||
3933 (!addr.isEmpty() && addr == wantHostaddr.toString()))
3936 LOG(VB_FILE, LOG_INFO,
LOC +
"HandleSGGetFileList: Getting local info");
3947 LOG(VB_FILE, LOG_INFO,
LOC +
3948 "HandleSGGetFileList: Getting remote info");
3952 slaveUnreachable =
false;
3956 LOG(VB_FILE, LOG_INFO,
LOC +
3957 QString(
"HandleSGGetFileList: Failed to grab slave socket "
3958 ": %1 :").arg(wantHost));
3959 slaveUnreachable =
true;
3964 if (slaveUnreachable)
3965 strList <<
"SLAVE UNREACHABLE: " << host;
3967 if (strList.isEmpty() || (strList.at(0) ==
"0"))
3968 strList <<
"EMPTY LIST";
3978 QString storageGroup = slist[2];
3980 bool allowFallback =
true;
3981 bool useRegex =
false;
3982 QStringList fileList;
3984 if (!QHostAddress(
hostname).isNull())
3986 LOG(VB_GENERAL, LOG_ERR, QString(
"Mainserver: QUERY_FINDFILE called "
3987 "with IP (%1) instead of hostname. "
3988 "This is invalid.").arg(
hostname));
3994 if (storageGroup.isEmpty())
3995 storageGroup =
"Default";
4000 LOG(VB_GENERAL, LOG_ERR,
LOC +
4001 QString(
"ERROR QueryFindFile, filename '%1' "
4002 "fails sanity checks").arg(
filename));
4003 fileList <<
"ERROR: Bad/Missing Filename";
4008 if (slist.size() >= 5)
4009 useRegex = (slist[4].toInt() > 0);
4011 if (slist.size() >= 6)
4012 allowFallback = (slist[5].toInt() > 0);
4014 LOG(VB_FILE, LOG_INFO,
LOC +
4015 QString(
"Looking for file '%1' on host '%2' in group '%3' (useregex: %4, allowfallback: %5")
4029 QStringList files = sgroup.
GetFileList(
'/' + fi.path());
4031 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Looking in dir '%1' for '%2'")
4032 .arg(fi.path(), fi.fileName()));
4034 for (
int x = 0; x < files.size(); x++)
4036 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Found '%1 - %2'").arg(x).arg(files[x]));
4039 QStringList filteredFiles = files.filter(QRegularExpression(fi.fileName()));
4040 for (
const QString&
file : std::as_const(filteredFiles))
4044 fi.path() +
'/' +
file,
4060 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Checking remote host '%1' for file").arg(
hostname));
4068 if (!slaveFiles.isEmpty() && slaveFiles[0] !=
"NOT FOUND" && !slaveFiles[0].startsWith(
"ERROR: "))
4069 fileList += slaveFiles;
4075 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Slave '%1' was unreachable").arg(
hostname));
4076 fileList << QString(
"ERROR: SLAVE UNREACHABLE: %1").arg(
hostname);
4084 if (
m_ismaster && fileList.isEmpty() && allowFallback)
4089 QString sql =
"SELECT DISTINCT hostname "
4090 "FROM storagegroup "
4091 "WHERE groupname = :GROUP "
4092 "AND hostname != :HOSTNAME";
4094 query.
bindValue(
":GROUP", storageGroup);
4100 fileList <<
"ERROR: failed to get host list";
4116 QStringList files = sgroup.
GetFileList(
'/' + fi.path());
4118 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Looking in dir '%1' for '%2'")
4119 .arg(fi.path(), fi.fileName()));
4121 for (
int x = 0; x < files.size(); x++)
4123 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Found '%1 - %2'").arg(x).arg(files[x]));
4126 QStringList filteredFiles = files.filter(QRegularExpression(fi.fileName()));
4128 for (
const QString&
file : std::as_const(filteredFiles))
4132 fi.path() +
'/' +
file,
4139 if (!fname.isEmpty())
4154 if (!slaveFiles.isEmpty() && slaveFiles[0] !=
"NOT FOUND" && !slaveFiles[0].startsWith(
"ERROR: "))
4155 fileList += slaveFiles;
4161 if (!fileList.isEmpty())
4166 if (fileList.isEmpty())
4168 fileList <<
"NOT FOUND";
4169 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"File was not found"));
4173 for (
int x = 0; x < fileList.size(); x++)
4175 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"File %1 was found at: '%2'").arg(x).arg(fileList[0]));
4188 QStringList strList;
4190 if (sList.size() < 4)
4192 LOG(VB_GENERAL, LOG_ERR,
LOC +
4193 QString(
"HandleSGFileQuery: Invalid Request. %1")
4194 .arg(sList.join(
"[]:[]")));
4195 strList <<
"EMPTY LIST";
4201 const QString& wantHost = sList.at(1);
4202 QHostAddress wantHostaddr(wantHost);
4203 const QString& groupname = sList.at(2);
4204 const QString&
filename = sList.at(3);
4206 bool allowFallback =
true;
4207 if (sList.size() >= 5)
4208 allowFallback = (sList.at(4).toInt() > 0);
4209 LOG(VB_FILE, LOG_ERR, QString(
"HandleSGFileQuery - allowFallback: %1").arg(allowFallback));
4211 bool slaveUnreachable =
false;
4213 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"HandleSGFileQuery: %1")
4218 if ((host.toLower() == wantHost.toLower()) ||
4219 (!addr.isEmpty() && addr == wantHostaddr.toString()))
4221 LOG(VB_FILE, LOG_INFO,
LOC +
"HandleSGFileQuery: Getting local info");
4230 LOG(VB_FILE, LOG_INFO,
LOC +
4231 "HandleSGFileQuery: Getting remote info");
4234 slaveUnreachable =
false;
4238 LOG(VB_FILE, LOG_INFO,
LOC +
4239 QString(
"HandleSGFileQuery: Failed to grab slave socket : %1 :")
4241 slaveUnreachable =
true;
4246 if (slaveUnreachable)
4247 strList <<
"SLAVE UNREACHABLE: " << wantHost;
4249 if (strList.count() == 0 || (strList.at(0) ==
"0"))
4250 strList <<
"EMPTY LIST";
4258 QString pbshost =
pbs->getHostname();
4260 QStringList strlist;
4269 if ((cardid != -1) && (cardid != elink->GetInputID()))
4272 if (elink->IsLocal())
4275 enchost = elink->GetHostName();
4277 if ((enchost == pbshost) &&
4278 (elink->IsConnected()) &&
4279 (!elink->IsBusy()) &&
4280 (!elink->IsTunerLocked()))
4294 QString msg = QString(
"Cardid %1 LOCKed for external use on %2.")
4295 .arg(retval).arg(pbshost);
4296 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
4299 query.
prepare(
"SELECT videodevice, audiodevice, "
4302 "WHERE cardid = :CARDID ;");
4308 strlist << QString::number(retval)
4309 << query.
value(0).toString()
4310 << query.
value(1).toString()
4311 << query.
value(2).toString();
4319 LOG(VB_GENERAL, LOG_ERR,
LOC +
4320 "MainServer::LockTuner(): Could not find "
4321 "card info in database");
4326 strlist <<
"-2" <<
"" <<
"" <<
"";
4332 strlist <<
"-1" <<
"" <<
"" <<
"";
4339 QStringList strlist;
4346 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleFreeTuner() " +
4347 QString(
"Unknown encoder: %1").arg(cardid));
4348 strlist <<
"FAILED";
4355 QString msg = QString(
"Cardid %1 FREED from external use on %2.")
4356 .arg(cardid).arg(
pbs->getHostname());
4357 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
4377 uint excluded_input)
4379 LOG(VB_CHANNEL, LOG_INFO,
4380 LOC + QString(
"Excluding input %1")
4381 .arg(excluded_input));
4384 std::vector<InputInfo> busyinputs;
4385 std::vector<InputInfo> freeinputs;
4386 QMap<uint, QSet<uint> > groupids;
4394 info.m_inputId = elink->GetInputID();
4396 if (!elink->IsConnected() || elink->IsTunerLocked())
4398 LOG(VB_CHANNEL, LOG_INFO,
4399 LOC + QString(
"Input %1 is locked or not connected")
4400 .arg(
info.m_inputId));
4404 std::vector<uint> infogroups;
4406 for (
uint group : infogroups)
4407 groupids[
info.m_inputId].insert(group);
4410 if (
info.m_inputId != excluded_input && elink->IsBusy(&busyinfo))
4412 LOG(VB_CHANNEL, LOG_DEBUG,
4413 LOC + QString(
"Input %1 is busy on %2/%3")
4417 busyinputs.push_back(
info);
4419 else if (
info.m_liveTvOrder)
4421 LOG(VB_CHANNEL, LOG_DEBUG,
4422 LOC + QString(
"Input %1 is free")
4423 .arg(
info.m_inputId));
4424 freeinputs.push_back(
info);
4431 for (
auto & busyinfo : busyinputs)
4433 auto freeiter = freeinputs.begin();
4434 while (freeiter != freeinputs.end())
4438 if ((groupids[busyinfo.m_inputId] & groupids[freeinfo.
m_inputId])
4445 if (busyinfo.m_sourceId == freeinfo.
m_sourceId)
4447 LOG(VB_CHANNEL, LOG_DEBUG,
4448 LOC + QString(
"Input %1 is limited to %2/%3 by input %4")
4449 .arg(freeinfo.
m_inputId).arg(busyinfo.m_chanId)
4450 .arg(busyinfo.m_mplexId).arg(busyinfo.m_inputId));
4451 freeinfo.
m_chanId = busyinfo.m_chanId;
4452 freeinfo.
m_mplexId = busyinfo.m_mplexId;
4457 LOG(VB_CHANNEL, LOG_DEBUG,
4458 LOC + QString(
"Input %1 is unavailable by input %2")
4459 .arg(freeinfo.
m_inputId).arg(busyinfo.m_inputId));
4460 freeiter = freeinputs.erase(freeiter);
4466 QStringList strlist;
4467 for (
auto & input : freeinputs)
4469 LOG(VB_CHANNEL, LOG_INFO,
4470 LOC + QString(
"Input %1 is available on %2/%3")
4471 .arg(input.m_inputId).arg(input.m_chanId)
4472 .arg(input.m_mplexId));
4473 input.ToStringList(strlist);
4476 if (strlist.empty())
4501 if (commands.size() < 2 || slist.size() < 2)
4504 int recnum = commands[1].toInt();
4511 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleRecorderQuery() " +
4512 QString(
"Unknown encoder: %1").arg(recnum));
4513 QStringList retlist(
"bad" );
4519 const QString& command = slist[1];
4521 QStringList retlist;
4526 LOG(VB_GENERAL, LOG_ERR,
LOC +
" MainServer::HandleRecorderQuery() " +
4527 QString(
"Command %1 for unconnected encoder %2")
4528 .arg(command).arg(recnum));
4534 if (command ==
"IS_RECORDING")
4538 else if (command ==
"GET_FRAMERATE")
4542 else if (command ==
"GET_FRAMES_WRITTEN")
4546 else if (command ==
"GET_FILE_POSITION")
4550 else if (command ==
"GET_MAX_BITRATE")
4554 else if (command ==
"GET_CURRENT_RECORDING")
4559 info->ToStringList(retlist);
4569 else if (command ==
"GET_KEYFRAME_POS")
4571 long long desired = slist[2].toLongLong();
4574 else if (command ==
"FILL_POSITION_MAP")
4576 int64_t start = slist[2].toLongLong();
4577 int64_t end = slist[3].toLongLong();
4586 for (
auto it = map.cbegin(); it != map.cend(); ++it)
4588 retlist += QString::number(it.key());
4589 retlist += QString::number(*it);
4591 if (retlist.empty())
4595 else if (command ==
"FILL_DURATION_MAP")
4597 int64_t start = slist[2].toLongLong();
4598 int64_t end = slist[3].toLongLong();
4607 for (
auto it = map.cbegin(); it != map.cend(); ++it)
4609 retlist += QString::number(it.key());
4610 retlist += QString::number(*it);
4612 if (retlist.empty())
4616 else if (command ==
"GET_RECORDING")
4631 else if (command ==
"FRONTEND_READY")
4636 else if (command ==
"CANCEL_NEXT_RECORDING")
4638 const QString& cancel = slist[2];
4639 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
4640 QString(
"Received: CANCEL_NEXT_RECORDING %1").arg(cancel));
4644 else if (command ==
"SPAWN_LIVETV")
4646 const QString& chainid = slist[2];
4657 enc->
SpawnLiveTV(chain, slist[3].toInt() != 0, slist[4]);
4660 else if (command ==
"STOP_LIVETV")
4677 else if (command ==
"PAUSE")
4682 else if (command ==
"FINISH_RECORDING")
4687 else if (command ==
"SET_LIVE_RECORDING")
4689 int recording = slist[2].toInt();
4693 else if (command ==
"GET_INPUT")
4696 ret = (ret.isEmpty()) ?
"UNKNOWN" : ret;
4699 else if (command ==
"SET_INPUT")
4701 const QString& input = slist[2];
4702 QString ret = enc->
SetInput(input);
4703 ret = (ret.isEmpty()) ?
"UNKNOWN" : ret;
4706 else if (command ==
"TOGGLE_CHANNEL_FAVORITE")
4708 const QString& changroup = slist[2];
4712 else if (command ==
"CHANGE_CHANNEL")
4718 else if (command ==
"SET_CHANNEL")
4720 const QString& name = slist[2];
4724 else if (command ==
"SET_SIGNAL_MONITORING_RATE")
4726 auto rate = std::chrono::milliseconds(slist[2].toInt());
4727 int notifyFrontend = slist[3].toInt();
4729 retlist << QString::number(oldrate.count());
4731 else if (command ==
"GET_COLOUR")
4734 retlist << QString::number(ret);
4736 else if (command ==
"GET_CONTRAST")
4739 retlist << QString::number(ret);
4741 else if (command ==
"GET_BRIGHTNESS")
4744 retlist << QString::number(ret);
4746 else if (command ==
"GET_HUE")
4749 retlist << QString::number(ret);
4751 else if (command ==
"CHANGE_COLOUR")
4753 int type = slist[2].toInt();
4754 bool up = slist[3].toInt() != 0;
4757 retlist << QString::number(ret);
4759 else if (command ==
"CHANGE_CONTRAST")
4761 int type = slist[2].toInt();
4762 bool up = slist[3].toInt() != 0;
4765 retlist << QString::number(ret);
4767 else if (command ==
"CHANGE_BRIGHTNESS")
4769 int type= slist[2].toInt();
4770 bool up = slist[3].toInt() != 0;
4773 retlist << QString::number(ret);
4775 else if (command ==
"CHANGE_HUE")
4777 int type= slist[2].toInt();
4778 bool up = slist[3].toInt() != 0;
4781 retlist << QString::number(ret);
4783 else if (command ==
"CHECK_CHANNEL")
4785 const QString& name = slist[2];
4786 retlist << QString::number((
int)(enc->
CheckChannel(name)));
4788 else if (command ==
"SHOULD_SWITCH_CARD")
4790 const QString& chanid = slist[2];
4793 else if (command ==
"CHECK_CHANNEL_PREFIX")
4795 QString needed_spacer;
4796 const QString&
prefix = slist[2];
4797 uint complete_valid_channel_on_rec = 0;
4798 bool is_extra_char_useful =
false;
4801 prefix, complete_valid_channel_on_rec,
4802 is_extra_char_useful, needed_spacer);
4804 retlist << QString::number((
int)match);
4805 retlist << QString::number(complete_valid_channel_on_rec);
4806 retlist << QString::number((
int)is_extra_char_useful);
4807 retlist << ((needed_spacer.isEmpty()) ? QString(
"X") : needed_spacer);
4809 else if (command ==
"GET_NEXT_PROGRAM_INFO" && (slist.size() >= 6))
4811 QString channelname = slist[2];
4812 uint chanid = slist[3].toUInt();
4814 QString starttime = slist[5];
4817 QString subtitle =
"";
4819 QString category =
"";
4820 QString endtime =
"";
4821 QString callsign =
"";
4822 QString iconpath =
"";
4823 QString seriesid =
"";
4824 QString programid =
"";
4827 title, subtitle, desc, category, starttime,
4828 endtime, callsign, iconpath, channelname, chanid,
4829 seriesid, programid);
4840 retlist << QString::number(chanid);
4844 else if (command ==
"GET_CHANNEL_INFO")
4846 uint chanid = slist[2].toUInt();
4848 QString callsign =
"";
4849 QString channum =
"";
4850 QString channame =
"";
4854 callsign, channum, channame, xmltv);
4856 retlist << QString::number(chanid);
4857 retlist << QString::number(sourceid);
4865 LOG(VB_GENERAL, LOG_ERR,
LOC +
4866 QString(
"Unknown command: %1").arg(command));
4878 int recnum = commands[1].toInt();
4885 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleSetNextLiveTVDir() " +
4886 QString(
"Unknown encoder: %1").arg(recnum));
4887 QStringList retlist(
"bad" );
4896 QStringList retlist(
"OK" );
4904 uint chanid = slist[1].toUInt();
4905 uint sourceid = slist[2].toUInt();
4906 QString oldcnum =
cleanup(slist[3]);
4907 QString callsign =
cleanup(slist[4]);
4908 QString channum =
cleanup(slist[5]);
4909 QString channame =
cleanup(slist[6]);
4910 QString xmltv =
cleanup(slist[7]);
4912 QStringList retlist;
4913 if (!chanid || !sourceid)
4925 ok &= encoder->SetChannelInfo(chanid, sourceid, oldcnum,
4926 callsign, channum, channame, xmltv);
4931 retlist << ((ok) ?
"1" :
"0");
4940 int recnum = commands[1].toInt();
4941 QStringList retlist;
4948 LOG(VB_GENERAL, LOG_ERR,
LOC +
4949 QString(
"HandleRemoteEncoder(cmd %1) ").arg(slist[1]) +
4950 QString(
"Unknown encoder: %1").arg(recnum));
4959 const QString& command = slist[1];
4961 if (command ==
"GET_STATE")
4963 retlist << QString::number((
int)enc->
GetState());
4965 else if (command ==
"GET_SLEEPSTATUS")
4969 else if (command ==
"GET_FLAGS")
4971 retlist << QString::number(enc->
GetFlags());
4973 else if (command ==
"IS_BUSY")
4975 std::chrono::seconds time_buffer = 5s;
4976 if (slist.size() >= 3)
4977 time_buffer = std::chrono::seconds(slist[2].toInt());
4979 retlist << QString::number((
int)enc->
IsBusy(&busy_input, time_buffer));
4982 else if (command ==
"MATCHES_RECORDING" &&
4985 QStringList::const_iterator it = slist.cbegin() + 2;
4990 else if (command ==
"START_RECORDING" &&
4993 QStringList::const_iterator it = slist.cbegin() + 2;
5000 else if (command ==
"GET_RECORDING_STATUS")
5004 else if (command ==
"RECORD_PENDING" &&
5007 auto secsleft = std::chrono::seconds(slist[2].toInt());
5008 int haslater = slist[3].toInt();
5009 QStringList::const_iterator it = slist.cbegin() + 4;
5016 else if (command ==
"CANCEL_NEXT_RECORDING" &&
5017 (slist.size() >= 3))
5019 bool cancel = (
bool) slist[2].toInt();
5023 else if (command ==
"STOP_RECORDING")
5028 else if (command ==
"GET_MAX_BITRATE")
5032 else if (command ==
"GET_CURRENT_RECORDING")
5037 info->ToStringList(retlist);
5060 if (
pbs->isMediaServer())
5071 QStringList retlist;
5073 retlist.push_front(QString::number(retlist.size()));
5080 QStringList retlist;
5081 const QString& queryhostname = slist[1];
5086 if (slave !=
nullptr)
5106 size_t totalKBperMin = 0;
5111 if (!enc->IsConnected() || !enc->IsBusy())
5114 long long maxBitrate = enc->GetMaxBitrate();
5116 maxBitrate = 19500000LL;
5117 long long thisKBperMin = (((size_t)maxBitrate)*((size_t)15))>>11;
5118 totalKBperMin += thisKBperMin;
5119 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Cardid %1: max bitrate %2 KB/min")
5120 .arg(enc->GetInputID()).arg(thisKBperMin));
5124 LOG(VB_FILE, LOG_INFO,
LOC +
5125 QString(
"Maximal bitrate of busy encoders is %1 KB/min")
5126 .arg(totalKBperMin));
5128 return totalKBperMin;
5135 QString allHostList;
5139 QMap <QString, bool> backendsCounted;
5140 std::list<PlaybackSock *> localPlaybackList;
5146 if ((
pbs->IsDisconnected()) ||
5147 (!
pbs->isMediaServer()) ||
5149 (backendsCounted.contains(
pbs->getHostname())))
5152 backendsCounted[
pbs->getHostname()] =
true;
5154 localPlaybackList.push_back(
pbs);
5155 allHostList +=
"," +
pbs->getHostname();
5160 for (
auto &
pbs : localPlaybackList) {
5161 fsInfos <<
pbs->GetDiskSpace();
5170 maxWriteFiveSec = std::max((int64_t)2048, maxWriteFiveSec);
5189 QStringList strlist;
5197 for (
auto & fsInfo : fsInfos)
5199 fsInfo.setFSysID(-1);
5202 LOG(VB_SCHEDULE | VB_FILE, LOG_DEBUG,
LOC +
5203 "Determining unique filesystems");
5206 maxWriteFiveSec = std::max((
size_t)2048, maxWriteFiveSec);
5212 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5213 "--- GetFilesystemInfos directory list start ---");
5214 for (
const auto&
fs1 : std::as_const(fsInfos))
5217 QString(
"Dir: %1:%2")
5218 .arg(
fs1.getHostname(),
fs1.getPath());
5219 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC + msg) ;
5220 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5221 QString(
" Location: %1")
5222 .arg(
fs1.isLocal() ?
"Local" :
"Remote"));
5223 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5224 QString(
" fsID : %1")
5225 .arg(
fs1.getFSysID()));
5226 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5227 QString(
" dirID : %1")
5228 .arg(
fs1.getGroupID()));
5229 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5230 QString(
" BlkSize : %1")
5231 .arg(
fs1.getBlockSize()));
5232 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5233 QString(
" TotalKB : %1")
5234 .arg(
fs1.getTotalSpace()));
5235 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5236 QString(
" UsedKB : %1")
5237 .arg(
fs1.getUsedSpace()));
5238 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5239 QString(
" FreeKB : %1")
5240 .arg(
fs1.getFreeSpace()));
5242 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5243 "--- GetFilesystemInfos directory list end ---");
5252 const QString &src,
const QString &dst)
5255 QStringList retlist;
5257 if (src.isEmpty() || dst.isEmpty()
5258 || src.contains(
"..") || dst.contains(
".."))
5260 LOG(VB_GENERAL, LOG_ERR,
LOC +
5261 QString(
"HandleMoveFile: ERROR moving file '%1' -> '%2', "
5262 "a path fails sanity checks").arg(src, dst));
5263 retlist <<
"0" <<
"Invalid path";
5268 QString srcAbs = sgroup.
FindFile(src);
5269 if (srcAbs.isEmpty())
5271 LOG(VB_GENERAL, LOG_ERR,
LOC +
5272 QString(
"HandleMoveFile: Unable to find %1").arg(src));
5273 retlist <<
"0" <<
"Source file not found";
5281 QString dstAbs = sgroup.
FindFile(dst);
5282 if (!dstAbs.isEmpty() && QFileInfo(dstAbs).isFile())
5284 LOG(VB_GENERAL, LOG_ERR,
LOC +
5285 QString(
"HandleMoveFile: Destination exists at %1").arg(dstAbs));
5286 retlist <<
"0" <<
"Destination file exists";
5292 int sgPathSize = srcAbs.size() - src.size();
5293 dstAbs = srcAbs.mid(0, sgPathSize) + dst;
5307 LOG(VB_FILE, LOG_INFO, QString(
"MainServer::RenameThread: Renaming %1 -> %2")
5310 QStringList retlist;
5311 QFileInfo fi(
m_dst);
5313 if (QDir().mkpath(fi.path()) && QFile::rename(
m_src,
m_dst))
5319 retlist <<
"0" <<
"Rename failed";
5320 LOG(VB_FILE, LOG_ERR,
"MainServer::DoRenameThread: Rename failed");
5353 QStringList retlist;
5359 LOG(VB_GENERAL, LOG_ERR,
LOC +
5360 QString(
"ERROR deleting file, filename '%1' "
5361 "fails sanity checks").arg(
filename));
5372 if (fullfile.isEmpty()) {
5373 LOG(VB_GENERAL, LOG_ERR,
LOC +
5374 QString(
"Unable to find %1 in HandleDeleteFile()") .arg(
filename));
5383 QFile checkFile(fullfile);
5390 const QFileInfo
info(fullfile);
5394 if ((fd < 0) && checkFile.exists())
5396 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error deleting file: %1.")
5416 auto *truncateThread =
new TruncateThread(
this, fullfile, fd, size);
5417 truncateThread->run();
5428 const QString &starttime,
5433 pbssock =
pbs->getSocket();
5436 frm_dir_map_t::const_iterator it;
5438 QStringList retlist;
5441 const ProgramInfo pginfo(chanid.toUInt(), recstartdt);
5450 for (it = markMap.cbegin(); it != markMap.cend(); ++it)
5453 QString intstr = QString(
"%1").arg(*it);
5455 retlist << QString::number(it.key());
5460 retlist.prepend(QString(
"%1").arg(rowcnt));
5469 const QString &starttime,
5484 const QString &starttime,
5500 const QString &starttime,
5511 pbssock =
pbs->getSocket();
5515 chanid.toUInt(), recstartts);
5517 QStringList retlist;
5518 retlist << QString::number(bookmark);
5537 pbssock =
pbs->getSocket();
5539 const QString& chanid = tokens[1];
5540 const QString& starttime = tokens[2];
5541 long long bookmark = tokens[3].toLongLong();
5544 QStringList retlist;
5555 retlist <<
"FAILED";
5569 pbssock =
pbs->getSocket();
5571 const QString&
hostname = tokens[1];
5572 const QString& setting = tokens[2];
5573 QStringList retlist;
5577 retlist << retvalue;
5585 bool synchronous = (command[0] ==
"DOWNLOAD_FILE_NOW");
5586 const QString& srcURL = command[1];
5587 const QString& storageGroup = command[2];
5592 QStringList retlist;
5596 pbssock =
pbs->getSocket();
5600 QFileInfo finfo(srcURL);
5604 if (outDir.isEmpty())
5606 LOG(VB_GENERAL, LOG_ERR,
LOC +
5607 QString(
"Unable to determine directory "
5608 "to write to in %1 write command").arg(command[0]));
5609 retlist <<
"downloadfile_directory_not_found";
5618 LOG(VB_GENERAL, LOG_ERR,
LOC +
5619 QString(
"ERROR: %1 write filename '%2' does not pass "
5620 "sanity checks.") .arg(command[0],
filename));
5621 retlist <<
"downloadfile_filename_dangerous";
5664 pbssock =
pbs->getSocket();
5666 const QString&
hostname = tokens[1];
5667 const QString& setting = tokens[2];
5668 const QString& svalue = tokens[3];
5669 QStringList retlist;
5684 QStringList retlist;
5706 QStringList strlist;
5712 QString sql =
"SELECT DISTINCT hostname "
5713 "FROM storagegroup "
5714 "WHERE groupname = 'Music'";
5726 LOG(VB_GENERAL, LOG_INFO,
LOC +
5727 QString(
"HandleScanMusic: running filescanner on master BE '%1'").arg(
hostname));
5739 LOG(VB_GENERAL, LOG_INFO,
LOC +
5740 QString(
"HandleScanMusic: asking slave '%1' to run file scanner").arg(
hostname));
5746 LOG(VB_GENERAL, LOG_INFO,
LOC +
5747 QString(
"HandleScanMusic: Failed to grab slave socket on '%1'").arg(
hostname));
5756 LOG(VB_GENERAL, LOG_INFO,
LOC +
5757 QString(
"HandleScanMusic: running filescanner on slave BE '%1'")
5775 QStringList strlist;
5779 const QString&
hostname = slist[1];
5787 LOG(VB_GENERAL, LOG_INFO,
LOC +
5788 QString(
"HandleMusicTagUpdateVolatile: asking slave '%1' to update the metadata").arg(
hostname));
5798 LOG(VB_GENERAL, LOG_INFO,
LOC +
5799 QString(
"HandleMusicTagUpdateVolatile: Failed to grab slave socket on '%1'").arg(
hostname));
5801 strlist <<
"ERROR: slave not found";
5810 QStringList paramList;
5811 paramList.append(QString(
"--songid='%1'").arg(slist[2]));
5812 paramList.append(QString(
"--rating='%1'").arg(slist[3]));
5813 paramList.append(QString(
"--playcount='%1'").arg(slist[4]));
5814 paramList.append(QString(
"--lastplayed='%1'").arg(slist[5]));
5816 QString command =
GetAppBinDir() +
"mythutil --updatemeta " + paramList.join(
" ");
5818 LOG(VB_GENERAL, LOG_INFO,
LOC +
5819 QString(
"HandleMusicTagUpdateVolatile: running %1'").arg(command));
5835 QStringList strlist;
5839 const QString&
hostname = slist[1];
5847 LOG(VB_GENERAL, LOG_INFO,
LOC +
5848 QString(
"HandleMusicCalcTrackLen: asking slave '%1' to update the track length").arg(
hostname));
5858 LOG(VB_GENERAL, LOG_INFO,
LOC +
5859 QString(
"HandleMusicCalcTrackLen: Failed to grab slave socket on '%1'").arg(
hostname));
5861 strlist <<
"ERROR: slave not found";
5870 QStringList paramList;
5871 paramList.append(QString(
"--songid='%1'").arg(slist[2]));
5873 QString command =
GetAppBinDir() +
"mythutil --calctracklen " + paramList.join(
" ");
5875 LOG(VB_GENERAL, LOG_INFO,
LOC +
5876 QString(
"HandleMusicCalcTrackLen: running %1'").arg(command));
5893 QStringList strlist;
5897 const QString&
hostname = slist[1];
5905 LOG(VB_GENERAL, LOG_INFO,
LOC +
5906 QString(
"HandleMusicTagUpdateMetadata: asking slave '%1' "
5907 "to update the metadata").arg(
hostname));
5917 LOG(VB_GENERAL, LOG_INFO,
LOC +
5918 QString(
"HandleMusicTagUpdateMetadata: Failed to grab "
5919 "slave socket on '%1'").arg(
hostname));
5921 strlist <<
"ERROR: slave not found";
5930 int songID = slist[2].toInt();
5936 LOG(VB_GENERAL, LOG_ERR,
LOC +
5937 QString(
"HandleMusicTagUpdateMetadata: "
5938 "Cannot find metadata for trackid: %1")
5941 strlist <<
"ERROR: track not found";
5954 LOG(VB_GENERAL, LOG_ERR,
LOC +
5955 QString(
"HandleMusicTagUpdateMetadata: "
5956 "Failed to write to tag for trackid: %1")
5959 strlist <<
"ERROR: write to tag failed";
5979 QStringList strlist;
5983 const QString&
hostname = slist[1];
5991 LOG(VB_GENERAL, LOG_INFO,
LOC +
5992 QString(
"HandleMusicFindAlbumArt: asking slave '%1' "
5993 "to update the albumart").arg(
hostname));
6003 LOG(VB_GENERAL, LOG_INFO,
LOC +
6004 QString(
"HandleMusicFindAlbumArt: Failed to grab "
6005 "slave socket on '%1'").arg(
hostname));
6007 strlist <<
"ERROR: slave not found";
6016 int songID = slist[2].toInt();
6017 bool updateDatabase = (slist[3].toInt() == 1);
6023 LOG(VB_GENERAL, LOG_ERR,
LOC +
6024 QString(
"HandleMusicFindAlbumArt: "
6025 "Cannot find metadata for trackid: %1").arg(songID));
6027 strlist <<
"ERROR: track not found";
6037 QDir dir = fi.absoluteDir();
6040 "*.png;*.jpg;*.jpeg;*.gif;*.bmp");
6041 dir.setNameFilters(nameFilter.split(
";"));
6043 QStringList files = dir.entryList();
6048 fi.setFile(mdata->
Filename(
false));
6049 QString startDir = fi.path();
6051 for (
const QString&
file : std::as_const(files))
6055 image->m_filename = startDir +
'/' + fi.fileName();
6057 image->m_embedded =
false;
6059 image->m_description =
"";
6060 images->addImage(image);
6072 for (
int x = 0; x < artList.count(); x++)
6076 images->addImage(image);
6084 LOG(VB_GENERAL, LOG_ERR,
LOC +
6085 QString(
"HandleMusicFindAlbumArt: "
6086 "Failed to find a tagger for trackid: %1").arg(songID));
6091 images->dumpToDatabase();
6094 strlist.append(QString(
"%1").arg(images->getImageCount()));
6096 for (
uint x = 0; x < images->getImageCount(); x++)
6099 strlist.append(QString(
"%1").arg(image->
m_id));
6100 strlist.append(QString(
"%1").arg((
int)image->
m_imageType));
6101 strlist.append(QString(
"%1").arg(
static_cast<int>(image->
m_embedded)));
6109 QStringList paramList;
6110 paramList.append(QString(
"--songid='%1'").arg(mdata->
ID()));
6111 paramList.append(QString(
"--imagetype='%1'").arg(image->
m_imageType));
6113 QString command =
GetAppBinDir() +
"mythutil --extractimage " + paramList.join(
" ");
6131 QStringList strlist;
6135 const QString&
hostname = slist[1];
6136 const QString& songid = slist[2];
6137 const QString& imagetype = slist[3];
6145 LOG(VB_GENERAL, LOG_INFO,
LOC +
6146 QString(
"HandleMusicTagGetImage: asking slave '%1' to "
6147 "extract the image").arg(
hostname));
6157 LOG(VB_GENERAL, LOG_INFO,
LOC +
6158 QString(
"HandleMusicTagGetImage: Failed to grab slave "
6163 QStringList paramList;
6164 paramList.append(QString(
"--songid='%1'").arg(songid));
6165 paramList.append(QString(
"--imagetype='%1'").arg(imagetype));
6167 QString command =
GetAppBinDir() +
"mythutil --extractimage " + paramList.join(
" ");
6185 QStringList strlist;
6189 const QString&
hostname = slist[1];
6197 LOG(VB_GENERAL, LOG_INFO,
LOC +
6198 QString(
"HandleMusicTagChangeImage: asking slave '%1' "
6199 "to update the metadata").arg(
hostname));
6209 LOG(VB_GENERAL, LOG_INFO,
LOC +
6210 QString(
"HandleMusicTagChangeImage: Failed to grab "
6211 "slave socket on '%1'").arg(
hostname));
6213 strlist <<
"ERROR: slave not found";
6221 int songID = slist[2].toInt();
6222 auto oldType = (
ImageType)slist[3].toInt();
6223 auto newType = (
ImageType)slist[4].toInt();
6230 LOG(VB_GENERAL, LOG_ERR,
LOC +
6231 QString(
"HandleMusicTagChangeImage: "
6232 "Cannot find metadata for trackid: %1")
6235 strlist <<
"ERROR: track not found";
6276 LOG(VB_GENERAL, LOG_ERR,
"HandleMusicTagChangeImage: failed to change image type");
6278 strlist <<
"ERROR: failed to change image type";
6296 image->
m_filename = fi.path() + QString(
"/%1-%2.jpg")
6310 QStringList paramList;
6311 paramList.append(QString(
"--songid='%1'").arg(mdata->
ID()));
6312 paramList.append(QString(
"--imagetype='%1'").arg(image->
m_imageType));
6314 QString command =
GetAppBinDir() +
"mythutil --extractimage " + paramList.join(
" ");
6327 image->
m_filename = fi.absolutePath() + QString(
"/%1.jpg")
6352 QStringList strlist;
6356 const QString&
hostname = slist[1];
6364 LOG(VB_GENERAL, LOG_INFO,
LOC +
6365 QString(
"HandleMusicTagAddImage: asking slave '%1' "
6366 "to add the image").arg(
hostname));
6376 LOG(VB_GENERAL, LOG_INFO,
LOC +
6377 QString(
"HandleMusicTagAddImage: Failed to grab "
6378 "slave socket on '%1'").arg(
hostname));
6380 strlist <<
"ERROR: slave not found";
6389 int songID = slist[2].toInt();
6390 const QString&
filename = slist[3];
6391 auto imageType = (
ImageType) slist[4].toInt();
6397 LOG(VB_GENERAL, LOG_ERR,
LOC +
6398 QString(
"HandleMusicTagAddImage: Cannot find metadata for trackid: %1")
6401 strlist <<
"ERROR: track not found";
6413 LOG(VB_GENERAL, LOG_ERR,
LOC +
6414 "HandleMusicTagAddImage: failed to find a tagger for track");
6416 strlist <<
"ERROR: tagger not found";
6427 LOG(VB_GENERAL, LOG_ERR,
LOC +
6428 "HandleMusicTagAddImage: asked to write album art to the tag "
6429 "but the tagger doesn't support it!");
6431 strlist <<
"ERROR: embedded images not supported by tag";
6442 bool isDirectoryImage =
false;
6445 if (imageFilename.isEmpty())
6449 imageFilename = fi.absolutePath() +
'/' +
filename;
6450 isDirectoryImage =
true;
6455 LOG(VB_GENERAL, LOG_ERR,
LOC +
6456 QString(
"HandleMusicTagAddImage: cannot find image file %1").arg(
filename));
6458 strlist <<
"ERROR: failed to find image file";
6474 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleMusicTagAddImage: failed to write album art to tag");
6476 strlist <<
"ERROR: failed to write album art to tag";
6481 if (!isDirectoryImage)
6482 QFile::remove(imageFilename);
6490 if (!isDirectoryImage)
6491 QFile::remove(imageFilename);
6507 QStringList strlist;
6511 const QString&
hostname = slist[1];
6519 LOG(VB_GENERAL, LOG_INFO,
LOC +
6520 QString(
"HandleMusicTagRemoveImage: asking slave '%1' "
6521 "to remove the image").arg(
hostname));
6531 LOG(VB_GENERAL, LOG_INFO,
LOC +
6532 QString(
"HandleMusicTagRemoveImage: Failed to grab "
6533 "slave socket on '%1'").arg(
hostname));
6535 strlist <<
"ERROR: slave not found";
6543 int songID = slist[2].toInt();
6544 int imageID = slist[3].toInt();
6551 LOG(VB_GENERAL, LOG_ERR,
LOC +
6552 QString(
"HandleMusicTagRemoveImage: Cannot find metadata for trackid: %1")
6555 strlist <<
"ERROR: track not found";
6567 LOG(VB_GENERAL, LOG_ERR,
LOC +
6568 "HandleMusicTagRemoveImage: failed to find a tagger for track");
6570 strlist <<
"ERROR: tagger not found";
6581 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleMusicTagRemoveImage: asked to remove album art "
6582 "from the tag but the tagger doesn't support it!");
6584 strlist <<
"ERROR: embedded images not supported by tag";
6597 LOG(VB_GENERAL, LOG_ERR,
LOC +
6598 QString(
"HandleMusicTagRemoveImage: Cannot find image for imageid: %1")
6601 strlist <<
"ERROR: image not found";
6613 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleMusicTagRemoveImage: failed to remove album art from tag");
6615 strlist <<
"ERROR: failed to remove album art from tag";
6634 QStringList strlist;
6638 const QString&
hostname = slist[1];
6639 const QString& songid = slist[2];
6640 const QString& grabberName = slist[3];
6641 QString artist =
"";
6645 if (slist.size() == 7)
6658 LOG(VB_GENERAL, LOG_INFO,
LOC +
6659 QString(
"HandleMusicFindLyrics: asking slave '%1' to "
6670 LOG(VB_GENERAL, LOG_INFO,
LOC +
6671 QString(
"HandleMusicFindLyrics: Failed to grab slave "
6676 QStringList paramList;
6677 paramList.append(QString(
"--songid='%1'").arg(songid));
6678 paramList.append(QString(
"--grabber='%1'").arg(grabberName));
6680 if (!artist.isEmpty())
6681 paramList.append(QString(
"--artist=\"%1\"").arg(artist));
6683 if (!album.isEmpty())
6684 paramList.append(QString(
"--album=\"%1\"").arg(album));
6686 if (!title.isEmpty())
6687 paramList.append(QString(
"--title=\"%1\"").arg(title));
6689 QString command =
GetAppBinDir() +
"mythutil --findlyrics " + paramList.join(
" ");
6723 QStringList strlist;
6727 QString scriptDir =
GetShareDir() +
"metadata/Music/lyrics";
6732 LOG(VB_GENERAL, LOG_ERR, QString(
"Cannot find lyric scripts directory: %1").arg(scriptDir));
6733 strlist << QString(
"ERROR: Cannot find lyric scripts directory: %1").arg(scriptDir);
6741 d.setFilter(QDir::Files | QDir::NoDotAndDotDot);
6742 d.setNameFilters(QStringList(
"*.py"));
6743 QFileInfoList list =
d.entryInfoList();
6746 LOG(VB_GENERAL, LOG_ERR, QString(
"Cannot find any lyric scripts in: %1").arg(scriptDir));
6747 strlist << QString(
"ERROR: Cannot find any lyric scripts in: %1").arg(scriptDir);
6755 QStringList scripts;
6756 for (
const auto & fi : std::as_const(list))
6758 LOG(VB_FILE, LOG_NOTICE, QString(
"Found lyric script at: %1").arg(fi.filePath()));
6759 scripts.append(fi.filePath());
6762 QStringList grabbers;
6765 for (
int x = 0; x < scripts.count(); x++)
6767 QStringList
args { scripts.at(x),
"-v" };
6769 p.start(PYTHON_EXE,
args);
6770 p.waitForFinished(-1);
6771 QString result =
p.readAllStandardOutput();
6773 QDomDocument domDoc;
6774#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
6777 int errorColumn = 0;
6779 if (!domDoc.setContent(result,
false, &errorMsg, &errorLine, &errorColumn))
6781 LOG(VB_GENERAL, LOG_ERR,
6782 QString(
"FindLyrics: Could not parse version from %1").arg(scripts.at(x)) +
6783 QString(
"\n\t\t\tError at line: %1 column: %2 msg: %3").arg(errorLine).arg(errorColumn).arg(errorMsg));
6787 auto parseResult = domDoc.setContent(result);
6790 LOG(VB_GENERAL, LOG_ERR,
6791 QString(
"FindLyrics: Could not parse version from %1")
6792 .arg(scripts.at(x)) +
6793 QString(
"\n\t\t\tError at line: %1 column: %2 msg: %3")
6794 .arg(parseResult.errorLine).arg(parseResult.errorColumn)
6795 .arg(parseResult.errorMessage));
6800 QDomNodeList itemList = domDoc.elementsByTagName(
"grabber");
6801 QDomNode itemNode = itemList.item(0);
6803 grabbers.append(itemNode.namedItem(QString(
"name")).toElement().text());
6810 for (
int x = 0; x < grabbers.count(); x++)
6811 strlist.append(grabbers.at(x));
6822 QStringList strlist;
6826 const QString&
hostname = slist[1];
6827 int songID = slist[2].toInt();
6835 LOG(VB_GENERAL, LOG_INFO,
LOC +
6836 QString(
"HandleMusicSaveLyrics: asking slave '%1' to "
6847 LOG(VB_GENERAL, LOG_INFO,
LOC +
6848 QString(
"HandleMusicSaveLyrics: Failed to grab slave "
6856 LOG(VB_GENERAL, LOG_ERR, QString(
"Cannot find metadata for trackid: %1").arg(songID));
6857 strlist << QString(
"ERROR: Cannot find metadata for trackid: %1").arg(songID);
6865 QString lyricsFile =
GetConfDir() + QString(
"/MythMusic/Lyrics/%1.txt").arg(songID);
6869 QFile::remove(lyricsFile);
6872 QFile
file(QLatin1String(qPrintable(lyricsFile)));
6874 if (
file.open(QIODevice::WriteOnly))
6876 QTextStream stream(&
file);
6877 for (
int x = 3; x < slist.count(); x++)
6878 stream << slist.at(x);
6890 QStringList &commands,
6895 int recnum = commands[1].toInt();
6896 const QString& command = slist[1];
6898 QStringList retlist;
6904 if (command ==
"DONE")
6912 LOG(VB_GENERAL, LOG_ERR,
LOC +
6913 QString(
"Unknown file transfer socket: %1").arg(recnum));
6914 retlist << QString(
"ERROR: Unknown file transfer socket: %1")
6926 if (command ==
"REQUEST_BLOCK")
6928 int size = slist[2].toInt();
6932 else if (command ==
"WRITE_BLOCK")
6934 int size = slist[2].toInt();
6936 retlist << QString::number(ft->
WriteBlock(size));
6938 else if (command ==
"SEEK")
6940 long long pos = slist[2].toLongLong();
6941 int whence = slist[3].toInt();
6942 long long curpos = slist[4].toLongLong();
6944 long long ret = ft->
Seek(curpos, pos, whence);
6945 retlist << QString::number(ret);
6947 else if (command ==
"IS_OPEN")
6949 bool isopen = ft->
isOpen();
6951 retlist << QString::number(static_cast<int>(isopen));
6953 else if (command ==
"REOPEN")
6955 retlist << QString::number(static_cast<int>(ft->
ReOpen(slist[2])));
6957 else if (command ==
"DONE")
6962 else if (command ==
"SET_TIMEOUT")
6964 bool fast = slist[2].toInt() != 0;
6968 else if (command ==
"REQUEST_SIZE")
6976 LOG(VB_GENERAL, LOG_ERR,
LOC +
6977 QString(
"Unknown command: %1").arg(command));
6978 retlist <<
"ERROR" <<
"invalid_call";
6992 QStringList::const_iterator it = slist.cbegin() + 1;
7004 retval = iter.key();
7010 QStringList strlist( QString::number(retval) );
7027 strlist <<
"nohost";
7039 int recordernum = slist[1].toInt();
7041 QStringList strlist;
7064 strlist <<
"nohost";
7073 if (slist.size() < 2)
7078 const QString& message = slist[1];
7079 QStringList extra_data;
7080 for (
uint i = 2; i < (
uint) slist.size(); i++)
7081 extra_data.push_back(slist[i]);
7083 if (extra_data.empty())
7094 QStringList retlist(
"OK" );
7102 QStringList retlist;
7104 const QString& newverbose = slist[1];
7105 int len = newverbose.length();
7111 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
7112 QString(
"Verbose mask changed, new mask is: %1").arg(
verboseString));
7118 LOG(VB_GENERAL, LOG_ERR,
LOC +
7119 QString(
"Invalid SET_VERBOSE string: '%1'").arg(newverbose));
7120 retlist <<
"Failed";
7129 QStringList retlist;
7130 const QString& newstring = slist[1];
7131 LogLevel_t newlevel = LOG_UNKNOWN;
7133 int len = newstring.length();
7137 if (newlevel != LOG_UNKNOWN)
7141 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
7142 QString(
"Log level changed, new level is: %1")
7149 if (newlevel == LOG_UNKNOWN)
7151 LOG(VB_GENERAL, LOG_ERR,
LOC +
7152 QString(
"Invalid SET_VERBOSE string: '%1'").arg(newstring));
7153 retlist <<
"Failed";
7163 int RecordingsInProgress = 0;
7164 int LiveTVRecordingsInProgress = 0;
7165 QStringList retlist;
7170 if (elink->IsBusyRecording()) {
7171 RecordingsInProgress++;
7174 if (
info &&
info->GetRecordingGroup() ==
"LiveTV")
7175 LiveTVRecordingsInProgress++;
7182 retlist << QString::number(RecordingsInProgress);
7183 retlist << QString::number(LiveTVRecordingsInProgress);
7192 if (slist.size() < 3)
7194 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Too few params in pixmap request");
7195 QStringList outputlist(
"ERROR");
7196 outputlist +=
"TOO_FEW_PARAMS";
7201 bool time_fmt_sec =
true;
7202 std::chrono::seconds time = std::chrono::seconds::max();
7203 long long frame = -1;
7207 bool has_extra_data =
false;
7209 QString token = slist[1];
7210 if (token.isEmpty())
7212 LOG(VB_GENERAL, LOG_ERR,
LOC +
7213 "Failed to parse pixmap request. Token absent");
7214 QStringList outputlist(
"ERROR");
7215 outputlist +=
"TOKEN_ABSENT";
7220 QStringList::const_iterator it = slist.cbegin() + 2;
7221 QStringList::const_iterator end = slist.cend();
7226 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to parse pixmap request. "
7227 "ProgramInfo missing pathname");
7228 QStringList outputlist(
"BAD");
7229 outputlist +=
"NO_PATHNAME";
7233 if (token.toLower() ==
"do_not_care")
7235 token = QString(
"%1:%2")
7238 if (it != slist.cend())
7239 (time_fmt_sec = ((*it).toLower() ==
"s")), ++it;
7240 if (it != slist.cend())
7243 time = std::chrono::seconds((*it).toLongLong()), ++it;
7245 frame = (*it).toLongLong(), ++it;
7247 if (it != slist.cend())
7248 (outputfile = *it), ++it;
7249 outputfile = (outputfile ==
"<EMPTY>") ? QString() : outputfile;
7250 if (it != slist.cend())
7252 width = (*it).toInt(&ok); ++it;
7253 width = (ok) ? width : -1;
7255 if (it != slist.cend())
7257 height = (*it).toInt(&ok); ++it;
7258 height = (ok) ? height : -1;
7259 has_extra_data =
true;
7261 QSize outputsize = QSize(width, height);
7265 auto pos_text = (time != std::chrono::seconds::max())
7266 ? QString::number(time.count()) +
"s"
7267 : QString::number(frame) +
"f";
7268 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
7269 QString(
"HandleGenPreviewPixmap got extra data\n\t\t\t"
7272 .arg(width).arg(height).arg(outputfile));
7287 QStringList outputlist;
7290 if (time != std::chrono::seconds::max())
7293 token, &pginfo, time, -1, outputfile, outputsize);
7298 token, &pginfo, std::chrono::seconds::max(), frame, outputfile, outputsize);
7308 if (outputlist.empty() || outputlist[0] !=
"OK")
7314 LOG(VB_GENERAL, LOG_ERR,
LOC +
7315 QString(
"HandleGenPreviewPixmap() "
7316 "Couldn't find backend for:\n\t\t\t%1")
7322 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleGenPreviewPixmap: Unable to "
7323 "find file locally, unable to make preview image.");
7324 QStringList outputlist(
"ERROR" );
7325 outputlist +=
"FILE_INACCESSIBLE";
7333 if (time != std::chrono::seconds::max()) {
7335 pginfo, outputsize, outputfile, time, -1, token);
7338 pginfo, outputsize, outputfile, -1s, frame, token);
7346 QStringList outputlist(
"OK");
7347 if (!outputfile.isEmpty())
7348 outputlist += outputfile;
7356 QStringList::const_iterator it = slist.cbegin() + 1;
7361 QStringList strlist;
7374 strlist = (slavetime.isValid()) ?
7375 QStringList(QString::number(slavetime.toSecsSinceEpoch())) :
7382 LOG(VB_GENERAL, LOG_ERR,
LOC +
7383 QString(
"HandlePixmapLastModified() "
7384 "Couldn't find backend for:\n\t\t\t%1")
7390 LOG(VB_GENERAL, LOG_ERR,
LOC +
7391 "MainServer: HandlePixmapLastModified: Unable to "
7392 "find file locally, unable to get last modified date.");
7393 QStringList outputlist(
"BAD" );
7404 QDateTime lastmodified = finfo.lastModified();
7405 if (lastmodified.isValid())
7406 strlist = QStringList(QString::number(lastmodified.toSecsSinceEpoch()));
7408 strlist = QStringList(QString::number(UINT_MAX));
7412 strlist = QStringList(
"BAD" );
7421 QStringList strlist;
7426 strlist = QStringList(
"ERROR");
7427 strlist +=
"1: Parameter list too short";
7432 QDateTime cachemodified;
7433 if (!slist[1].isEmpty() && (slist[1].toInt() != -1))
7438 int max_file_size = slist[2].toInt();
7440 QStringList::const_iterator it = slist.begin() + 3;
7445 strlist = QStringList(
"ERROR");
7446 strlist +=
"2: Invalid ProgramInfo";
7457 size_t fsize = finfo.size();
7458 QDateTime lastmodified = finfo.lastModified();
7459 bool out_of_date = !cachemodified.isValid() ||
7460 (lastmodified > cachemodified);
7462 if (out_of_date && (fsize > 0) && ((ssize_t)fsize < max_file_size))
7466 bool open_ok =
file.open(QIODevice::ReadOnly);
7468 data =
file.readAll();
7470 if (!data.isEmpty())
7472 LOG(VB_FILE, LOG_INFO,
LOC +
7473 QString(
"Read preview file '%1'")
7475 if (lastmodified.isValid())
7476 strlist += QString::number(lastmodified.toSecsSinceEpoch());
7478 strlist += QString::number(UINT_MAX);
7479 strlist += QString::number(data.size());
7480#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
7481 quint16 checksum = qChecksum(data.constData(), data.size());
7483 quint16 checksum = qChecksum(data);
7485 strlist += QString::number(checksum);
7486 strlist += QString(data.toBase64());
7490 LOG(VB_GENERAL, LOG_ERR,
LOC +
7491 QString(
"Failed to read preview file '%1'")
7494 strlist = QStringList(
"ERROR");
7496 QString(
"3: Failed to read preview file '%1'%2")
7498 (open_ok) ?
"" :
" open failed");
7501 else if (out_of_date && (max_file_size > 0))
7503 if (fsize >= (
size_t) max_file_size)
7505 strlist = QStringList(
"WARNING");
7506 strlist += QString(
"1: Preview file too big %1 > %2")
7507 .arg(fsize).arg(max_file_size);
7511 strlist = QStringList(
"ERROR");
7512 strlist +=
"4: Preview file is invalid";
7517 if (lastmodified.isValid())
7518 strlist += QString::number(lastmodified.toSecsSinceEpoch());
7520 strlist += QString::number(UINT_MAX);
7534 strlist = QStringList(
"ERROR");
7536 "5: Could not locate mythbackend that made this recording";
7545 if (!strlist.empty())
7552 strlist = QStringList(
"WARNING");
7553 strlist +=
"2: Could not locate requested file";
7559 QStringList retlist(
"OK" );
7565 pbs->setBlockShutdown(blockShutdown);
7568 QStringList retlist(
"OK" );
7613 QList<uint> disconnectedSlaves;
7625 MythEvent me(
"LOCAL_RECONNECT_TO_MASTER");
7631 disconnectedSlaves.clear();
7632 bool needsReschedule =
false;
7636 LOG(VB_GENERAL, LOG_ERR,
LOC +
7637 QString(
"Slave backend: %1 no longer connected")
7638 .arg(
pbs->getHostname()));
7640 bool isFallingAsleep =
true;
7644 if (elink->GetSocket() ==
pbs)
7646 if (!elink->IsFallingAsleep())
7647 isFallingAsleep =
false;
7649 elink->SetSocket(
nullptr);
7651 disconnectedSlaves.push_back(elink->GetInputID());
7655 if (
m_sched && !isFallingAsleep)
7656 needsReschedule =
true;
7658 QString message = QString(
"LOCAL_SLAVE_BACKEND_OFFLINE %1")
7659 .arg(
pbs->getHostname());
7667 QString(
"SLAVE_DISCONNECTED HOSTNAME %1")
7668 .arg(
pbs->getHostname()));
7677 if (chain !=
nullptr)
7688 std::this_thread::sleep_for(500us);
7690 if (enc->IsBusy() &&
7691 enc->GetChainID() == chain->
GetID())
7702 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 sock(%2) '%3' disconnected")
7703 .arg(
pbs->getBlockShutdown() ?
"Playback" :
"Monitor")
7704 .arg(quintptr(socket),0,16)
7705 .arg(
pbs->getHostname()) );
7706 pbs->SetDisconnected();
7711 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Playback sock still exists?");
7719 if (!disconnectedSlaves.isEmpty())
7728 MythEvent me(
"LOCAL_CONNECTION_CLOSED");
7742 LOG(VB_GENERAL, LOG_INFO, QString(
"BEFileTransfer sock(%1) disconnected")
7743 .arg(quintptr(socket),0,16) );
7755 LOG(VB_GENERAL, LOG_INFO, QString(
"Control sock(%1) disconnected")
7756 .arg(quintptr(socket),0,16) );
7766 LOG(VB_GENERAL, LOG_WARNING,
LOC +
7767 QString(
"Unknown socket closing MythSocket(0x%1)")
7768 .arg((intptr_t)socket,0,16));
7781 if (
pbs->isSlaveBackend() &&
7804 if (
pbs->isMediaServer() &&
7820 { return sock == pbs->getSocket(); });
7828 if (
id == ft->getSocket()->GetSocketDescriptor())
7837 if (sock == ft->getSocket())
7847 if (chain->GetID() ==
id)
7857 if (chain->IsHostSocket(sock))
7867 if (chain->ProgramIsAt(pginfo) >= 0)
7887 std::vector<LiveTVChain*> newChains;
7892 newChains.push_back(entry);
7902 if (closeApplication)
7908 QString lpath = QString(path);
7910 if (lpath.section(
'/', -2, -2) ==
"channels")
7913 QString
file = lpath.section(
'/', -1);
7917 query.
prepare(
"SELECT icon FROM channel "
7918 "WHERE deleted IS NULL AND icon LIKE :FILENAME ;");
7923 lpath = query.
value(0).toString();
7932 lpath = lpath.section(
'/', -1);
7934 QString fpath = lpath;
7935 if (fpath.endsWith(
".png"))
7936 fpath = fpath.left(fpath.length() - 4);
7942 if (pburl.startsWith(
"/"))
7944 lpath = pburl.section(
'/', 0, -2) +
"/" + lpath;
7945 LOG(VB_FILE, LOG_INFO,
LOC +
7946 QString(
"Local file path: %1").arg(lpath));
7950 LOG(VB_GENERAL, LOG_ERR,
LOC +
7951 QString(
"ERROR: LocalFilePath unable to find local "
7952 "path for '%1', found '%2' instead.")
7953 .arg(lpath, pburl));
7957 else if (!lpath.isEmpty())
7960 QString opath = lpath;
7963 if (!wantgroup.isEmpty())
7965 sgroup.
Init(wantgroup);
7966 lpath = QString(path);
7970 lpath = QFileInfo(lpath).fileName();
7973 QString tmpFile = sgroup.
FindFile(lpath);
7974 if (!tmpFile.isEmpty())
7977 LOG(VB_FILE, LOG_INFO,
LOC +
7978 QString(
"LocalFilePath(%1 '%2'), found file through "
7979 "exhaustive search at '%3'")
7980 .arg(path, opath, lpath));
7984 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"ERROR: LocalFilePath "
7985 "unable to find local path for '%1'.") .arg(path));
8001 auto *masterServerSock =
new MythSocket(-1,
this);
8006 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
8007 QString(
"Connecting to master server: %1:%2")
8008 .arg(server).arg(port));
8010 if (!masterServerSock->ConnectToHost(server, port))
8012 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
8013 "Connection to master server timed out.");
8015 masterServerSock->DecrRef();
8019 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Connected successfully");
8021 QString str = QString(
"ANN SlaveBackend %1 %2")
8025 QStringList strlist( str );
8030 elink->CancelNextRecording(
true);
8048 masterServerSock->SetReadyReadCallbackEnabled(
false);
8049 if (!masterServerSock->SendReceiveStringList(strlist, 1) ||
8050 (strlist[0] ==
"ERROR"))
8052 masterServerSock->DecrRef();
8053 masterServerSock =
nullptr;
8054 if (strlist.empty())
8056 LOG(VB_GENERAL, LOG_ERR,
LOC +
8057 "Failed to open master server socket, timeout");
8061 LOG(VB_GENERAL, LOG_ERR,
LOC +
8062 "Failed to open master server socket" +
8063 ((strlist.size() >= 2) ?
8064 QString(
", error was %1").arg(strlist[1]) :
8065 QString(
", remote error")));
8070 masterServerSock->SetReadyReadCallbackEnabled(
true);
8085 bool foundClient =
false;
8095 if ((*it)->isSlaveBackend())
8100 if (onlyBlockingClients && !(*it)->getBlockShutdown())
8108 return (foundClient);
8117 QStringList bcast(
"SHUTDOWN_NOW" );
8124 if (
pbs->isSlaveBackend())
8125 pbs->getSocket()->WriteStringList(bcast);
8135 bool needsReschedule =
event.ExtraData(0).toUInt() != 0U;
8136 for (
int i = 1; i <
event.ExtraDataCount(); i++)
8139 if (needsReschedule)
8145 const QList<uint> &offlineEncoderIDs,
bool needsReschedule)
8147 QStringList extraData;
8148 extraData.push_back(
8149 QString::number(
static_cast<uint>(needsReschedule)));
8151 QList<uint>::const_iterator it;
8152 for (it = offlineEncoderIDs.begin(); it != offlineEncoderIDs.end(); ++it)
8153 extraData.push_back(QString::number(*it));
8155 MythEvent me(
"LOCAL_SLAVE_BACKEND_ENCODERS_OFFLINE", extraData);
8161#if CONFIG_SYSTEMD_NOTIFY
8162 QStringList status2;
8165 status2 << QString(
"Master backend.");
8167 status2 << QString(
"Slave backend.");
8172 int playback = 0, frontend = 0, monitor = 0, slave = 0, media = 0;
8178 if (
pbs->IsDisconnected())
8180 if (
pbs->isSlaveBackend())
8182 else if (
pbs->isMediaServer())
8184 else if (
pbs->IsFrontend())
8186 else if (
pbs->getBlockShutdown())
8191 status2 << QString(
"Connections: Pl %1, Fr %2, Mo %3, Sl %4, MS %5, FT %6, Co %7")
8192 .arg(playback).arg(frontend).arg(monitor).arg(slave).arg(media)
8203 if (not elink->IsLocal())
8205 switch (elink->GetState())
8224 for (
auto & recording : recordings)
8232 while (!recordings.empty())
8236 recordings.pop_back();
8240 QString(
"Recordings: active %1, scheduled %2")
8241 .arg(active).arg(scheduled);
8245 QString status(
"STATUS=" + status2.join(
' '));
8246 (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