15#include "libmythbase/mythconfig.h"
18#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
19#include <QtSystemDetection>
24#if CONFIG_SYSTEMD_NOTIFY
25#include <systemd/sd-daemon.h>
29#include <QCoreApplication>
33#include <QWaitCondition>
34#include <QWriteLocker>
36#include <QRegularExpression>
40#include <QNetworkInterface>
41#include <QNetworkProxy>
42#include <QHostAddress>
57#include "libmythbase/mythversion.h"
88static constexpr std::chrono::milliseconds
PRT_TIMEOUT { 10ms };
92#define LOC QString("MainServer: ")
93#define LOC_WARN QString("MainServer, Warning: ")
94#define LOC_ERR QString("MainServer, Error: ")
99 bool followLinks,
bool checkexists)
103 bool success1 =
true;
104 bool success2 =
true;
106 LOG(VB_FILE, LOG_INFO,
LOC +
107 QString(
"About to delete file: %1").arg(
filename));
111 if (finfo.isSymLink())
115 QFile target(linktext);
116 success1 = target.remove();
119 LOG(VB_GENERAL, LOG_ERR,
LOC +
120 QString(
"Error deleting '%1' -> '%2'")
125 if (!checkexists || checkFile.exists())
127 success2 = checkFile.remove();
130 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error deleting '%1': %2")
134 return success1 && success2;
199 QMutexLocker locker(&
m_lock);
209 m_wait.wait(locker.mutex(), left.count());
215 QMutexLocker locker(&
m_lock);
240 QMap<int, EncoderLink *> *_tvList,
242 m_encoderList(_tvList),
244 m_ismaster(master), m_threadPool(
"ProcessRequestPool"),
245 m_sched(
sched), m_expirer(_expirer)
267 bool v4IsSet = !config_v4.isNull();
272 bool v6IsSet = !config_v6.isNull();
274 if (v6IsSet && !listenAddrs.contains(config_v6))
275 LOG(VB_GENERAL, LOG_WARNING,
LOC +
276 "Unable to find IPv6 address to bind");
278 if (v4IsSet && !listenAddrs.contains(config_v4))
279 LOG(VB_GENERAL, LOG_WARNING,
LOC +
280 "Unable to find IPv4 address to bind");
282 if ((v4IsSet && !listenAddrs.contains(config_v4))
283 && (v6IsSet && !listenAddrs.contains(config_v6))
286 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to find either IPv4 or IPv6 "
287 "address we can bind to, exiting");
437 auto *ms =
new MythSocket(socketDescriptor,
this);
438 if (ms->IsConnected())
450 QCoreApplication::processEvents();
458 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"No data on sock %1")
472 QStringList listline;
475 if (!
pbs->ReadStringList(listline) || listline.empty())
478 LOG(VB_GENERAL, LOG_INFO,
"No data in ProcessRequestWork()");
483 else if (!bIsControl)
490 LOG(VB_GENERAL, LOG_INFO,
LOC +
"No data in ProcessRequestWork()");
494 QString line = listline[0];
496 line = line.simplified();
497 QStringList tokens = line.split(
' ', Qt::SkipEmptyParts);
498 QString command = tokens[0];
500 if (command ==
"MYTH_PROTO_VERSION")
502 if (tokens.size() < 2)
508 if (command ==
"ANN")
513 if (command ==
"DONE")
524 LOG(VB_GENERAL, LOG_ERR,
LOC +
"ProcessRequest unknown socket");
530 if (command ==
"QUERY_FILETRANSFER")
532 if (tokens.size() != 2)
537 else if (command ==
"QUERY_RECORDINGS")
539 if (tokens.size() != 2)
544 else if (command ==
"QUERY_RECORDING")
548 else if (command ==
"GO_TO_SLEEP")
552 else if (command ==
"QUERY_FREE_SPACE")
556 else if (command ==
"QUERY_FREE_SPACE_LIST")
560 else if (command ==
"QUERY_FREE_SPACE_SUMMARY")
564 else if (command ==
"QUERY_LOAD")
568 else if (command ==
"QUERY_UPTIME")
572 else if (command ==
"QUERY_HOSTNAME")
576 else if (command ==
"QUERY_MEMSTATS")
580 else if (command ==
"QUERY_TIME_ZONE")
584 else if (command ==
"QUERY_CHECKFILE")
588 else if (command ==
"QUERY_FILE_EXISTS")
590 if (listline.size() < 2)
595 else if (command ==
"QUERY_FINDFILE")
597 if (listline.size() < 4)
602 else if (command ==
"QUERY_FILE_HASH")
604 if (listline.size() < 3)
609 else if (command ==
"QUERY_GUIDEDATATHROUGH")
613 else if (command ==
"DELETE_FILE")
615 if (listline.size() < 3)
620 else if (command ==
"MOVE_FILE")
622 if (listline.size() < 4)
627 else if (command ==
"STOP_RECORDING")
631 else if (command ==
"CHECK_RECORDING")
635 else if (command ==
"DELETE_RECORDING")
637 if (3 <= tokens.size() && tokens.size() <= 5)
639 bool force = (tokens.size() >= 4) && (tokens[3] ==
"FORCE");
640 bool forget = (tokens.size() >= 5) && (tokens[4] ==
"FORGET");
648 else if (command ==
"FORCE_DELETE_RECORDING")
652 else if (command ==
"UNDELETE_RECORDING")
656 else if (command ==
"ADD_CHILD_INPUT")
661 LOG(VB_GENERAL, LOG_ERR,
LOC +
662 "ADD_CHILD_INPUT command received in master context");
663 reslist << QString(
"ERROR: Called in master context");
665 else if (tokens.size() != 2)
667 reslist <<
"ERROR: Bad ADD_CHILD_INPUT request";
675 reslist << QString(
"ERROR: Failed to add child input");
679 else if (command ==
"RESCHEDULE_RECORDINGS")
681 listline.pop_front();
684 else if (command ==
"FORGET_RECORDING")
688 else if (command ==
"QUERY_GETALLPENDING")
690 if (tokens.size() == 1)
692 else if (tokens.size() == 2)
697 else if (command ==
"QUERY_GETALLSCHEDULED")
701 else if (command ==
"QUERY_GETCONFLICTING")
705 else if (command ==
"QUERY_GETEXPIRING")
709 else if (command ==
"QUERY_SG_GETFILELIST")
713 else if (command ==
"QUERY_SG_FILEQUERY")
717 else if (command ==
"GET_FREE_INPUT_INFO")
719 if (tokens.size() != 2)
724 else if (command ==
"QUERY_RECORDER")
726 if (tokens.size() != 2)
731 else if ((command ==
"QUERY_RECORDING_DEVICE") ||
732 (command ==
"QUERY_RECORDING_DEVICES"))
736 else if (command ==
"SET_NEXT_LIVETV_DIR")
738 if (tokens.size() != 3)
743 else if (command ==
"SET_CHANNEL_INFO")
747 else if (command ==
"QUERY_REMOTEENCODER")
749 if (tokens.size() != 2)
754 else if (command ==
"GET_RECORDER_FROM_NUM")
758 else if (command ==
"GET_RECORDER_NUM")
762 else if (command ==
"QUERY_GENPIXMAP2")
766 else if (command ==
"QUERY_PIXMAP_LASTMODIFIED")
770 else if (command ==
"QUERY_PIXMAP_GET_IF_MODIFIED")
774 else if (command ==
"QUERY_ISRECORDING")
778 else if (command ==
"MESSAGE")
780 if ((listline.size() >= 2) && (listline[1].startsWith(
"SET_VERBOSE")))
782 else if ((listline.size() >= 2) &&
783 (listline[1].startsWith(
"SET_LOG_LEVEL")))
788 else if (command ==
"FILL_PROGRAM_INFO")
792 else if (command ==
"LOCK_TUNER")
794 if (tokens.size() == 1)
796 else if (tokens.size() == 2)
801 else if (command ==
"FREE_TUNER")
803 if (tokens.size() != 2)
808 else if (command ==
"QUERY_ACTIVE_BACKENDS")
812 else if (command ==
"QUERY_IS_ACTIVE_BACKEND")
814 if (tokens.size() != 1)
819 else if (command ==
"QUERY_COMMBREAK")
821 if (tokens.size() != 3)
826 else if (command ==
"QUERY_CUTLIST")
828 if (tokens.size() != 3)
833 else if (command ==
"QUERY_BOOKMARK")
835 if (tokens.size() != 3)
840 else if (command ==
"SET_BOOKMARK")
842 if (tokens.size() != 4)
847 else if (command ==
"QUERY_SETTING")
849 if (tokens.size() != 3)
854 else if (command ==
"SET_SETTING")
856 if (tokens.size() != 4)
861 else if (command ==
"SCAN_VIDEOS")
865 else if (command ==
"SCAN_MUSIC")
869 else if (command ==
"MUSIC_TAG_UPDATE_VOLATILE")
871 if (listline.size() != 6)
876 else if (command ==
"MUSIC_CALC_TRACK_LENGTH")
878 if (listline.size() != 3)
883 else if (command ==
"MUSIC_TAG_UPDATE_METADATA")
885 if (listline.size() != 3)
890 else if (command ==
"MUSIC_FIND_ALBUMART")
892 if (listline.size() != 4)
897 else if (command ==
"MUSIC_TAG_GETIMAGE")
899 if (listline.size() < 4)
904 else if (command ==
"MUSIC_TAG_ADDIMAGE")
906 if (listline.size() < 5)
911 else if (command ==
"MUSIC_TAG_REMOVEIMAGE")
913 if (listline.size() < 4)
918 else if (command ==
"MUSIC_TAG_CHANGEIMAGE")
920 if (listline.size() < 5)
925 else if (command ==
"MUSIC_LYRICS_FIND")
927 if (listline.size() < 3)
932 else if (command ==
"MUSIC_LYRICS_GETGRABBERS")
936 else if (command ==
"MUSIC_LYRICS_SAVE")
938 if (listline.size() < 3)
943 else if (command ==
"IMAGE_SCAN")
946 QStringList reply = (listline.size() == 2)
948 : QStringList(
"ERROR") <<
"Bad: " << listline;
952 else if (command ==
"IMAGE_COPY")
955 QStringList reply = (listline.size() >= 2)
957 : QStringList(
"ERROR") <<
"Bad: " << listline;
961 else if (command ==
"IMAGE_MOVE")
964 QStringList reply = (listline.size() == 4)
966 HandleDbMove(listline[1], listline[2], listline[3])
967 : QStringList(
"ERROR") <<
"Bad: " << listline;
971 else if (command ==
"IMAGE_DELETE")
974 QStringList reply = (listline.size() == 2)
976 : QStringList(
"ERROR") <<
"Bad: " << listline;
980 else if (command ==
"IMAGE_HIDE")
983 QStringList reply = (listline.size() == 3)
985 HandleHide(listline[1].toInt() != 0, listline[2])
986 : QStringList(
"ERROR") <<
"Bad: " << listline;
990 else if (command ==
"IMAGE_TRANSFORM")
993 QStringList reply = (listline.size() == 3)
995 HandleTransform(listline[1].toInt(), listline[2])
996 : QStringList(
"ERROR") <<
"Bad: " << listline;
1000 else if (command ==
"IMAGE_RENAME")
1003 QStringList reply = (listline.size() == 3)
1005 : QStringList(
"ERROR") <<
"Bad: " << listline;
1009 else if (command ==
"IMAGE_CREATE_DIRS")
1012 QStringList reply = (listline.size() >= 4)
1014 HandleDirs(listline[1], listline[2].toInt() != 0, listline.mid(3))
1015 : QStringList(
"ERROR") <<
"Bad: " << listline;
1019 else if (command ==
"IMAGE_COVER")
1022 QStringList reply = (listline.size() == 3)
1024 HandleCover(listline[1].toInt(), listline[2].toInt())
1025 : QStringList(
"ERROR") <<
"Bad: " << listline;
1029 else if (command ==
"IMAGE_IGNORE")
1032 QStringList reply = (listline.size() == 2)
1034 : QStringList(
"ERROR") <<
"Bad: " << listline;
1038 else if (command ==
"ALLOW_SHUTDOWN")
1040 if (tokens.size() != 1)
1045 else if (command ==
"BLOCK_SHUTDOWN")
1047 if (tokens.size() != 1)
1052 else if (command ==
"SHUTDOWN_NOW")
1054 if (tokens.size() != 1)
1061 if (listline.size() >= 2)
1062 halt_cmd = listline[1];
1064 if (!halt_cmd.isEmpty())
1066 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
1067 "Going down now as of Mainserver request!");
1076 else if (command ==
"BACKEND_MESSAGE")
1078 const QString& message = listline[1];
1079 QStringList extra( listline[2] );
1080 extra.reserve(listline.size() - 2);
1081 for (
int i = 3; i < listline.size(); i++)
1082 extra << listline[i];
1086 else if ((command ==
"DOWNLOAD_FILE") ||
1087 (command ==
"DOWNLOAD_FILE_NOW"))
1089 if (listline.size() != 4)
1094 else if (command ==
"REFRESH_BACKEND")
1096 LOG(VB_GENERAL, LOG_INFO ,
LOC +
"Reloading backend settings");
1099 else if (command ==
"OK")
1101 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Got 'OK' out of sequence.");
1103 else if (command ==
"UNKNOWN_COMMAND")
1105 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Got 'UNKNOWN_COMMAND' out of sequence.");
1109 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unknown command: " + command);
1113 QStringList strlist;
1114 strlist <<
"UNKNOWN_COMMAND";
1127 QStringList broadcast;
1128 QSet<QString> receivers;
1146 auto *me =
dynamic_cast<MythEvent *
>(e);
1150 QString message = me->
Message();
1152 if ((message ==
"PREVIEW_SUCCESS" || message ==
"PREVIEW_QUEUED") &&
1153 me->ExtraDataCount() >= 5)
1156 uint recordingID = me->ExtraData(0).toUInt();
1157 const QString&
filename = me->ExtraData(1);
1158 const QString& msg = me->ExtraData(2);
1159 const QString& datetime = me->ExtraData(3);
1161 if (message ==
"PREVIEW_QUEUED")
1163 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1164 QString(
"Preview Queued: '%1' '%2'")
1170 ok = ok &&
file.open(QIODevice::ReadOnly);
1174 QByteArray data =
file.readAll();
1175 QStringList extra(
"OK");
1176 extra.reserve(7 + std::max(0, me->ExtraDataCount()-4));
1177 extra.push_back(QString::number(recordingID));
1178 extra.push_back(msg);
1179 extra.push_back(datetime);
1180 extra.push_back(QString::number(data.size()));
1181#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1182 quint16 checksum = qChecksum(data.constData(), data.size());
1184 quint16 checksum = qChecksum(data);
1186 extra.push_back(QString::number(checksum));
1187 extra.push_back(QString(data.toBase64()));
1189 for (
uint i = 4 ; i < (
uint) me->ExtraDataCount(); i++)
1191 const QString& token = me->ExtraData(i);
1192 extra.push_back(token);
1196 receivers.insert(*it);
1201 if (receivers.empty())
1203 LOG(VB_GENERAL, LOG_ERR,
LOC +
1204 "PREVIEW_SUCCESS but no receivers.");
1208 broadcast.push_back(
"BACKEND_MESSAGE");
1209 broadcast.push_back(
"GENERATED_PIXMAP");
1214 message =
"PREVIEW_FAILED";
1220 if (message ==
"PREVIEW_FAILED" && me->ExtraDataCount() >= 5)
1222 const QString& pginfokey = me->ExtraData(0);
1223 const QString& msg = me->ExtraData(2);
1225 QStringList extra(
"ERROR");
1226 extra.reserve(3 + std::max(0, me->ExtraDataCount()-4));
1227 extra.push_back(pginfokey);
1228 extra.push_back(msg);
1229 for (
uint i = 4 ; i < (
uint) me->ExtraDataCount(); i++)
1231 const QString& token = me->ExtraData(i);
1232 extra.push_back(token);
1236 receivers.insert(*it);
1241 if (receivers.empty())
1243 LOG(VB_GENERAL, LOG_ERR,
LOC +
1244 "PREVIEW_FAILED but no receivers.");
1248 broadcast.push_back(
"BACKEND_MESSAGE");
1249 broadcast.push_back(
"GENERATED_PIXMAP");
1253 if (me->Message().startsWith(
"AUTO_EXPIRE"))
1255 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1256 if (tokens.size() != 3)
1258 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad AUTO_EXPIRE message");
1282 QString msg = QString(
"Cannot find program info for '%1', "
1283 "while attempting to Auto-Expire.")
1284 .arg(me->Message());
1285 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
1291 if (me->Message().startsWith(
"QUERY_NEXT_LIVETV_DIR") &&
m_sched)
1293 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1294 if (tokens.size() != 2)
1296 LOG(VB_GENERAL, LOG_ERR,
LOC +
1297 QString(
"Bad %1 message").arg(tokens[0]));
1305 if (me->Message().startsWith(
"STOP_RECORDING"))
1307 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1308 if (tokens.size() < 3 || tokens.size() > 3)
1310 LOG(VB_GENERAL, LOG_ERR,
LOC +
1311 QString(
"Bad STOP_RECORDING message: %1")
1312 .arg(me->Message()));
1325 LOG(VB_GENERAL, LOG_ERR,
LOC +
1326 QString(
"Cannot find program info for '%1' while "
1327 "attempting to stop recording.").arg(me->Message()));
1333 if ((me->Message().startsWith(
"DELETE_RECORDING")) ||
1334 (me->Message().startsWith(
"FORCE_DELETE_RECORDING")))
1336 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1337 if (tokens.size() < 3 || tokens.size() > 5)
1339 LOG(VB_GENERAL, LOG_ERR,
LOC +
1340 QString(
"Bad %1 message").arg(tokens[0]));
1344 bool force = (tokens.size() >= 4) && (tokens[3] ==
"FORCE");
1345 bool forget = (tokens.size() >= 5) && (tokens[4] ==
"FORGET");
1352 if (tokens[0] ==
"FORCE_DELETE_RECORDING")
1359 LOG(VB_GENERAL, LOG_ERR,
LOC +
1360 QString(
"Cannot find program info for '%1' while "
1361 "attempting to delete.").arg(me->Message()));
1367 if (me->Message().startsWith(
"UNDELETE_RECORDING"))
1369 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1370 if (tokens.size() < 3 || tokens.size() > 3)
1372 LOG(VB_GENERAL, LOG_ERR,
LOC +
1373 QString(
"Bad UNDELETE_RECORDING message: %1")
1374 .arg(me->Message()));
1387 LOG(VB_GENERAL, LOG_ERR,
LOC +
1388 QString(
"Cannot find program info for '%1' while "
1389 "attempting to undelete.").arg(me->Message()));
1395 if (me->Message().startsWith(
"ADD_CHILD_INPUT"))
1397 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1400 LOG(VB_GENERAL, LOG_ERR,
LOC +
1401 "ADD_CHILD_INPUT event received in slave context");
1403 else if (tokens.size() != 2)
1405 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad ADD_CHILD_INPUT message");
1414 if (me->Message().startsWith(
"RESCHEDULE_RECORDINGS") &&
m_sched)
1416 const QStringList& request = me->ExtraDataList();
1421 if (me->Message().startsWith(
"SCHEDULER_ADD_RECORDING") &&
m_sched)
1426 LOG(VB_GENERAL, LOG_ERR,
LOC +
1427 "Bad SCHEDULER_ADD_RECORDING message");
1435 if (me->Message().startsWith(
"UPDATE_RECORDING_STATUS") &&
m_sched)
1437 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
1438 if (tokens.size() != 6)
1440 LOG(VB_GENERAL, LOG_ERR,
LOC +
1441 "Bad UPDATE_RECORDING_STATUS message");
1445 uint cardid = tokens[1].toUInt();
1446 uint chanid = tokens[2].toUInt();
1451 recstatus, recendts);
1457 if (me->Message().startsWith(
"LIVETV_EXITED"))
1459 const QString& chainid = me->ExtraData();
1467 if (me->Message() ==
"CLEAR_SETTINGS_CACHE")
1470 if (me->Message().startsWith(
"RESET_IDLETIME") &&
m_sched)
1473 if (me->Message() ==
"LOCAL_RECONNECT_TO_MASTER")
1476 if (me->Message() ==
"LOCAL_SLAVE_BACKEND_ENCODERS_OFFLINE")
1479 if (me->Message().startsWith(
"LOCAL_"))
1482 if (me->Message() ==
"CREATE_THUMBNAILS")
1485 if (me->Message() ==
"IMAGE_GET_METADATA")
1488 std::unique_ptr<MythEvent> mod_me {
nullptr};
1489 if (me->Message().startsWith(
"MASTER_UPDATE_REC_INFO"))
1491 QStringList tokens = me->Message().simplified().split(
" ");
1492 uint recordedid = 0;
1493 if (tokens.size() >= 2)
1494 recordedid = tokens[1].toUInt();
1495 if (recordedid == 0)
1509 mod_me = std::make_unique<MythEvent>(
"RECORDING_LIST_CHANGE UPDATE", list);
1517 if (me->Message().startsWith(
"DOWNLOAD_FILE"))
1519 QStringList extraDataList = me->ExtraDataList();
1520 QString localFile = extraDataList[1];
1521 QFile
file(localFile);
1522 QStringList tokens = me->Message().simplified().split(
" ");
1530 if ((tokens.size() >= 2) && (tokens[1] ==
"FINISHED"))
1533 mod_me = std::make_unique<MythEvent>(me->Message(), extraDataList);
1536 if (broadcast.empty())
1538 broadcast.push_back(
"BACKEND_MESSAGE");
1539 if (mod_me !=
nullptr)
1541 broadcast.push_back(mod_me->Message());
1542 broadcast += mod_me->ExtraDataList();
1546 broadcast.push_back(me->Message());
1547 broadcast += me->ExtraDataList();
1552 if (!broadcast.empty())
1555 std::vector<PlaybackSock *> localPBSList;
1561 localPBSList.push_back(
pbs);
1565 bool sendGlobal =
false;
1566 if (
m_ismaster && broadcast[1].startsWith(
"GLOBAL_"))
1568 broadcast[1].replace(
"GLOBAL_",
"LOCAL_");
1569 MythEvent me(broadcast[1], broadcast[2]);
1575 QSet<PlaybackSock*> sentSet;
1577 bool isSystemEvent = broadcast[1].startsWith(
"SYSTEM_EVENT ");
1580 std::vector<PlaybackSock*>::const_iterator iter;
1581 for (iter = localPBSList.begin(); iter != localPBSList.end(); ++iter)
1585 if (sentSet.contains(
pbs) ||
pbs->IsDisconnected())
1588 if (!receivers.empty() && !receivers.contains(
pbs->getHostname()))
1591 sentSet.insert(
pbs);
1593 bool reallysendit =
false;
1595 if (broadcast[1] ==
"CLEAR_SETTINGS_CACHE")
1598 (
pbs->isSlaveBackend() ||
pbs->wantsEvents()))
1599 reallysendit =
true;
1601 else if (sendGlobal)
1603 if (
pbs->isSlaveBackend())
1604 reallysendit =
true;
1606 else if (
pbs->wantsEvents())
1608 reallysendit =
true;
1615 if (!
pbs->wantsSystemEvents())
1619 if (!
pbs->wantsOnlySystemEvents())
1621 if (sentSetSystemEvent.contains(
pbs->getHostname()))
1624 sentSetSystemEvent <<
pbs->getHostname();
1627 else if (
pbs->wantsOnlySystemEvents())
1639 for (iter = localPBSList.begin(); iter != localPBSList.end(); ++iter)
1657 QStringList retlist;
1658 const QString&
version = slist[1];
1659 if (
version != MYTH_PROTO_VERSION)
1661 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1662 "MainServer::HandleVersion - Client speaks protocol version " +
1663 version +
" but we speak " + MYTH_PROTO_VERSION +
'!');
1664 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1670 if (slist.size() < 3)
1672 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1673 "MainServer::HandleVersion - Client did not pass protocol "
1674 "token. Refusing connection!");
1675 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1681 const QString& token = slist[2];
1682 if (token != QString::fromUtf8(MYTH_PROTO_TOKEN))
1684 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1685 QString(
"MainServer::HandleVersion - Client sent incorrect "
1686 "protocol token \"%1\" for protocol version. Refusing "
1687 "connection!").arg(token));
1688 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1694 retlist <<
"ACCEPT" << MYTH_PROTO_VERSION;
1723 QStringList retlist(
"OK" );
1724 QStringList errlist(
"ERROR" );
1726 if (commands.size() < 3 || commands.size() > 6)
1729 if (commands.size() == 2)
1730 info = QString(
" %1").arg(commands[1]);
1732 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Received malformed ANN%1 query")
1735 errlist <<
"malformed_ann_query";
1743 if (
pbs->getSocket() == socket)
1745 LOG(VB_GENERAL, LOG_WARNING,
LOC +
1746 QString(
"Client %1 is trying to announce a socket "
1756 if (commands[1] ==
"Playback" || commands[1] ==
"Monitor" ||
1757 commands[1] ==
"Frontend")
1759 if (commands.size() < 4)
1761 LOG(VB_GENERAL, LOG_ERR,
LOC +
1762 QString(
"Received malformed ANN %1 query")
1765 errlist <<
"malformed_ann_query";
1782 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"MainServer::ANN %1")
1784 LOG(VB_GENERAL, LOG_INFO,
LOC +
1785 QString(
"adding: %1(%2) as a client (events: %3)")
1787 .arg(quintptr(socket),0,16)
1789 pbs->setBlockShutdown((commands[1] ==
"Playback") ||
1790 (commands[1] ==
"Frontend"));
1792 if (commands[1] ==
"Frontend")
1794 pbs->SetAsFrontend();
1796 frontend->m_name = commands[2];
1811 else if (commands[1] ==
"MediaServer")
1813 if (commands.size() < 3)
1815 LOG(VB_GENERAL, LOG_ERR,
LOC +
1816 "Received malformed ANN MediaServer query");
1817 errlist <<
"malformed_ann_query";
1826 pbs->setAsMediaServer();
1827 pbs->setBlockShutdown(
false);
1832 QString(
"CLIENT_CONNECTED HOSTNAME %1").arg(commands[2]));
1834 else if (commands[1] ==
"SlaveBackend")
1836 if (commands.size() < 4)
1838 LOG(VB_GENERAL, LOG_ERR,
LOC +
1839 QString(
"Received malformed ANN %1 query")
1841 errlist <<
"malformed_ann_query";
1853 LOG(VB_GENERAL, LOG_INFO,
LOC +
1854 QString(
"adding: %1 as a slave backend server")
1856 pbs->setAsSlaveBackend();
1857 pbs->setIP(commands[3]);
1862 QStringList::const_iterator sit = slist.
cbegin()+1;
1863 while (sit != slist.cend())
1866 if (!recinfo->GetChanID())
1876 bool wasAsleep =
true;
1880 if (elink->GetHostName() == commands[2])
1882 if (! (elink->IsWaking() || elink->IsAsleep()))
1884 elink->SetSocket(
pbs);
1892 QString message = QString(
"LOCAL_SLAVE_BACKEND_ONLINE %2")
1897 pbs->setBlockShutdown(
false);
1902 QString(
"SLAVE_CONNECTED HOSTNAME %1").arg(commands[2]));
1904 else if (commands[1] ==
"FileTransfer")
1906 if (slist.size() < 3)
1908 LOG(VB_GENERAL, LOG_ERR,
LOC +
1909 "Received malformed FileTransfer command");
1910 errlist <<
"malformed_filetransfer_command";
1915 LOG(VB_NETWORK, LOG_INFO,
LOC +
1916 "MainServer::HandleAnnounce FileTransfer");
1917 LOG(VB_NETWORK, LOG_INFO,
LOC +
1918 QString(
"adding: %1 as a remote file transfer") .arg(commands[2]));
1919 QStringList::const_iterator it = slist.cbegin();
1920 QString path = *(++it);
1921 QString wantgroup = *(++it);
1923 QStringList checkfiles;
1925 for (++it; it != slist.cend(); ++it)
1929 bool writemode =
false;
1930 bool usereadahead =
true;
1931 std::chrono::milliseconds timeout_ms = 2s;
1932 if (commands.size() > 3)
1933 writemode = (commands[3].toInt() != 0);
1935 if (commands.size() > 4)
1936 usereadahead = (commands[4].toInt() != 0);
1938 if (commands.size() > 5)
1939 timeout_ms = std::chrono::milliseconds(commands[5].toInt());
1943 if (wantgroup.isEmpty())
1944 wantgroup =
"Default";
1950 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to determine directory "
1951 "to write to in FileTransfer write command");
1952 errlist <<
"filetransfer_directory_not_found";
1959 LOG(VB_GENERAL, LOG_ERR,
LOC +
1960 QString(
"FileTransfer write filename is empty in path '%1'.")
1962 errlist <<
"filetransfer_filename_empty";
1967 if ((path.contains(
"/../")) ||
1968 (path.startsWith(
"../")))
1970 LOG(VB_GENERAL, LOG_ERR,
LOC +
1971 QString(
"FileTransfer write filename '%1' does not pass "
1972 "sanity checks.") .arg(path));
1973 errlist <<
"filetransfer_filename_dangerous";
1987 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Empty filename, cowardly aborting!");
1988 errlist <<
"filetransfer_filename_empty";
1997 LOG(VB_GENERAL, LOG_ERR,
LOC +
1998 QString(
"FileTransfer filename '%1' is actually a directory, "
1999 "cannot transfer.") .arg(
filename));
2000 errlist <<
"filetransfer_filename_is_a_directory";
2007 QString dirPath = finfo.absolutePath();
2011 if (!qdir.mkpath(dirPath))
2013 LOG(VB_GENERAL, LOG_ERR,
LOC +
2014 QString(
"FileTransfer filename '%1' is in a "
2015 "subdirectory which does not exist, and can "
2016 "not be created.") .arg(
filename));
2017 errlist <<
"filetransfer_unable_to_create_subdirectory";
2037 LOG(VB_GENERAL, LOG_ERR,
LOC +
2038 QString(
"Can't open %1").arg(
filename));
2039 errlist <<
"filetransfer_unable_to_open_file";
2046 LOG(VB_GENERAL, LOG_INFO,
LOC +
2047 QString(
"adding: %1(%2) as a file transfer")
2049 .arg(quintptr(socket),0,16));
2059 if (!checkfiles.empty())
2062 QDir dir = fi.absoluteDir();
2063 for (
const auto &
file : std::as_const(checkfiles))
2065 if (dir.exists(
file) &&
2066 (
file.endsWith(
".srt") ||
2099 QStringList strList(
"ERROR");
2114 bool do_write =
false;
2129 LOG(VB_GENERAL, LOG_ERR,
LOC +
2130 "SendResponse: Unable to write to client socket, as it's no "
2146 QString playbackhost =
pbs->getHostname();
2148 QMap<QString,ProgramInfo*> recMap;
2153 QMap<QString,bool> isJobRunning =
2159 if ((
type ==
"Ascending") || (
type ==
"Play"))
2161 else if ((
type ==
"Descending") || (
type ==
"Delete"))
2166 destination, (
type ==
"Recording"),
2167 inUseMap, isJobRunning, recMap, sort);
2169 QMap<QString,ProgramInfo*>::iterator mit = recMap.begin();
2170 for (; mit != recMap.end(); mit = recMap.erase(mit))
2173 QStringList outputlist(QString::number(destination.
size()));
2174 QMap<QString, int> backendPortMap;
2178 for (
auto* proginfo : destination)
2189 proginfo->GetBasename()));
2190 if (!proginfo->GetFilesize())
2193 if (tmpURL.startsWith(
'/'))
2195 QFile checkFile(tmpURL);
2196 if (!tmpURL.isEmpty() && checkFile.exists())
2198 proginfo->SetFilesize(checkFile.size());
2199 if (proginfo->GetRecordingEndTime() <
2202 proginfo->SaveFilesize(proginfo->GetFilesize());
2211 if (proginfo->GetPathname().isEmpty())
2213 LOG(VB_GENERAL, LOG_ERR,
LOC +
2214 QString(
"HandleQueryRecordings() "
2215 "Couldn't find backend for:\n\t\t\t%1")
2218 proginfo->SetFilesize(0);
2219 proginfo->SetPathname(
"file not found");
2224 if (!proginfo->GetFilesize())
2228 LOG(VB_GENERAL, LOG_ERR,
LOC +
2229 "MainServer::HandleQueryRecordings()"
2230 "\n\t\t\tCould not fill program info "
2235 if (proginfo->GetRecordingEndTime() <
2238 proginfo->SaveFilesize(proginfo->GetFilesize());
2247 if (!backendPortMap.contains(
hostname))
2259 proginfo->ToStringList(outputlist);
2272 if (slist.size() < 3)
2274 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad QUERY_RECORDING query");
2279 QString command = slist[1].toUpper();
2282 if (command ==
"BASENAME")
2286 else if (command ==
"TIMESLOT")
2288 if (slist.size() < 4)
2290 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad QUERY_RECORDING query");
2295 pginfo =
new ProgramInfo(slist[2].toUInt(), recstartts);
2298 QStringList strlist;
2319 const QString& playbackhost = slist[1];
2321 QStringList::const_iterator it = slist.cbegin() + 2;
2336 const QFileInfo
info(lpath);
2340 QStringList strlist;
2358 std::this_thread::sleep_for(3s + std::chrono::microseconds(
MythRandom(0, 2000)));
2363 QString logInfo = QString(
"recording id %1 (chanid %2 at %3)")
2368 QString name = QString(
"deleteThread%1%2").arg(getpid()).arg(
MythRandom());
2374 QString msg = QString(
"ERROR opening database connection for Delete "
2375 "Thread for chanid %1 recorded at %2. Program "
2376 "will NOT be deleted.")
2379 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2389 QString msg = QString(
"ERROR retrieving program info when trying to "
2390 "delete program for chanid %1 recorded at %2. "
2391 "Recording will NOT be deleted.")
2394 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2404 if ((!checkFile.exists()) && pginfo.
GetFilesize() &&
2407 LOG(VB_GENERAL, LOG_ERR,
LOC +
2408 QString(
"ERROR when trying to delete file: %1. File "
2409 "doesn't exist. Database metadata will not be removed.")
2427 bool errmsg =
false;
2442 if ((fd < 0) && checkFile.exists())
2448 std::this_thread::sleep_for(2s);
2449 if (checkFile.exists())
2455 LOG(VB_GENERAL, LOG_ERR,
LOC +
2456 QString(
"Error deleting file: %1. Keeping metadata in database.")
2471 QStringList nameFilters;
2472 nameFilters.push_back(fInfo.fileName() +
"*.png");
2473 nameFilters.push_back(fInfo.fileName() +
"*.jpg");
2474 nameFilters.push_back(fInfo.fileName() +
".tmp");
2475 nameFilters.push_back(fInfo.fileName() +
".old");
2476 nameFilters.push_back(fInfo.fileName() +
".map");
2477 nameFilters.push_back(fInfo.fileName() +
".tmp.map");
2478 nameFilters.push_back(fInfo.baseName() +
".srt");
2480 QDir dir (fInfo.path());
2481 QFileInfoList miscFiles = dir.entryInfoList(nameFilters);
2483 for (
const auto &
file : std::as_const(miscFiles))
2485 QString sFileName =
file.absoluteFilePath();
2497 if (slowDeletes && fd >= 0)
2503 QString logInfo = QString(
"recording id %1 filename %2")
2506 LOG(VB_GENERAL, LOG_NOTICE,
"DeleteRecordedFiles - " + logInfo);
2510 query.
prepare(
"SELECT basename, hostname, storagegroup FROM recordedfile "
2511 "WHERE recordedid = :RECORDEDID;");
2514 if (!query.
exec() || !query.
size())
2517 LOG(VB_GENERAL, LOG_ERR,
LOC +
2518 QString(
"Error querying recordedfiles for %1.") .arg(logInfo));
2521 while (query.
next())
2523 QString basename = query.
value(0).toString();
2526 bool deleteInDB =
false;
2528 if (basename == QFileInfo(ds->
m_filename).fileName())
2559 update.
prepare(
"DELETE FROM recordedfile "
2560 "WHERE recordedid = :RECORDEDID "
2561 "AND basename = :BASENAME ;");
2563 update.
bindValue(
":BASENAME", basename);
2567 LOG(VB_GENERAL, LOG_ERR,
LOC +
2568 QString(
"Error querying recordedfile (%1) for %2.")
2569 .arg(query.
value(1).toString(), logInfo));
2577 QString logInfo = QString(
"recording id %1 (chanid %2 at %3)")
2581 LOG(VB_GENERAL, LOG_NOTICE,
"DoDeleteINDB - " + logInfo);
2584 query.
prepare(
"DELETE FROM recorded WHERE recordedid = :RECORDEDID AND "
2589 if (!query.
exec() || !query.
size())
2592 LOG(VB_GENERAL, LOG_ERR,
LOC +
2593 QString(
"Error deleting recorded entry for %1.") .arg(logInfo));
2596 std::this_thread::sleep_for(1s);
2599 QString msg = QString(
"RECORDING_LIST_CHANGE DELETE %1")
2604 std::this_thread::sleep_for(3s);
2606 query.
prepare(
"DELETE FROM recordedmarkup "
2607 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2614 LOG(VB_GENERAL, LOG_ERR,
LOC +
2615 QString(
"Error deleting recordedmarkup for %1.") .arg(logInfo));
2618 query.
prepare(
"DELETE FROM recordedseek "
2619 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2626 LOG(VB_GENERAL, LOG_ERR,
LOC +
2627 QString(
"Error deleting recordedseek for %1.")
2642 bool deleteBrokenSymlinks)
2646 QString linktext =
"";
2647 QByteArray fname =
filename.toLocal8Bit();
2650 LOG(VB_FILE, LOG_INFO,
LOC +
2651 QString(
"About to unlink/delete file: '%1'")
2652 .arg(fname.constData()));
2654 QString errmsg = QString(
"Delete Error '%1'").arg(fname.constData());
2655 if (finfo.isSymLink())
2658 QByteArray alink = linktext.toLocal8Bit();
2659 errmsg += QString(
" -> '%2'").arg(alink.constData());
2662 if (followLinks && finfo.isSymLink())
2664 if (!finfo.exists() && deleteBrokenSymlinks)
2666 unlink(fname.constData());
2673 unlink(fname.constData());
2676 else if (!finfo.isSymLink())
2683 int err = unlink(fname.constData());
2688 if (fd < 0 && open_errno != EISDIR)
2689 LOG(VB_GENERAL, LOG_ERR,
LOC + errmsg +
ENO);
2705 QByteArray fname =
filename.toLocal8Bit();
2706 QString msg = QString(
"Error deleting '%1'").arg(fname.constData());
2707 int fd = open(fname.constData(), O_WRONLY);
2711 if (errno == EISDIR)
2716 LOG(VB_GENERAL, LOG_ERR, msg +
" could not delete directory " +
ENO);
2722 LOG(VB_GENERAL, LOG_ERR, msg +
" could not open " +
ENO);
2726 else if (unlink(fname.constData()))
2728 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
" could not unlink " +
ENO);
2745 const QString &
filename, off_t fsize)
2758 query.
prepare(
"SELECT COUNT(cardid) FROM capturecard;");
2760 cards = query.
value(0).toInt();
2764 constexpr std::chrono::milliseconds sleep_time = 500ms;
2765 const size_t min_tps = 8LL * 1024 * 1024;
2766 const auto calc_tps = (size_t) (cards * 1.2 * (22200000LL / 8.0));
2767 const size_t tps = std::max(min_tps, calc_tps);
2768 const auto increment = (size_t) (tps * (sleep_time.count() * 0.001F));
2770 LOG(VB_FILE, LOG_INFO,
LOC +
2771 QString(
"Truncating '%1' by %2 MB every %3 milliseconds")
2773 .arg(increment / (1024.0 * 1024.0), 0,
'f', 2)
2774 .arg(sleep_time.count()));
2776 GetMythDB()->GetDBManager()->PurgeIdleConnections(
false);
2782 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"Truncating '%1' to %2 MB")
2783 .arg(
filename).arg(fsize / (1024.0 * 1024.0), 0,
'f', 2));
2786 int err = ftruncate(fd, fsize);
2789 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error truncating '%1'")
2793 return 0 ==
close(fd);
2798 if (pginfo && ((count % 100) == 0))
2803 std::this_thread::sleep_for(sleep_time);
2806 bool ok = (0 ==
close(fd));
2811 LOG(VB_FILE, LOG_INFO,
LOC +
2812 QString(
"Finished truncating '%1'").arg(
filename));
2822 pbssock =
pbs->getSocket();
2824 QStringList::const_iterator it = slist.cbegin() + 1;
2846 result = iter.key();
2851 QStringList outputlist( QString::number(result) );
2858 QStringList::const_iterator it = slist.cbegin() + 1;
2870 bool hasConflicts =
false;
2872 for (
auto *pInfo : schedList)
2890 pbssock =
pbs->getSocket();
2913 (*m_encoderList)[num]->StopRecording();
2921 QStringList outputlist(
"0" );
2946 recnum = iter.key();
2953 std::this_thread::sleep_for(100us);
2969 QStringList outputlist( QString::number(recnum) );
2976 bool forceMetadataDelete,
2984 qDebug() <<
"HandleDeleteRecording(chanid, starttime) Empty Recording ID";
2991 pbssock =
pbs->getSocket();
2993 QStringList outputlist( QString::number(0) );
3003 bool forceMetadataDelete)
3005 QStringList::const_iterator it = slist.cbegin() + 1;
3010 qDebug() <<
"HandleDeleteRecording(QStringList) Empty Recording ID";
3019 bool forceMetadataDelete,
bool lexpirer,
bool forgetHistory)
3021 int resultCode = -1;
3024 pbssock =
pbs->getSocket();
3026 bool justexpire = lexpirer ?
false :
3034 LOG(VB_GENERAL, LOG_ERR,
LOC +
3035 QString(
"ERROR when trying to delete file for %1. Unable "
3036 "to determine filename of recording.")
3042 QStringList outputlist(QString::number(resultCode));
3052 if (justexpire && !forceMetadataDelete &&
3061 QStringList outputlist( QString::number(0) );
3085 QStringList outputlist( QString::number(num) );
3095 bool fileExists = checkFile.exists();
3098 QFile checkFileUTF8(QString::fromUtf8(
filename.toLatin1().constData()));
3099 fileExists = checkFileUTF8.exists();
3108 if (fileExists || !recinfo.
GetFilesize() || forceMetadataDelete)
3114 qDebug() <<
"DoHandleDeleteRecording() Empty Recording ID";
3121 forceMetadataDelete);
3122 deleteThread->start();
3127 QString logInfo = QString(
"chanid %1")
3131 LOG(VB_GENERAL, LOG_ERR,
LOC +
3132 QString(
"ERROR when trying to delete file: %1. File doesn't "
3133 "exist. Database metadata will not be removed.")
3140 QStringList outputlist( QString::number(resultCode) );
3152 if (fileExists || !recinfo.
GetFilesize() || forceMetadataDelete)
3155 QString(
"REC_DELETED CHANID %1 STARTTIME %2")
3165 if (slist.size() == 3)
3174 QStringList::const_iterator it = slist.cbegin()+1;
3188 pbssock =
pbs->getSocket();
3202 QStringList outputlist( QString::number(ret) );
3239 result = QStringList(QString::number(1));
3243 result = QStringList(QString::number(0));
3262 LOG(VB_GENERAL, LOG_INFO,
LOC +
"HandleAddChildInput: Already locked");
3266 LOG(VB_GENERAL, LOG_INFO,
LOC +
3267 QString(
"HandleAddChildInput: Handling input %1").arg(inputid));
3277 LOG(VB_GENERAL, LOG_ERR,
LOC +
3278 QString(
"HandleAddChildInput: "
3279 "Failed to add child to input %1").arg(inputid));
3285 LOG(VB_GENERAL, LOG_INFO,
LOC +
3286 QString(
"HandleAddChildInput: Added child input %1").arg(childid));
3294 auto *tv =
new TVRec(childid);
3295 if (!tv || !tv->Init())
3297 LOG(VB_GENERAL, LOG_ERR,
LOC +
3298 QString(
"HandleAddChildInput: "
3299 "Failed to initialize input %1").arg(childid));
3308 (*m_encoderList)[childid] = enc;
3315 LOG(VB_GENERAL, LOG_ERR,
LOC +
3316 QString(
"HandleAddChildInput: "
3317 "Failed to add remote input %1").arg(childid));
3327 (*m_encoderList)[childid] = enc;
3336 auto *tv =
new TVRec(inputid);
3337 if (!tv || !tv->Init())
3339 LOG(VB_GENERAL, LOG_ERR,
LOC +
3340 QString(
"HandleAddChildInput: "
3341 "Failed to initialize input %1").arg(inputid));
3349 (*m_encoderList)[inputid] = enc;
3355 LOG(VB_GENERAL, LOG_INFO,
LOC +
3356 QString(
"HandleAddChildInput: "
3357 "Successfully handled input %1").arg(inputid));
3364 QStringList::const_iterator it = slist.cbegin() + 1;
3371 pbssock =
pbs->getSocket();
3374 QStringList outputlist( QString::number(0) );
3386 QStringList strlist;
3389 if (!sleepCmd.isEmpty())
3393 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
3394 "Received GO_TO_SLEEP command from master, running SleepCommand.");
3399 strlist <<
"ERROR: SleepCommand is empty";
3400 LOG(VB_GENERAL, LOG_ERR,
LOC +
3401 "ERROR: in HandleGoToSleep(), but no SleepCommand found!");
3417 QStringList strlist;
3451 QStringList strlist;
3470 QStringList shortlist;
3471 if (strlist.size() < 4)
3473 shortlist << QString(
"0");
3474 shortlist << QString(
"0");
3478 unsigned int index = (
uint)(strlist.size()) - 2;
3479 shortlist << strlist[index++];
3480 shortlist << strlist[index++];
3496 QStringList strlist;
3498#if defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
3499 strlist <<
"0" <<
"0" <<
"0";
3505 strlist <<
"getloadavg() failed";
3509 strlist << QString::number(loads[0])
3510 << QString::number(loads[1])
3511 << QString::number(loads[2]);
3526 QStringList strlist;
3527 std::chrono::seconds uptime = 0s;
3531 strlist << QString::number(uptime.count());
3536 strlist <<
"Could not determine uptime.";
3550 QStringList strlist;
3565 QStringList strlist;
3571 if (
getMemStats(totalMB, freeMB, totalVM, freeVM))
3573 strlist << QString::number(totalMB) << QString::number(freeMB)
3574 << QString::number(totalVM) << QString::number(freeVM);
3579 strlist <<
"Could not determine memory stats.";
3593 QStringList strlist;
3608 bool checkSlaves = slist[1].toInt() != 0;
3610 QStringList::const_iterator it = slist.cbegin() + 2;
3626 QStringList outputlist( QString::number(
static_cast<int>(
exists)) );
3646 QStringList strlist( QString::number(
static_cast<int>(
exists)) );
3658 QString storageGroup =
"Default";
3663 switch (slist.size()) {
3665 if (!slist[3].isEmpty())
3669 if (slist[2].isEmpty())
3670 storageGroup = slist[2];
3678 LOG(VB_GENERAL, LOG_ERR,
LOC +
3679 QString(
"ERROR checking for file, filename '%1' "
3680 "fails sanity checks").arg(
filename));
3687 LOG(VB_GENERAL, LOG_ERR,
LOC +
3688 "ERROR, invalid input count for QUERY_FILE_HASH");
3725 const QString&
filename = slist[1];
3726 QString storageGroup =
"Default";
3727 QStringList retlist;
3729 if (slist.size() > 2)
3730 storageGroup = slist[2];
3736 LOG(VB_GENERAL, LOG_ERR,
LOC +
3737 QString(
"ERROR checking for file, filename '%1' "
3738 "fails sanity checks").arg(
filename));
3744 if (storageGroup.isEmpty())
3745 storageGroup =
"Default";
3751 if (!fullname.isEmpty())
3754 retlist << fullname;
3756 struct stat fileinfo {};
3757 if (stat(fullname.toLocal8Bit().constData(), &fileinfo) >= 0)
3759 retlist << QString::number(fileinfo.st_dev);
3760 retlist << QString::number(fileinfo.st_ino);
3761 retlist << QString::number(fileinfo.st_mode);
3762 retlist << QString::number(fileinfo.st_nlink);
3763 retlist << QString::number(fileinfo.st_uid);
3764 retlist << QString::number(fileinfo.st_gid);
3765 retlist << QString::number(fileinfo.st_rdev);
3766 retlist << QString::number(fileinfo.st_size);
3771 retlist << QString::number(fileinfo.st_blksize);
3772 retlist << QString::number(fileinfo.st_blocks);
3774 retlist << QString::number(fileinfo.st_atime);
3775 retlist << QString::number(fileinfo.st_mtime);
3776 retlist << QString::number(fileinfo.st_ctime);
3790 query.
prepare(
"SELECT MAX(endtime) FROM program WHERE manualid = 0;");
3800 QDateTime GuideDataThrough;
3802 QStringList strlist;
3806 if (GuideDataThrough.isNull())
3807 strlist << QString(
"0000-00-00 00:00");
3809 strlist << GuideDataThrough.toString(
"yyyy-MM-dd hh:mm");
3815 const QString& tmptable,
int recordid)
3819 QStringList strList;
3823 if (tmptable.isEmpty())
3837 query.
prepare(
"SELECT NULL FROM record "
3838 "WHERE recordid = :RECID;");
3844 record->m_recordID = recordid;
3845 if (record->Load() &&
3851 query.
prepare(
"DELETE FROM program WHERE manualid = :RECID;");
3861 strList << QString::number(0);
3862 strList << QString::number(0);
3872 QStringList strList;
3877 strList << QString::number(0);
3887 QStringList::const_iterator it = slist.cbegin() + 1;
3890 QStringList strlist;
3895 strlist << QString::number(0);
3904 QStringList strList;
3909 strList << QString::number(0);
3918 QStringList strList;
3920 if ((sList.size() < 4) || (sList.size() > 5))
3922 LOG(VB_GENERAL, LOG_ERR,
LOC +
3923 QString(
"HandleSGGetFileList: Invalid Request. %1")
3924 .arg(sList.join(
"[]:[]")));
3925 strList <<
"EMPTY LIST";
3931 const QString& wantHost = sList.at(1);
3932 QHostAddress wantHostaddr(wantHost);
3933 const QString& groupname = sList.at(2);
3934 const QString& path = sList.at(3);
3935 bool fileNamesOnly =
false;
3937 if (sList.size() >= 5)
3938 fileNamesOnly = (sList.at(4).toInt() != 0);
3940 bool slaveUnreachable =
false;
3942 LOG(VB_FILE, LOG_INFO,
LOC +
3943 QString(
"HandleSGGetFileList: group = %1 host = %2 "
3944 " path = %3 wanthost = %4")
3945 .arg(groupname, host, path, wantHost));
3949 if ((host.toLower() == wantHost.toLower()) ||
3950 (!addr.isEmpty() && addr == wantHostaddr.toString()))
3953 LOG(VB_FILE, LOG_INFO,
LOC +
"HandleSGGetFileList: Getting local info");
3964 LOG(VB_FILE, LOG_INFO,
LOC +
3965 "HandleSGGetFileList: Getting remote info");
3969 slaveUnreachable =
false;
3973 LOG(VB_FILE, LOG_INFO,
LOC +
3974 QString(
"HandleSGGetFileList: Failed to grab slave socket "
3975 ": %1 :").arg(wantHost));
3976 slaveUnreachable =
true;
3981 if (slaveUnreachable)
3982 strList <<
"SLAVE UNREACHABLE: " << host;
3984 if (strList.isEmpty() || (strList.at(0) ==
"0"))
3985 strList <<
"EMPTY LIST";
3995 QString storageGroup = slist[2];
3997 bool allowFallback =
true;
3998 bool useRegex =
false;
3999 QStringList fileList;
4001 if (!QHostAddress(
hostname).isNull())
4003 LOG(VB_GENERAL, LOG_ERR, QString(
"Mainserver: QUERY_FINDFILE called "
4004 "with IP (%1) instead of hostname. "
4005 "This is invalid.").arg(
hostname));
4011 if (storageGroup.isEmpty())
4012 storageGroup =
"Default";
4017 LOG(VB_GENERAL, LOG_ERR,
LOC +
4018 QString(
"ERROR QueryFindFile, filename '%1' "
4019 "fails sanity checks").arg(
filename));
4020 fileList <<
"ERROR: Bad/Missing Filename";
4025 if (slist.size() >= 5)
4026 useRegex = (slist[4].toInt() > 0);
4028 if (slist.size() >= 6)
4029 allowFallback = (slist[5].toInt() > 0);
4031 LOG(VB_FILE, LOG_INFO,
LOC +
4032 QString(
"Looking for file '%1' on host '%2' in group '%3' (useregex: %4, allowfallback: %5")
4046 QStringList files = sgroup.
GetFileList(
'/' + fi.path());
4048 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Looking in dir '%1' for '%2'")
4049 .arg(fi.path(), fi.fileName()));
4051 for (
int x = 0; x < files.size(); x++)
4053 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Found '%1 - %2'").arg(x).arg(files[x]));
4056 QStringList filteredFiles = files.filter(QRegularExpression(fi.fileName()));
4057 fileList.reserve(filteredFiles.size());
4058 for (
const QString&
file : std::as_const(filteredFiles))
4062 fi.path() +
'/' +
file,
4078 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Checking remote host '%1' for file").arg(
hostname));
4086 if (!slaveFiles.isEmpty() && slaveFiles[0] !=
"NOT FOUND" && !slaveFiles[0].startsWith(
"ERROR: "))
4087 fileList += slaveFiles;
4093 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Slave '%1' was unreachable").arg(
hostname));
4094 fileList << QString(
"ERROR: SLAVE UNREACHABLE: %1").arg(
hostname);
4102 if (
m_ismaster && fileList.isEmpty() && allowFallback)
4107 QString sql =
"SELECT DISTINCT hostname "
4108 "FROM storagegroup "
4109 "WHERE groupname = :GROUP "
4110 "AND hostname != :HOSTNAME";
4112 query.
bindValue(
":GROUP", storageGroup);
4118 fileList <<
"ERROR: failed to get host list";
4134 QStringList files = sgroup.
GetFileList(
'/' + fi.path());
4136 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Looking in dir '%1' for '%2'")
4137 .arg(fi.path(), fi.fileName()));
4139 for (
int x = 0; x < files.size(); x++)
4141 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Found '%1 - %2'").arg(x).arg(files[x]));
4144 QStringList filteredFiles = files.filter(QRegularExpression(fi.fileName()));
4146 for (
const QString&
file : std::as_const(filteredFiles))
4150 fi.path() +
'/' +
file,
4157 if (!fname.isEmpty())
4172 if (!slaveFiles.isEmpty() && slaveFiles[0] !=
"NOT FOUND" && !slaveFiles[0].startsWith(
"ERROR: "))
4173 fileList += slaveFiles;
4179 if (!fileList.isEmpty())
4184 if (fileList.isEmpty())
4186 fileList <<
"NOT FOUND";
4187 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"File was not found"));
4191 for (
int x = 0; x < fileList.size(); x++)
4193 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"File %1 was found at: '%2'").arg(x).arg(fileList[0]));
4206 QStringList strList;
4208 if (sList.size() < 4)
4210 LOG(VB_GENERAL, LOG_ERR,
LOC +
4211 QString(
"HandleSGFileQuery: Invalid Request. %1")
4212 .arg(sList.join(
"[]:[]")));
4213 strList <<
"EMPTY LIST";
4219 const QString& wantHost = sList.at(1);
4220 QHostAddress wantHostaddr(wantHost);
4221 const QString& groupname = sList.at(2);
4222 const QString&
filename = sList.at(3);
4224 bool allowFallback =
true;
4225 if (sList.size() >= 5)
4226 allowFallback = (sList.at(4).toInt() > 0);
4227 LOG(VB_FILE, LOG_ERR, QString(
"HandleSGFileQuery - allowFallback: %1").arg(allowFallback));
4229 bool slaveUnreachable =
false;
4231 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"HandleSGFileQuery: %1")
4236 if ((host.toLower() == wantHost.toLower()) ||
4237 (!addr.isEmpty() && addr == wantHostaddr.toString()))
4239 LOG(VB_FILE, LOG_INFO,
LOC +
"HandleSGFileQuery: Getting local info");
4248 LOG(VB_FILE, LOG_INFO,
LOC +
4249 "HandleSGFileQuery: Getting remote info");
4252 slaveUnreachable =
false;
4256 LOG(VB_FILE, LOG_INFO,
LOC +
4257 QString(
"HandleSGFileQuery: Failed to grab slave socket : %1 :")
4259 slaveUnreachable =
true;
4264 if (slaveUnreachable)
4265 strList <<
"SLAVE UNREACHABLE: " << wantHost;
4267 if (strList.count() == 0 || (strList.at(0) ==
"0"))
4268 strList <<
"EMPTY LIST";
4276 QString pbshost =
pbs->getHostname();
4278 QStringList strlist;
4287 if ((cardid != -1) && (cardid != elink->GetInputID()))
4290 if (elink->IsLocal())
4293 enchost = elink->GetHostName();
4295 if ((enchost == pbshost) &&
4296 (elink->IsConnected()) &&
4297 (!elink->IsBusy()) &&
4298 (!elink->IsTunerLocked()))
4312 QString msg = QString(
"Cardid %1 LOCKed for external use on %2.")
4313 .arg(retval).arg(pbshost);
4314 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
4317 query.
prepare(
"SELECT videodevice, audiodevice, "
4320 "WHERE cardid = :CARDID ;");
4326 strlist << QString::number(retval)
4327 << query.
value(0).toString()
4328 << query.
value(1).toString()
4329 << query.
value(2).toString();
4337 LOG(VB_GENERAL, LOG_ERR,
LOC +
4338 "MainServer::LockTuner(): Could not find "
4339 "card info in database");
4344 strlist <<
"-2" <<
"" <<
"" <<
"";
4350 strlist <<
"-1" <<
"" <<
"" <<
"";
4357 QStringList strlist;
4364 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleFreeTuner() " +
4365 QString(
"Unknown encoder: %1").arg(cardid));
4366 strlist <<
"FAILED";
4373 QString msg = QString(
"Cardid %1 FREED from external use on %2.")
4374 .arg(cardid).arg(
pbs->getHostname());
4375 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
4395 uint excluded_input)
4397 LOG(VB_CHANNEL, LOG_INFO,
4398 LOC + QString(
"Excluding input %1")
4399 .arg(excluded_input));
4402 std::vector<InputInfo> busyinputs;
4403 std::vector<InputInfo> freeinputs;
4404 QMap<uint, QSet<uint> > groupids;
4412 info.m_inputId = elink->GetInputID();
4414 if (!elink->IsConnected() || elink->IsTunerLocked())
4416 LOG(VB_CHANNEL, LOG_INFO,
4417 LOC + QString(
"Input %1 is locked or not connected")
4418 .arg(
info.m_inputId));
4422 std::vector<uint> infogroups;
4424 for (
uint group : infogroups)
4425 groupids[
info.m_inputId].insert(group);
4428 if (
info.m_inputId != excluded_input && elink->IsBusy(&busyinfo))
4430 LOG(VB_CHANNEL, LOG_DEBUG,
4431 LOC + QString(
"Input %1 is busy on %2/%3")
4435 busyinputs.push_back(
info);
4437 else if (
info.m_liveTvOrder)
4439 LOG(VB_CHANNEL, LOG_DEBUG,
4440 LOC + QString(
"Input %1 is free")
4441 .arg(
info.m_inputId));
4442 freeinputs.push_back(
info);
4449 for (
auto & busyinfo : busyinputs)
4451 auto freeiter = freeinputs.begin();
4452 while (freeiter != freeinputs.end())
4456 if ((groupids[busyinfo.m_inputId] & groupids[freeinfo.
m_inputId])
4463 if (busyinfo.m_sourceId == freeinfo.
m_sourceId)
4465 LOG(VB_CHANNEL, LOG_DEBUG,
4466 LOC + QString(
"Input %1 is limited to %2/%3 by input %4")
4467 .arg(freeinfo.
m_inputId).arg(busyinfo.m_chanId)
4468 .arg(busyinfo.m_mplexId).arg(busyinfo.m_inputId));
4469 freeinfo.
m_chanId = busyinfo.m_chanId;
4470 freeinfo.
m_mplexId = busyinfo.m_mplexId;
4475 LOG(VB_CHANNEL, LOG_DEBUG,
4476 LOC + QString(
"Input %1 is unavailable by input %2")
4477 .arg(freeinfo.
m_inputId).arg(busyinfo.m_inputId));
4478 freeiter = freeinputs.erase(freeiter);
4484 QStringList strlist;
4485 for (
auto & input : freeinputs)
4487 LOG(VB_CHANNEL, LOG_INFO,
4488 LOC + QString(
"Input %1 is available on %2/%3")
4489 .arg(input.m_inputId).arg(input.m_chanId)
4490 .arg(input.m_mplexId));
4491 input.ToStringList(strlist);
4494 if (strlist.empty())
4519 if (commands.size() < 2 || slist.size() < 2)
4522 int recnum = commands[1].toInt();
4529 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleRecorderQuery() " +
4530 QString(
"Unknown encoder: %1").arg(recnum));
4531 QStringList retlist(
"bad" );
4537 const QString& command = slist[1];
4539 QStringList retlist;
4544 LOG(VB_GENERAL, LOG_ERR,
LOC +
" MainServer::HandleRecorderQuery() " +
4545 QString(
"Command %1 for unconnected encoder %2")
4546 .arg(command).arg(recnum));
4552 if (command ==
"IS_RECORDING")
4556 else if (command ==
"GET_FRAMERATE")
4560 else if (command ==
"GET_FRAMES_WRITTEN")
4564 else if (command ==
"GET_FILE_POSITION")
4568 else if (command ==
"GET_MAX_BITRATE")
4572 else if (command ==
"GET_CURRENT_RECORDING")
4577 info->ToStringList(retlist);
4587 else if (command ==
"GET_KEYFRAME_POS")
4589 long long desired = slist[2].toLongLong();
4592 else if (command ==
"FILL_POSITION_MAP")
4594 int64_t start = slist[2].toLongLong();
4595 int64_t end = slist[3].toLongLong();
4604 for (
auto it = map.cbegin(); it != map.cend(); ++it)
4606 retlist += QString::number(it.key());
4607 retlist += QString::number(*it);
4609 if (retlist.empty())
4613 else if (command ==
"FILL_DURATION_MAP")
4615 int64_t start = slist[2].toLongLong();
4616 int64_t end = slist[3].toLongLong();
4625 for (
auto it = map.cbegin(); it != map.cend(); ++it)
4627 retlist += QString::number(it.key());
4628 retlist += QString::number(*it);
4630 if (retlist.empty())
4634 else if (command ==
"GET_RECORDING")
4649 else if (command ==
"FRONTEND_READY")
4654 else if (command ==
"CANCEL_NEXT_RECORDING")
4656 const QString& cancel = slist[2];
4657 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
4658 QString(
"Received: CANCEL_NEXT_RECORDING %1").arg(cancel));
4662 else if (command ==
"SPAWN_LIVETV")
4664 const QString& chainid = slist[2];
4675 enc->
SpawnLiveTV(chain, slist[3].toInt() != 0, slist[4]);
4678 else if (command ==
"STOP_LIVETV")
4695 else if (command ==
"PAUSE")
4700 else if (command ==
"FINISH_RECORDING")
4705 else if (command ==
"SET_LIVE_RECORDING")
4707 int recording = slist[2].toInt();
4711 else if (command ==
"GET_INPUT")
4714 ret = (ret.isEmpty()) ?
"UNKNOWN" : ret;
4717 else if (command ==
"SET_INPUT")
4719 const QString& input = slist[2];
4720 QString ret = enc->
SetInput(input);
4721 ret = (ret.isEmpty()) ?
"UNKNOWN" : ret;
4724 else if (command ==
"TOGGLE_CHANNEL_FAVORITE")
4726 const QString& changroup = slist[2];
4730 else if (command ==
"CHANGE_CHANNEL")
4736 else if (command ==
"SET_CHANNEL")
4738 const QString& name = slist[2];
4742 else if (command ==
"SET_SIGNAL_MONITORING_RATE")
4744 auto rate = std::chrono::milliseconds(slist[2].toInt());
4745 int notifyFrontend = slist[3].toInt();
4747 retlist << QString::number(oldrate.count());
4749 else if (command ==
"GET_COLOUR")
4752 retlist << QString::number(ret);
4754 else if (command ==
"GET_CONTRAST")
4757 retlist << QString::number(ret);
4759 else if (command ==
"GET_BRIGHTNESS")
4762 retlist << QString::number(ret);
4764 else if (command ==
"GET_HUE")
4767 retlist << QString::number(ret);
4769 else if (command ==
"CHANGE_COLOUR")
4771 int type = slist[2].toInt();
4772 bool up = slist[3].toInt() != 0;
4775 retlist << QString::number(ret);
4777 else if (command ==
"CHANGE_CONTRAST")
4779 int type = slist[2].toInt();
4780 bool up = slist[3].toInt() != 0;
4783 retlist << QString::number(ret);
4785 else if (command ==
"CHANGE_BRIGHTNESS")
4787 int type= slist[2].toInt();
4788 bool up = slist[3].toInt() != 0;
4791 retlist << QString::number(ret);
4793 else if (command ==
"CHANGE_HUE")
4795 int type= slist[2].toInt();
4796 bool up = slist[3].toInt() != 0;
4799 retlist << QString::number(ret);
4801 else if (command ==
"CHECK_CHANNEL")
4803 const QString& name = slist[2];
4804 retlist << QString::number((
int)(enc->
CheckChannel(name)));
4806 else if (command ==
"SHOULD_SWITCH_CARD")
4808 const QString& chanid = slist[2];
4811 else if (command ==
"CHECK_CHANNEL_PREFIX")
4813 QString needed_spacer;
4814 const QString&
prefix = slist[2];
4815 uint complete_valid_channel_on_rec = 0;
4816 bool is_extra_char_useful =
false;
4819 prefix, complete_valid_channel_on_rec,
4820 is_extra_char_useful, needed_spacer);
4822 retlist << QString::number((
int)match);
4823 retlist << QString::number(complete_valid_channel_on_rec);
4824 retlist << QString::number((
int)is_extra_char_useful);
4825 retlist << ((needed_spacer.isEmpty()) ? QString(
"X") : needed_spacer);
4827 else if (command ==
"GET_NEXT_PROGRAM_INFO" && (slist.size() >= 6))
4829 QString channelname = slist[2];
4830 uint chanid = slist[3].toUInt();
4832 QString starttime = slist[5];
4835 QString subtitle =
"";
4837 QString category =
"";
4838 QString endtime =
"";
4839 QString callsign =
"";
4840 QString iconpath =
"";
4841 QString seriesid =
"";
4842 QString programid =
"";
4845 title, subtitle, desc, category, starttime,
4846 endtime, callsign, iconpath, channelname, chanid,
4847 seriesid, programid);
4858 retlist << QString::number(chanid);
4862 else if (command ==
"GET_CHANNEL_INFO")
4864 uint chanid = slist[2].toUInt();
4866 QString callsign =
"";
4867 QString channum =
"";
4868 QString channame =
"";
4872 callsign, channum, channame, xmltv);
4874 retlist << QString::number(chanid);
4875 retlist << QString::number(sourceid);
4883 LOG(VB_GENERAL, LOG_ERR,
LOC +
4884 QString(
"Unknown command: %1").arg(command));
4896 int recnum = commands[1].toInt();
4903 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleSetNextLiveTVDir() " +
4904 QString(
"Unknown encoder: %1").arg(recnum));
4905 QStringList retlist(
"bad" );
4914 QStringList retlist(
"OK" );
4922 uint chanid = slist[1].toUInt();
4923 uint sourceid = slist[2].toUInt();
4924 QString oldcnum =
cleanup(slist[3]);
4925 QString callsign =
cleanup(slist[4]);
4926 QString channum =
cleanup(slist[5]);
4927 QString channame =
cleanup(slist[6]);
4928 QString xmltv =
cleanup(slist[7]);
4930 QStringList retlist;
4931 if (!chanid || !sourceid)
4943 ok &= encoder->SetChannelInfo(chanid, sourceid, oldcnum,
4944 callsign, channum, channame, xmltv);
4949 retlist << (ok ?
"1" :
"0");
4958 int recnum = commands[1].toInt();
4959 QStringList retlist;
4966 LOG(VB_GENERAL, LOG_ERR,
LOC +
4967 QString(
"HandleRemoteEncoder(cmd %1) ").arg(slist[1]) +
4968 QString(
"Unknown encoder: %1").arg(recnum));
4977 const QString& command = slist[1];
4979 if (command ==
"GET_STATE")
4981 retlist << QString::number((
int)enc->
GetState());
4983 else if (command ==
"GET_SLEEPSTATUS")
4987 else if (command ==
"GET_FLAGS")
4989 retlist << QString::number(enc->
GetFlags());
4991 else if (command ==
"IS_BUSY")
4993 std::chrono::seconds time_buffer = 5s;
4994 if (slist.size() >= 3)
4995 time_buffer = std::chrono::seconds(slist[2].toInt());
4997 retlist << QString::number((
int)enc->
IsBusy(&busy_input, time_buffer));
5000 else if (command ==
"MATCHES_RECORDING" &&
5003 QStringList::const_iterator it = slist.cbegin() + 2;
5008 else if (command ==
"START_RECORDING" &&
5011 QStringList::const_iterator it = slist.cbegin() + 2;
5018 else if (command ==
"GET_RECORDING_STATUS")
5022 else if (command ==
"RECORD_PENDING" &&
5025 auto secsleft = std::chrono::seconds(slist[2].toInt());
5026 int haslater = slist[3].toInt();
5027 QStringList::const_iterator it = slist.cbegin() + 4;
5034 else if (command ==
"CANCEL_NEXT_RECORDING" &&
5035 (slist.size() >= 3))
5037 bool cancel = (bool) slist[2].toInt();
5041 else if (command ==
"STOP_RECORDING")
5046 else if (command ==
"GET_MAX_BITRATE")
5050 else if (command ==
"GET_CURRENT_RECORDING")
5055 info->ToStringList(retlist);
5078 if (
pbs->isMediaServer())
5089 QStringList retlist;
5091 retlist.push_front(QString::number(retlist.size()));
5098 QStringList retlist;
5099 const QString& queryhostname = slist[1];
5104 if (slave !=
nullptr)
5124 size_t totalKBperMin = 0;
5129 if (!enc->IsConnected() || !enc->IsBusy())
5132 long long maxBitrate = enc->GetMaxBitrate();
5134 maxBitrate = 19500000LL;
5135 long long thisKBperMin = (((size_t)maxBitrate)*((size_t)15))>>11;
5136 totalKBperMin += thisKBperMin;
5137 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Cardid %1: max bitrate %2 KB/min")
5138 .arg(enc->GetInputID()).arg(thisKBperMin));
5142 LOG(VB_FILE, LOG_INFO,
LOC +
5143 QString(
"Maximal bitrate of busy encoders is %1 KB/min")
5144 .arg(totalKBperMin));
5146 return totalKBperMin;
5153 QString allHostList;
5157 QMap <QString, bool> backendsCounted;
5158 std::list<PlaybackSock *> localPlaybackList;
5164 if ((
pbs->IsDisconnected()) ||
5165 (!
pbs->isMediaServer()) ||
5167 (backendsCounted.contains(
pbs->getHostname())))
5170 backendsCounted[
pbs->getHostname()] =
true;
5172 localPlaybackList.push_back(
pbs);
5173 allHostList +=
"," +
pbs->getHostname();
5178 for (
auto &
pbs : localPlaybackList) {
5179 fsInfos <<
pbs->GetDiskSpace();
5188 maxWriteFiveSec = std::max((int64_t)2048, maxWriteFiveSec);
5207 QStringList strlist;
5215 for (
auto & fsInfo : fsInfos)
5217 fsInfo.setFSysID(-1);
5220 LOG(VB_SCHEDULE | VB_FILE, LOG_DEBUG,
LOC +
5221 "Determining unique filesystems");
5224 maxWriteFiveSec = std::max((
size_t)2048, maxWriteFiveSec);
5230 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5231 "--- GetFilesystemInfos directory list start ---");
5232 for (
const auto&
fs1 : std::as_const(fsInfos))
5235 QString(
"Dir: %1:%2")
5236 .arg(
fs1.getHostname(),
fs1.getPath());
5237 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC + msg) ;
5238 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5239 QString(
" Location: %1")
5240 .arg(
fs1.isLocal() ?
"Local" :
"Remote"));
5241 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5242 QString(
" fsID : %1")
5243 .arg(
fs1.getFSysID()));
5244 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5245 QString(
" dirID : %1")
5246 .arg(
fs1.getGroupID()));
5247 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5248 QString(
" BlkSize : %1")
5249 .arg(
fs1.getBlockSize()));
5250 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5251 QString(
" TotalKB : %1")
5252 .arg(
fs1.getTotalSpace()));
5253 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5254 QString(
" UsedKB : %1")
5255 .arg(
fs1.getUsedSpace()));
5256 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5257 QString(
" FreeKB : %1")
5258 .arg(
fs1.getFreeSpace()));
5260 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5261 "--- GetFilesystemInfos directory list end ---");
5270 const QString &src,
const QString &dst)
5273 QStringList retlist;
5275 if (src.isEmpty() || dst.isEmpty()
5276 || src.contains(
"..") || dst.contains(
".."))
5278 LOG(VB_GENERAL, LOG_ERR,
LOC +
5279 QString(
"HandleMoveFile: ERROR moving file '%1' -> '%2', "
5280 "a path fails sanity checks").arg(src, dst));
5281 retlist <<
"0" <<
"Invalid path";
5286 QString srcAbs = sgroup.
FindFile(src);
5287 if (srcAbs.isEmpty())
5289 LOG(VB_GENERAL, LOG_ERR,
LOC +
5290 QString(
"HandleMoveFile: Unable to find %1").arg(src));
5291 retlist <<
"0" <<
"Source file not found";
5299 QString dstAbs = sgroup.
FindFile(dst);
5300 if (!dstAbs.isEmpty() && QFileInfo(dstAbs).isFile())
5302 LOG(VB_GENERAL, LOG_ERR,
LOC +
5303 QString(
"HandleMoveFile: Destination exists at %1").arg(dstAbs));
5304 retlist <<
"0" <<
"Destination file exists";
5310 int sgPathSize = srcAbs.size() - src.size();
5311 dstAbs = srcAbs.mid(0, sgPathSize) + dst;
5325 LOG(VB_FILE, LOG_INFO, QString(
"MainServer::RenameThread: Renaming %1 -> %2")
5328 QStringList retlist;
5329 QFileInfo fi(
m_dst);
5331 if (QDir().mkpath(fi.path()) && QFile::rename(
m_src,
m_dst))
5337 retlist <<
"0" <<
"Rename failed";
5338 LOG(VB_FILE, LOG_ERR,
"MainServer::DoRenameThread: Rename failed");
5371 QStringList retlist;
5377 LOG(VB_GENERAL, LOG_ERR,
LOC +
5378 QString(
"ERROR deleting file, filename '%1' "
5379 "fails sanity checks").arg(
filename));
5390 if (fullfile.isEmpty()) {
5391 LOG(VB_GENERAL, LOG_ERR,
LOC +
5392 QString(
"Unable to find %1 in HandleDeleteFile()") .arg(
filename));
5401 QFile checkFile(fullfile);
5408 const QFileInfo
info(fullfile);
5412 if ((fd < 0) && checkFile.exists())
5414 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error deleting file: %1.")
5434 auto *truncateThread =
new TruncateThread(
this, fullfile, fd, size);
5435 truncateThread->run();
5446 const QString &starttime,
5451 pbssock =
pbs->getSocket();
5454 frm_dir_map_t::const_iterator it;
5456 QStringList retlist;
5459 const ProgramInfo pginfo(chanid.toUInt(), recstartdt);
5468 for (it = markMap.cbegin(); it != markMap.cend(); ++it)
5471 QString intstr = QString(
"%1").arg(*it);
5473 retlist << QString::number(it.key());
5478 retlist.prepend(QString(
"%1").arg(rowcnt));
5487 const QString &starttime,
5502 const QString &starttime,
5518 const QString &starttime,
5529 pbssock =
pbs->getSocket();
5533 chanid.toUInt(), recstartts);
5535 QStringList retlist;
5536 retlist << QString::number(bookmark);
5555 pbssock =
pbs->getSocket();
5557 const QString& chanid = tokens[1];
5558 const QString& starttime = tokens[2];
5559 long long bookmark = tokens[3].toLongLong();
5562 QStringList retlist;
5573 retlist <<
"FAILED";
5587 pbssock =
pbs->getSocket();
5589 const QString&
hostname = tokens[1];
5590 const QString& setting = tokens[2];
5591 QStringList retlist;
5595 retlist << retvalue;
5603 bool synchronous = (command[0] ==
"DOWNLOAD_FILE_NOW");
5604 const QString& srcURL = command[1];
5605 const QString& storageGroup = command[2];
5610 QStringList retlist;
5614 pbssock =
pbs->getSocket();
5618 QFileInfo finfo(srcURL);
5622 if (outDir.isEmpty())
5624 LOG(VB_GENERAL, LOG_ERR,
LOC +
5625 QString(
"Unable to determine directory "
5626 "to write to in %1 write command").arg(command[0]));
5627 retlist <<
"downloadfile_directory_not_found";
5636 LOG(VB_GENERAL, LOG_ERR,
LOC +
5637 QString(
"ERROR: %1 write filename '%2' does not pass "
5638 "sanity checks.") .arg(command[0],
filename));
5639 retlist <<
"downloadfile_filename_dangerous";
5682 pbssock =
pbs->getSocket();
5684 const QString&
hostname = tokens[1];
5685 const QString& setting = tokens[2];
5686 const QString& svalue = tokens[3];
5687 QStringList retlist;
5702 QStringList retlist;
5724 QStringList strlist;
5730 QString sql =
"SELECT DISTINCT hostname "
5731 "FROM storagegroup "
5732 "WHERE groupname = 'Music'";
5746 LOG(VB_GENERAL, LOG_INFO,
LOC +
5747 QString(
"HandleScanMusic: running filescanner on master BE '%1'").arg(
hostname));
5759 LOG(VB_GENERAL, LOG_INFO,
LOC +
5760 QString(
"HandleScanMusic: asking slave '%1' to run file scanner").arg(
hostname));
5766 LOG(VB_GENERAL, LOG_INFO,
LOC +
5767 QString(
"HandleScanMusic: Failed to grab slave socket on '%1'").arg(
hostname));
5776 LOG(VB_GENERAL, LOG_INFO,
LOC +
5777 QString(
"HandleScanMusic: running filescanner on slave BE '%1'")
5795 QStringList strlist;
5799 const QString&
hostname = slist[1];
5807 LOG(VB_GENERAL, LOG_INFO,
LOC +
5808 QString(
"HandleMusicTagUpdateVolatile: asking slave '%1' to update the metadata").arg(
hostname));
5818 LOG(VB_GENERAL, LOG_INFO,
LOC +
5819 QString(
"HandleMusicTagUpdateVolatile: Failed to grab slave socket on '%1'").arg(
hostname));
5821 strlist <<
"ERROR: slave not found";
5830 QStringList paramList;
5831 paramList.append(QString(
"--songid='%1'").arg(slist[2]));
5832 paramList.append(QString(
"--rating='%1'").arg(slist[3]));
5833 paramList.append(QString(
"--playcount='%1'").arg(slist[4]));
5834 paramList.append(QString(
"--lastplayed='%1'").arg(slist[5]));
5836 QString command =
GetAppBinDir() +
"mythutil --updatemeta " + paramList.join(
" ");
5838 LOG(VB_GENERAL, LOG_INFO,
LOC +
5839 QString(
"HandleMusicTagUpdateVolatile: running %1'").arg(command));
5855 QStringList strlist;
5859 const QString&
hostname = slist[1];
5867 LOG(VB_GENERAL, LOG_INFO,
LOC +
5868 QString(
"HandleMusicCalcTrackLen: asking slave '%1' to update the track length").arg(
hostname));
5878 LOG(VB_GENERAL, LOG_INFO,
LOC +
5879 QString(
"HandleMusicCalcTrackLen: Failed to grab slave socket on '%1'").arg(
hostname));
5881 strlist <<
"ERROR: slave not found";
5890 QStringList paramList;
5891 paramList.append(QString(
"--songid='%1'").arg(slist[2]));
5893 QString command =
GetAppBinDir() +
"mythutil --calctracklen " + paramList.join(
" ");
5895 LOG(VB_GENERAL, LOG_INFO,
LOC +
5896 QString(
"HandleMusicCalcTrackLen: running %1'").arg(command));
5913 QStringList strlist;
5917 const QString&
hostname = slist[1];
5925 LOG(VB_GENERAL, LOG_INFO,
LOC +
5926 QString(
"HandleMusicTagUpdateMetadata: asking slave '%1' "
5927 "to update the metadata").arg(
hostname));
5937 LOG(VB_GENERAL, LOG_INFO,
LOC +
5938 QString(
"HandleMusicTagUpdateMetadata: Failed to grab "
5939 "slave socket on '%1'").arg(
hostname));
5941 strlist <<
"ERROR: slave not found";
5950 int songID = slist[2].toInt();
5956 LOG(VB_GENERAL, LOG_ERR,
LOC +
5957 QString(
"HandleMusicTagUpdateMetadata: "
5958 "Cannot find metadata for trackid: %1")
5961 strlist <<
"ERROR: track not found";
5974 LOG(VB_GENERAL, LOG_ERR,
LOC +
5975 QString(
"HandleMusicTagUpdateMetadata: "
5976 "Failed to write to tag for trackid: %1")
5979 strlist <<
"ERROR: write to tag failed";
5999 QStringList strlist;
6003 const QString&
hostname = slist[1];
6011 LOG(VB_GENERAL, LOG_INFO,
LOC +
6012 QString(
"HandleMusicFindAlbumArt: asking slave '%1' "
6013 "to update the albumart").arg(
hostname));
6023 LOG(VB_GENERAL, LOG_INFO,
LOC +
6024 QString(
"HandleMusicFindAlbumArt: Failed to grab "
6025 "slave socket on '%1'").arg(
hostname));
6027 strlist <<
"ERROR: slave not found";
6036 int songID = slist[2].toInt();
6037 bool updateDatabase = (slist[3].toInt() == 1);
6043 LOG(VB_GENERAL, LOG_ERR,
LOC +
6044 QString(
"HandleMusicFindAlbumArt: "
6045 "Cannot find metadata for trackid: %1").arg(songID));
6047 strlist <<
"ERROR: track not found";
6057 QDir dir = fi.absoluteDir();
6060 "*.png;*.jpg;*.jpeg;*.gif;*.bmp");
6061 dir.setNameFilters(nameFilter.split(
";"));
6063 QStringList files = dir.entryList();
6068 fi.setFile(mdata->
Filename(
false));
6069 QString startDir = fi.path();
6071 for (
const QString&
file : std::as_const(files))
6075 image->m_filename = startDir +
'/' + fi.fileName();
6077 image->m_embedded =
false;
6079 image->m_description =
"";
6080 images->addImage(image);
6092 for (
int x = 0; x < artList.count(); x++)
6096 images->addImage(image);
6104 LOG(VB_GENERAL, LOG_ERR,
LOC +
6105 QString(
"HandleMusicFindAlbumArt: "
6106 "Failed to find a tagger for trackid: %1").arg(songID));
6111 images->dumpToDatabase();
6113 strlist.reserve(2 + (6 * images->getImageCount()));
6115 strlist.append(QString(
"%1").arg(images->getImageCount()));
6117 QStringList paramList;
6118 for (
uint x = 0; x < images->getImageCount(); x++)
6121 strlist.append(QString(
"%1").arg(image->
m_id));
6122 strlist.append(QString(
"%1").arg((
int)image->
m_imageType));
6123 strlist.append(QString(
"%1").arg(
static_cast<int>(image->
m_embedded)));
6132 paramList.reserve(2);
6133 paramList.append(QString(
"--songid='%1'").arg(mdata->
ID()));
6134 paramList.append(QString(
"--imagetype='%1'").arg(image->
m_imageType));
6136 QString command =
GetAppBinDir() +
"mythutil --extractimage " + paramList.join(
" ");
6154 QStringList strlist;
6158 const QString&
hostname = slist[1];
6159 const QString& songid = slist[2];
6160 const QString& imagetype = slist[3];
6168 LOG(VB_GENERAL, LOG_INFO,
LOC +
6169 QString(
"HandleMusicTagGetImage: asking slave '%1' to "
6170 "extract the image").arg(
hostname));
6180 LOG(VB_GENERAL, LOG_INFO,
LOC +
6181 QString(
"HandleMusicTagGetImage: Failed to grab slave "
6186 QStringList paramList;
6187 paramList.append(QString(
"--songid='%1'").arg(songid));
6188 paramList.append(QString(
"--imagetype='%1'").arg(imagetype));
6190 QString command =
GetAppBinDir() +
"mythutil --extractimage " + paramList.join(
" ");
6208 QStringList strlist;
6212 const QString&
hostname = slist[1];
6220 LOG(VB_GENERAL, LOG_INFO,
LOC +
6221 QString(
"HandleMusicTagChangeImage: asking slave '%1' "
6222 "to update the metadata").arg(
hostname));
6232 LOG(VB_GENERAL, LOG_INFO,
LOC +
6233 QString(
"HandleMusicTagChangeImage: Failed to grab "
6234 "slave socket on '%1'").arg(
hostname));
6236 strlist <<
"ERROR: slave not found";
6244 int songID = slist[2].toInt();
6245 auto oldType = (
ImageType)slist[3].toInt();
6246 auto newType = (
ImageType)slist[4].toInt();
6253 LOG(VB_GENERAL, LOG_ERR,
LOC +
6254 QString(
"HandleMusicTagChangeImage: "
6255 "Cannot find metadata for trackid: %1")
6258 strlist <<
"ERROR: track not found";
6299 LOG(VB_GENERAL, LOG_ERR,
"HandleMusicTagChangeImage: failed to change image type");
6301 strlist <<
"ERROR: failed to change image type";
6319 image->
m_filename = fi.path() + QString(
"/%1-%2.jpg")
6335 QStringList paramList;
6336 paramList.append(QString(
"--songid='%1'").arg(mdata->
ID()));
6337 paramList.append(QString(
"--imagetype='%1'").arg(image->
m_imageType));
6339 QString command =
GetAppBinDir() +
"mythutil --extractimage " + paramList.join(
" ");
6352 image->
m_filename = fi.absolutePath() + QString(
"/%1.jpg")
6377 QStringList strlist;
6381 const QString&
hostname = slist[1];
6389 LOG(VB_GENERAL, LOG_INFO,
LOC +
6390 QString(
"HandleMusicTagAddImage: asking slave '%1' "
6391 "to add the image").arg(
hostname));
6401 LOG(VB_GENERAL, LOG_INFO,
LOC +
6402 QString(
"HandleMusicTagAddImage: Failed to grab "
6403 "slave socket on '%1'").arg(
hostname));
6405 strlist <<
"ERROR: slave not found";
6414 int songID = slist[2].toInt();
6415 const QString&
filename = slist[3];
6416 auto imageType = (
ImageType) slist[4].toInt();
6422 LOG(VB_GENERAL, LOG_ERR,
LOC +
6423 QString(
"HandleMusicTagAddImage: Cannot find metadata for trackid: %1")
6426 strlist <<
"ERROR: track not found";
6438 LOG(VB_GENERAL, LOG_ERR,
LOC +
6439 "HandleMusicTagAddImage: failed to find a tagger for track");
6441 strlist <<
"ERROR: tagger not found";
6452 LOG(VB_GENERAL, LOG_ERR,
LOC +
6453 "HandleMusicTagAddImage: asked to write album art to the tag "
6454 "but the tagger doesn't support it!");
6456 strlist <<
"ERROR: embedded images not supported by tag";
6467 bool isDirectoryImage =
false;
6470 if (imageFilename.isEmpty())
6474 imageFilename = fi.absolutePath() +
'/' +
filename;
6475 isDirectoryImage =
true;
6480 LOG(VB_GENERAL, LOG_ERR,
LOC +
6481 QString(
"HandleMusicTagAddImage: cannot find image file %1").arg(
filename));
6483 strlist <<
"ERROR: failed to find image file";
6499 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleMusicTagAddImage: failed to write album art to tag");
6501 strlist <<
"ERROR: failed to write album art to tag";
6506 if (!isDirectoryImage)
6507 QFile::remove(imageFilename);
6515 if (!isDirectoryImage)
6516 QFile::remove(imageFilename);
6532 QStringList strlist;
6536 const QString&
hostname = slist[1];
6544 LOG(VB_GENERAL, LOG_INFO,
LOC +
6545 QString(
"HandleMusicTagRemoveImage: asking slave '%1' "
6546 "to remove the image").arg(
hostname));
6556 LOG(VB_GENERAL, LOG_INFO,
LOC +
6557 QString(
"HandleMusicTagRemoveImage: Failed to grab "
6558 "slave socket on '%1'").arg(
hostname));
6560 strlist <<
"ERROR: slave not found";
6568 int songID = slist[2].toInt();
6569 int imageID = slist[3].toInt();
6576 LOG(VB_GENERAL, LOG_ERR,
LOC +
6577 QString(
"HandleMusicTagRemoveImage: Cannot find metadata for trackid: %1")
6580 strlist <<
"ERROR: track not found";
6592 LOG(VB_GENERAL, LOG_ERR,
LOC +
6593 "HandleMusicTagRemoveImage: failed to find a tagger for track");
6595 strlist <<
"ERROR: tagger not found";
6606 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleMusicTagRemoveImage: asked to remove album art "
6607 "from the tag but the tagger doesn't support it!");
6609 strlist <<
"ERROR: embedded images not supported by tag";
6622 LOG(VB_GENERAL, LOG_ERR,
LOC +
6623 QString(
"HandleMusicTagRemoveImage: Cannot find image for imageid: %1")
6626 strlist <<
"ERROR: image not found";
6638 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleMusicTagRemoveImage: failed to remove album art from tag");
6640 strlist <<
"ERROR: failed to remove album art from tag";
6659 QStringList strlist;
6663 const QString&
hostname = slist[1];
6664 const QString& songid = slist[2];
6665 const QString& grabberName = slist[3];
6666 QString artist =
"";
6670 if (slist.size() == 7)
6683 LOG(VB_GENERAL, LOG_INFO,
LOC +
6684 QString(
"HandleMusicFindLyrics: asking slave '%1' to "
6695 LOG(VB_GENERAL, LOG_INFO,
LOC +
6696 QString(
"HandleMusicFindLyrics: Failed to grab slave "
6701 QStringList paramList;
6702 paramList.append(QString(
"--songid='%1'").arg(songid));
6703 paramList.append(QString(
"--grabber='%1'").arg(grabberName));
6705 if (!artist.isEmpty())
6706 paramList.append(QString(
"--artist=\"%1\"").arg(artist));
6708 if (!album.isEmpty())
6709 paramList.append(QString(
"--album=\"%1\"").arg(album));
6711 if (!title.isEmpty())
6712 paramList.append(QString(
"--title=\"%1\"").arg(title));
6714 QString command =
GetAppBinDir() +
"mythutil --findlyrics " + paramList.join(
" ");
6748 QStringList strlist;
6752 QString scriptDir =
GetShareDir() +
"metadata/Music/lyrics";
6757 LOG(VB_GENERAL, LOG_ERR, QString(
"Cannot find lyric scripts directory: %1").arg(scriptDir));
6758 strlist << QString(
"ERROR: Cannot find lyric scripts directory: %1").arg(scriptDir);
6766 d.setFilter(QDir::Files | QDir::NoDotAndDotDot);
6767 d.setNameFilters(QStringList(
"*.py"));
6768 QFileInfoList list =
d.entryInfoList();
6771 LOG(VB_GENERAL, LOG_ERR, QString(
"Cannot find any lyric scripts in: %1").arg(scriptDir));
6772 strlist << QString(
"ERROR: Cannot find any lyric scripts in: %1").arg(scriptDir);
6780 QStringList scripts;
6781 for (
const auto & fi : std::as_const(list))
6783 LOG(VB_FILE, LOG_NOTICE, QString(
"Found lyric script at: %1").arg(fi.filePath()));
6784 scripts.append(fi.filePath());
6787 QStringList grabbers;
6790 for (
int x = 0; x < scripts.count(); x++)
6792 QStringList
args { scripts.at(x),
"-v" };
6794 p.start(PYTHON_EXE,
args);
6795 p.waitForFinished(-1);
6796 QString result =
p.readAllStandardOutput();
6798 QDomDocument domDoc;
6799#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
6802 int errorColumn = 0;
6804 if (!domDoc.setContent(result,
false, &errorMsg, &errorLine, &errorColumn))
6806 LOG(VB_GENERAL, LOG_ERR,
6807 QString(
"FindLyrics: Could not parse version from %1").arg(scripts.at(x)) +
6808 QString(
"\n\t\t\tError at line: %1 column: %2 msg: %3").arg(errorLine).arg(errorColumn).arg(errorMsg));
6812 auto parseResult = domDoc.setContent(result);
6815 LOG(VB_GENERAL, LOG_ERR,
6816 QString(
"FindLyrics: Could not parse version from %1")
6817 .arg(scripts.at(x)) +
6818 QString(
"\n\t\t\tError at line: %1 column: %2 msg: %3")
6819 .arg(parseResult.errorLine).arg(parseResult.errorColumn)
6820 .arg(parseResult.errorMessage));
6825 QDomNodeList itemList = domDoc.elementsByTagName(
"grabber");
6826 QDomNode itemNode = itemList.item(0);
6828 grabbers.append(itemNode.namedItem(QString(
"name")).toElement().text());
6833 strlist.reserve(1 + grabbers.count());
6836 for (
int x = 0; x < grabbers.count(); x++)
6837 strlist.append(grabbers.at(x));
6848 QStringList strlist;
6852 const QString&
hostname = slist[1];
6853 int songID = slist[2].toInt();
6861 LOG(VB_GENERAL, LOG_INFO,
LOC +
6862 QString(
"HandleMusicSaveLyrics: asking slave '%1' to "
6873 LOG(VB_GENERAL, LOG_INFO,
LOC +
6874 QString(
"HandleMusicSaveLyrics: Failed to grab slave "
6882 LOG(VB_GENERAL, LOG_ERR, QString(
"Cannot find metadata for trackid: %1").arg(songID));
6883 strlist << QString(
"ERROR: Cannot find metadata for trackid: %1").arg(songID);
6891 QString lyricsFile =
GetConfDir() + QString(
"/MythMusic/Lyrics/%1.txt").arg(songID);
6895 QFile::remove(lyricsFile);
6898 QFile
file(QLatin1String(qPrintable(lyricsFile)));
6900 if (
file.open(QIODevice::WriteOnly))
6902 QTextStream stream(&
file);
6903 for (
int x = 3; x < slist.count(); x++)
6904 stream << slist.at(x);
6916 QStringList &commands,
6921 int recnum = commands[1].toInt();
6922 const QString& command = slist[1];
6924 QStringList retlist;
6930 if (command ==
"DONE")
6938 LOG(VB_GENERAL, LOG_ERR,
LOC +
6939 QString(
"Unknown file transfer socket: %1").arg(recnum));
6940 retlist << QString(
"ERROR: Unknown file transfer socket: %1")
6952 if (command ==
"REQUEST_BLOCK")
6954 int size = slist[2].toInt();
6958 else if (command ==
"WRITE_BLOCK")
6960 int size = slist[2].toInt();
6962 retlist << QString::number(ft->
WriteBlock(size));
6964 else if (command ==
"SEEK")
6966 long long pos = slist[2].toLongLong();
6967 int whence = slist[3].toInt();
6968 long long curpos = slist[4].toLongLong();
6970 long long ret = ft->
Seek(curpos, pos, whence);
6971 retlist << QString::number(ret);
6973 else if (command ==
"IS_OPEN")
6975 bool isopen = ft->
isOpen();
6977 retlist << QString::number(static_cast<int>(isopen));
6979 else if (command ==
"REOPEN")
6981 retlist << QString::number(static_cast<int>(ft->
ReOpen(slist[2])));
6983 else if (command ==
"DONE")
6988 else if (command ==
"SET_TIMEOUT")
6990 bool fast = slist[2].toInt() != 0;
6994 else if (command ==
"REQUEST_SIZE")
7002 LOG(VB_GENERAL, LOG_ERR,
LOC +
7003 QString(
"Unknown command: %1").arg(command));
7004 retlist <<
"ERROR" <<
"invalid_call";
7018 QStringList::const_iterator it = slist.cbegin() + 1;
7030 retval = iter.key();
7036 QStringList strlist( QString::number(retval) );
7053 strlist <<
"nohost";
7065 int recordernum = slist[1].toInt();
7067 QStringList strlist;
7090 strlist <<
"nohost";
7099 if (slist.size() < 2)
7104 const QString& message = slist[1];
7105 QStringList extra_data;
7106 extra_data.reserve(slist.size() - 2);
7107 for (
uint i = 2; i < (
uint) slist.size(); i++)
7108 extra_data.push_back(slist[i]);
7110 if (extra_data.empty())
7121 QStringList retlist(
"OK" );
7129 QStringList retlist;
7131 const QString& newverbose = slist[1];
7132 int len = newverbose.length();
7138 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
7139 QString(
"Verbose mask changed, new mask is: %1").arg(
verboseString));
7145 LOG(VB_GENERAL, LOG_ERR,
LOC +
7146 QString(
"Invalid SET_VERBOSE string: '%1'").arg(newverbose));
7147 retlist <<
"Failed";
7156 QStringList retlist;
7157 const QString& newstring = slist[1];
7158 LogLevel_t newlevel = LOG_UNKNOWN;
7160 int len = newstring.length();
7164 if (newlevel != LOG_UNKNOWN)
7168 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
7169 QString(
"Log level changed, new level is: %1")
7176 if (newlevel == LOG_UNKNOWN)
7178 LOG(VB_GENERAL, LOG_ERR,
LOC +
7179 QString(
"Invalid SET_VERBOSE string: '%1'").arg(newstring));
7180 retlist <<
"Failed";
7190 int RecordingsInProgress = 0;
7191 int LiveTVRecordingsInProgress = 0;
7192 QStringList retlist;
7197 if (elink->IsBusyRecording()) {
7198 RecordingsInProgress++;
7201 if (
info &&
info->GetRecordingGroup() ==
"LiveTV")
7202 LiveTVRecordingsInProgress++;
7209 retlist << QString::number(RecordingsInProgress);
7210 retlist << QString::number(LiveTVRecordingsInProgress);
7219 if (slist.size() < 3)
7221 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Too few params in pixmap request");
7222 QStringList outputlist(
"ERROR");
7223 outputlist +=
"TOO_FEW_PARAMS";
7228 bool time_fmt_sec =
true;
7229 std::chrono::seconds time = std::chrono::seconds::max();
7230 long long frame = -1;
7234 bool has_extra_data =
false;
7236 QString token = slist[1];
7237 if (token.isEmpty())
7239 LOG(VB_GENERAL, LOG_ERR,
LOC +
7240 "Failed to parse pixmap request. Token absent");
7241 QStringList outputlist(
"ERROR");
7242 outputlist +=
"TOKEN_ABSENT";
7247 QStringList::const_iterator it = slist.cbegin() + 2;
7248 QStringList::const_iterator end = slist.cend();
7253 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to parse pixmap request. "
7254 "ProgramInfo missing pathname");
7255 QStringList outputlist(
"BAD");
7256 outputlist +=
"NO_PATHNAME";
7260 if (token.toLower() ==
"do_not_care")
7262 token = QString(
"%1:%2")
7265 if (it != slist.cend())
7266 (time_fmt_sec = ((*it).toLower() ==
"s")), ++it;
7267 if (it != slist.cend())
7270 time = std::chrono::seconds((*it).toLongLong()), ++it;
7272 frame = (*it).toLongLong(), ++it;
7274 if (it != slist.cend())
7275 (outputfile = *it), ++it;
7276 outputfile = (outputfile ==
"<EMPTY>") ? QString() : outputfile;
7277 if (it != slist.cend())
7279 width = (*it).toInt(&ok); ++it;
7280 width = ok ? width : -1;
7282 if (it != slist.cend())
7284 height = (*it).toInt(&ok); ++it;
7285 height = ok ? height : -1;
7286 has_extra_data =
true;
7288 QSize outputsize = QSize(width, height);
7292 auto pos_text = (time != std::chrono::seconds::max())
7293 ? QString::number(time.count()) +
"s"
7294 : QString::number(frame) +
"f";
7295 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
7296 QString(
"HandleGenPreviewPixmap got extra data\n\t\t\t"
7299 .arg(width).arg(height).arg(outputfile));
7314 QStringList outputlist;
7317 if (time != std::chrono::seconds::max())
7320 token, &pginfo, time, -1, outputfile, outputsize);
7325 token, &pginfo, std::chrono::seconds::max(), frame, outputfile, outputsize);
7335 if (outputlist.empty() || outputlist[0] !=
"OK")
7341 LOG(VB_GENERAL, LOG_ERR,
LOC +
7342 QString(
"HandleGenPreviewPixmap() "
7343 "Couldn't find backend for:\n\t\t\t%1")
7349 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleGenPreviewPixmap: Unable to "
7350 "find file locally, unable to make preview image.");
7351 QStringList outputlist(
"ERROR" );
7352 outputlist +=
"FILE_INACCESSIBLE";
7360 if (time != std::chrono::seconds::max()) {
7362 pginfo, outputsize, outputfile, time, -1, token);
7365 pginfo, outputsize, outputfile, -1s, frame, token);
7373 QStringList outputlist(
"OK");
7374 if (!outputfile.isEmpty())
7375 outputlist += outputfile;
7383 QStringList::const_iterator it = slist.cbegin() + 1;
7388 QStringList strlist;
7401 strlist = (slavetime.isValid()) ?
7402 QStringList(QString::number(slavetime.toSecsSinceEpoch())) :
7409 LOG(VB_GENERAL, LOG_ERR,
LOC +
7410 QString(
"HandlePixmapLastModified() "
7411 "Couldn't find backend for:\n\t\t\t%1")
7417 LOG(VB_GENERAL, LOG_ERR,
LOC +
7418 "MainServer: HandlePixmapLastModified: Unable to "
7419 "find file locally, unable to get last modified date.");
7420 QStringList outputlist(
"BAD" );
7431 QDateTime lastmodified = finfo.lastModified();
7432 if (lastmodified.isValid())
7433 strlist = QStringList(QString::number(lastmodified.toSecsSinceEpoch()));
7435 strlist = QStringList(QString::number(UINT_MAX));
7439 strlist = QStringList(
"BAD" );
7448 QStringList strlist;
7453 strlist = QStringList(
"ERROR");
7454 strlist +=
"1: Parameter list too short";
7459 QDateTime cachemodified;
7460 if (!slist[1].isEmpty() && (slist[1].toInt() != -1))
7465 int max_file_size = slist[2].toInt();
7467 QStringList::const_iterator it = slist.begin() + 3;
7472 strlist = QStringList(
"ERROR");
7473 strlist +=
"2: Invalid ProgramInfo";
7484 size_t fsize = finfo.size();
7485 QDateTime lastmodified = finfo.lastModified();
7486 bool out_of_date = !cachemodified.isValid() ||
7487 (lastmodified > cachemodified);
7489 if (out_of_date && (fsize > 0) && ((ssize_t)fsize < max_file_size))
7493 bool open_ok =
file.open(QIODevice::ReadOnly);
7495 data =
file.readAll();
7497 if (!data.isEmpty())
7499 LOG(VB_FILE, LOG_INFO,
LOC +
7500 QString(
"Read preview file '%1'")
7502 if (lastmodified.isValid())
7503 strlist += QString::number(lastmodified.toSecsSinceEpoch());
7505 strlist += QString::number(UINT_MAX);
7506 strlist += QString::number(data.size());
7507#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
7508 quint16 checksum = qChecksum(data.constData(), data.size());
7510 quint16 checksum = qChecksum(data);
7512 strlist += QString::number(checksum);
7513 strlist += QString(data.toBase64());
7517 LOG(VB_GENERAL, LOG_ERR,
LOC +
7518 QString(
"Failed to read preview file '%1'")
7521 strlist = QStringList(
"ERROR");
7523 QString(
"3: Failed to read preview file '%1'%2")
7525 open_ok ?
"" :
" open failed");
7528 else if (out_of_date && (max_file_size > 0))
7530 if (fsize >= (
size_t) max_file_size)
7532 strlist = QStringList(
"WARNING");
7533 strlist += QString(
"1: Preview file too big %1 > %2")
7534 .arg(fsize).arg(max_file_size);
7538 strlist = QStringList(
"ERROR");
7539 strlist +=
"4: Preview file is invalid";
7544 if (lastmodified.isValid())
7545 strlist += QString::number(lastmodified.toSecsSinceEpoch());
7547 strlist += QString::number(UINT_MAX);
7561 strlist = QStringList(
"ERROR");
7563 "5: Could not locate mythbackend that made this recording";
7572 if (!strlist.empty())
7579 strlist = QStringList(
"WARNING");
7580 strlist +=
"2: Could not locate requested file";
7586 QStringList retlist(
"OK" );
7592 pbs->setBlockShutdown(blockShutdown);
7595 QStringList retlist(
"OK" );
7640 QList<uint> disconnectedSlaves;
7652 MythEvent me(
"LOCAL_RECONNECT_TO_MASTER");
7658 disconnectedSlaves.clear();
7659 bool needsReschedule =
false;
7663 LOG(VB_GENERAL, LOG_ERR,
LOC +
7664 QString(
"Slave backend: %1 no longer connected")
7665 .arg(
pbs->getHostname()));
7667 bool isFallingAsleep =
true;
7671 if (elink->GetSocket() ==
pbs)
7673 if (!elink->IsFallingAsleep())
7674 isFallingAsleep =
false;
7676 elink->SetSocket(
nullptr);
7678 disconnectedSlaves.push_back(elink->GetInputID());
7682 if (
m_sched && !isFallingAsleep)
7683 needsReschedule =
true;
7685 QString message = QString(
"LOCAL_SLAVE_BACKEND_OFFLINE %1")
7686 .arg(
pbs->getHostname());
7694 QString(
"SLAVE_DISCONNECTED HOSTNAME %1")
7695 .arg(
pbs->getHostname()));
7704 if (chain !=
nullptr)
7715 std::this_thread::sleep_for(500us);
7717 if (enc->IsBusy() &&
7718 enc->GetChainID() == chain->
GetID())
7729 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 sock(%2) '%3' disconnected")
7730 .arg(
pbs->getBlockShutdown() ?
"Playback" :
"Monitor")
7731 .arg(quintptr(socket),0,16)
7732 .arg(
pbs->getHostname()) );
7733 pbs->SetDisconnected();
7738 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Playback sock still exists?");
7746 if (!disconnectedSlaves.isEmpty())
7757 MythEvent me(
"LOCAL_CONNECTION_CLOSED");
7771 LOG(VB_GENERAL, LOG_INFO, QString(
"BEFileTransfer sock(%1) disconnected")
7772 .arg(quintptr(socket),0,16) );
7784 LOG(VB_GENERAL, LOG_INFO, QString(
"Control sock(%1) disconnected")
7785 .arg(quintptr(socket),0,16) );
7795 LOG(VB_GENERAL, LOG_WARNING,
LOC +
7796 QString(
"Unknown socket closing MythSocket(0x%1)")
7797 .arg((intptr_t)socket,0,16));
7810 if (
pbs->isSlaveBackend() &&
7833 if (
pbs->isMediaServer() &&
7849 {
return sock ==
pbs->getSocket(); });
7857 if (
id == ft->getSocket()->GetSocketDescriptor())
7866 if (sock == ft->getSocket())
7876 if (chain->GetID() ==
id)
7886 if (chain->IsHostSocket(sock))
7896 if (chain->ProgramIsAt(pginfo) >= 0)
7916 std::vector<LiveTVChain*> newChains;
7921 newChains.push_back(entry);
7931 if (closeApplication)
7937 QString lpath = QString(path);
7939 if (lpath.section(
'/', -2, -2) ==
"channels")
7942 QString
file = lpath.section(
'/', -1);
7946 query.
prepare(
"SELECT icon FROM channel "
7947 "WHERE deleted IS NULL AND icon LIKE :FILENAME ;");
7952 lpath = query.
value(0).toString();
7961 lpath = lpath.section(
'/', -1);
7963 QString fpath = lpath;
7964 if (fpath.endsWith(
".png"))
7965 fpath = fpath.left(fpath.length() - 4);
7971 if (pburl.startsWith(
"/"))
7973 lpath = pburl.section(
'/', 0, -2) +
"/" + lpath;
7974 LOG(VB_FILE, LOG_INFO,
LOC +
7975 QString(
"Local file path: %1").arg(lpath));
7979 LOG(VB_GENERAL, LOG_ERR,
LOC +
7980 QString(
"ERROR: LocalFilePath unable to find local "
7981 "path for '%1', found '%2' instead.")
7982 .arg(lpath, pburl));
7986 else if (!lpath.isEmpty())
7989 QString opath = lpath;
7992 if (!wantgroup.isEmpty())
7994 sgroup.
Init(wantgroup);
7995 lpath = QString(path);
7999 lpath = QFileInfo(lpath).fileName();
8002 QString tmpFile = sgroup.
FindFile(lpath);
8003 if (!tmpFile.isEmpty())
8006 LOG(VB_FILE, LOG_INFO,
LOC +
8007 QString(
"LocalFilePath(%1 '%2'), found file through "
8008 "exhaustive search at '%3'")
8009 .arg(path, opath, lpath));
8013 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"ERROR: LocalFilePath "
8014 "unable to find local path for '%1'.") .arg(path));
8030 auto *masterServerSock =
new MythSocket(-1,
this);
8035 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
8036 QString(
"Connecting to master server: %1:%2")
8037 .arg(server).arg(port));
8039 if (!masterServerSock->ConnectToHost(server, port))
8041 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
8042 "Connection to master server timed out.");
8044 masterServerSock->DecrRef();
8048 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Connected successfully");
8050 QString str = QString(
"ANN SlaveBackend %1 %2")
8054 QStringList strlist( str );
8059 elink->CancelNextRecording(
true);
8077 masterServerSock->SetReadyReadCallbackEnabled(
false);
8078 if (!masterServerSock->SendReceiveStringList(strlist, 1) ||
8079 (strlist[0] ==
"ERROR"))
8081 masterServerSock->DecrRef();
8082 masterServerSock =
nullptr;
8083 if (strlist.empty())
8085 LOG(VB_GENERAL, LOG_ERR,
LOC +
8086 "Failed to open master server socket, timeout");
8090 LOG(VB_GENERAL, LOG_ERR,
LOC +
8091 "Failed to open master server socket" +
8092 ((strlist.size() >= 2) ?
8093 QString(
", error was %1").arg(strlist[1]) :
8094 QString(
", remote error")));
8099 masterServerSock->SetReadyReadCallbackEnabled(
true);
8114 bool foundClient =
false;
8124 if ((*it)->isSlaveBackend())
8129 if (onlyBlockingClients && !(*it)->getBlockShutdown())
8146 QStringList bcast(
"SHUTDOWN_NOW" );
8153 if (
pbs->isSlaveBackend())
8154 pbs->getSocket()->WriteStringList(bcast);
8164 bool needsReschedule =
event.ExtraData(0).toUInt() != 0U;
8165 for (
int i = 1; i <
event.ExtraDataCount(); i++)
8168 if (needsReschedule)
8174 const QList<uint> &offlineEncoderIDs,
bool needsReschedule)
8176 QStringList extraData;
8177 extraData.push_back(
8178 QString::number(
static_cast<uint>(needsReschedule)));
8180 QList<uint>::const_iterator it;
8181 for (it = offlineEncoderIDs.begin(); it != offlineEncoderIDs.end(); ++it)
8182 extraData.push_back(QString::number(*it));
8184 MythEvent me(
"LOCAL_SLAVE_BACKEND_ENCODERS_OFFLINE", extraData);
8190#if CONFIG_SYSTEMD_NOTIFY
8191 QStringList status2;
8194 status2 << QString(
"Master backend.");
8196 status2 << QString(
"Slave backend.");
8201 int playback = 0, frontend = 0, monitor = 0, slave = 0, media = 0;
8207 if (
pbs->IsDisconnected())
8209 if (
pbs->isSlaveBackend())
8211 else if (
pbs->isMediaServer())
8213 else if (
pbs->IsFrontend())
8215 else if (
pbs->getBlockShutdown())
8220 status2 << QString(
"Connections: Pl %1, Fr %2, Mo %3, Sl %4, MS %5, FT %6, Co %7")
8221 .arg(playback).arg(frontend).arg(monitor).arg(slave).arg(media)
8232 if (not elink->IsLocal())
8234 switch (elink->GetState())
8253 for (
auto & recording : recordings)
8261 while (!recordings.empty())
8265 recordings.pop_back();
8269 QString(
"Recordings: active %1, scheduled %2")
8270 .arg(active).arg(scheduled);
8274 QString status(
"STATUS=" + status2.join(
' '));
8275 (void)sd_notify(0, qPrintable(status));
8279#include "moc_mainserver.cpp"
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