13 #include <QCoreApplication>
18 #include "libmythbase/mythconfig.h"
33 #define LOC QString("JobQueue: ")
40 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
41 m_runningJobsLock(new QMutex(QMutex::Recursive)),
43 m_runningJobsLock(new QRecursiveMutex()),
46 m_queueThread(new
MThread(
"JobQueue", this))
50 #ifndef USING_VALGRIND
55 LOG(VB_GENERAL, LOG_ERR,
LOC +
56 "The JobQueue has been disabled because "
57 "you compiled with the --enable-valgrind option.");
58 #endif // USING_VALGRIND
86 QString message = me->
Message();
88 if (message.startsWith(
"LOCAL_JOB"))
93 message = message.simplified();
94 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
95 QStringList tokens = message.split(
" ", QString::SkipEmptyParts);
97 QStringList tokens = message.split(
" ", Qt::SkipEmptyParts);
99 QString
action = tokens[1];
102 if (tokens[2] ==
"ID")
103 jobID = tokens[3].toInt();
115 msg = QString(
"Unable to determine jobID for message: "
116 "%1. Program will not be flagged.")
118 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
124 msg = QString(
"Received message '%1'").arg(message);
125 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + msg);
136 else if (
action ==
"PAUSE")
138 else if (
action ==
"RESUME")
140 else if (
action ==
"RESTART")
166 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
"ProcessQueue() started");
172 QMap<int, int> jobStatus;
174 QMap<int, JobQueueEntry> jobs;
176 QMap<int, RunningJobInfo>::Iterator rjiter;
183 bool startedJobAlready =
false;
186 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
187 QString(
"Currently set to run up to %1 job(s) max.")
196 if ((*rjiter).pginfo)
197 (*rjiter).pginfo->UpdateInUseMark();
207 for (
const auto & job : qAsConst(jobs))
209 int status = job.status;
212 if (((status == JOB_RUNNING) ||
213 (status == JOB_STARTING) ||
214 (status == JOB_PAUSED)) &&
219 message = QString(
"Currently Running %1 jobs.")
223 message += QString(
" Jobs in Queue, but we are outside of the "
224 "Job Queue time window, no new jobs can be "
226 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
230 message +=
" (At Maximum, no new jobs can be started until "
231 "a running job completes)";
234 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
240 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
248 int jobID = jobs[x].id;
249 int cmds = jobs[x].cmds;
251 int status = jobs[x].status;
255 logInfo = QString(
"jobID #%1").arg(
jobID);
257 logInfo = QString(
"chanid %1 @ %2").arg(jobs[x].chanid)
258 .arg(jobs[x].startts);
261 if ((inTimeWindow) &&
268 jobStatus[
jobID] = status;
270 message = QString(
"Skipping '%1' job for %2, "
271 "should run on '%3' instead")
274 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
283 if (otherJobID && (jobStatus.contains(otherJobID)) &&
284 (!(jobStatus[otherJobID] & JOB_DONE)))
287 QString(
"Skipping '%1' job for %2, "
288 "Job ID %3 is already running for "
289 "this recording with a status of '%4'")
291 QString::number(otherJobID),
293 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
298 jobStatus[
jobID] = status;
303 message = QString(
"Skipping '%1' job for %2, "
304 "not allowed to run on this backend.")
306 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
313 message = QString(
"Skipping '%1' job for %2, this job is "
314 "not scheduled to run until %3.")
318 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
326 if (status != JOB_QUEUED) {
327 message = QString(
"Stopping '%1' job for %2")
329 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
344 message = QString(
"Cancelling '%1' job for %2")
346 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
354 message = QString(
"Unable to claim '%1' job for %2")
356 LOG(VB_JOBQUEUE, LOG_ERR,
LOC + message);
365 if ((cmds &
JOB_PAUSE) && (status != JOB_QUEUED))
367 message = QString(
"Pausing '%1' job for %2")
369 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
380 if ((cmds &
JOB_RESTART) && (status != JOB_QUEUED))
382 message = QString(
"Restart '%1' job for %2")
384 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
395 if (status != JOB_QUEUED)
400 message = QString(
"Resetting '%1' job for %2 to %3 "
401 "status, because no hostname is set.")
405 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
410 else if (inTimeWindow)
412 message = QString(
"Skipping '%1' job for %2, "
413 "current job status is '%3'")
417 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
423 if (startedJobAlready)
426 if ((inTimeWindow) &&
430 message = QString(
"Unable to claim '%1' job for %2")
432 LOG(VB_JOBQUEUE, LOG_ERR,
LOC + message);
438 message = QString(
"Skipping '%1' job for %2, "
439 "current time is outside of the "
440 "Job Queue processing window.")
442 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
446 message = QString(
"Processing '%1' job for %2, "
447 "current status is '%3'")
450 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
454 startedJobAlready =
true;
465 LOG(VB_JOBQUEUE, LOG_INFO, QString(
"%1 jobs running. "
474 LOG(VB_JOBQUEUE, LOG_INFO,
"No jobs running. "
475 "Allowing shutdown.");
484 std::chrono::milliseconds st = (startedJobAlready) ? 5s : sleepTime;
501 QString jobHost = QString(
"");
514 const QString&
args,
const QString& comment, QString host,
515 int flags,
int status, QDateTime schedruntime)
517 int tmpStatus = JOB_UNKNOWN;
518 int tmpCmd = JOB_UNKNOWN;
521 if(!schedruntime.isValid())
530 query.
prepare(
"SELECT status, id, cmds FROM jobqueue "
531 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
532 "AND type = :JOBTYPE;");
534 query.
bindValue(
":STARTTIME", recstartts);
544 tmpStatus = query.
value(0).toInt();
546 tmpCmd = query.
value(2).toInt();
563 if (! (tmpStatus & JOB_DONE) && (tmpCmd &
JOB_STOP))
572 query.
prepare(
"INSERT INTO jobqueue (chanid, starttime, inserttime, type, "
573 "status, statustime, schedruntime, hostname, args, comment, "
575 "VALUES (:CHANID, :STARTTIME, now(), :JOBTYPE, :STATUS, "
576 "now(), :SCHEDRUNTIME, :HOST, :ARGS, :COMMENT, :FLAGS);");
579 query.
bindValue(
":STARTTIME", recstartts);
582 query.
bindValue(
":SCHEDRUNTIME", schedruntime);
598 const QString&
args,
const QString& comment,
const QString& host)
622 schedruntime = QDateTime(schedruntime.addDays(defer).date(),
623 QTime(0,0,0), Qt::UTC);
627 0, JOB_QUEUED, schedruntime);
647 query.
prepare(
"SELECT id FROM jobqueue "
648 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
649 "AND type = :JOBTYPE;");
651 query.
bindValue(
":STARTTIME", recstartts);
660 return query.
value(0).toInt();
665 int jobID,
int &jobType,
uint &chanid, QDateTime &recstartts)
669 query.
prepare(
"SELECT type, chanid, starttime FROM jobqueue "
681 jobType = query.
value(0).toInt();
682 chanid = query.
value(1).toUInt();
690 int jobID,
int &jobType,
uint &chanid, QString &recstartts)
692 QDateTime tmpStarttime;
695 jobID, jobType, chanid, tmpStarttime);
707 LOG(VB_GENERAL, LOG_ERR, QString(
"'%1' is an invalid Job Name.")
716 QString message = QString(
"GLOBAL_JOB PAUSE ID %1").arg(
jobID);
725 QString message = QString(
"GLOBAL_JOB RESUME ID %1").arg(
jobID);
734 QString message = QString(
"GLOBAL_JOB RESTART ID %1").arg(
jobID);
743 QString message = QString(
"GLOBAL_JOB STOP ID %1").arg(
jobID);
755 query.
prepare(
"UPDATE jobqueue SET status = :CANCELLED "
756 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
757 "AND status = :QUEUED;");
759 query.
bindValue(
":CANCELLED", JOB_CANCELLED);
761 query.
bindValue(
":STARTTIME", recstartts);
767 query.
prepare(
"UPDATE jobqueue SET cmds = :CMD "
768 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
769 "AND status <> :CANCELLED;");
772 query.
bindValue(
":STARTTIME", recstartts);
773 query.
bindValue(
":CANCELLED", JOB_CANCELLED);
782 bool jobsAreRunning =
true;
783 std::chrono::seconds totalSlept = 0s;
784 std::chrono::seconds maxSleep = 90s;
785 while (jobsAreRunning && totalSlept < maxSleep)
788 query.
prepare(
"SELECT id FROM jobqueue "
789 "WHERE chanid = :CHANID and starttime = :STARTTIME "
791 "(:FINISHED,:ABORTED,:ERRORED,:CANCELLED);");
793 query.
bindValue(
":STARTTIME", recstartts);
794 query.
bindValue(
":FINISHED", JOB_FINISHED);
795 query.
bindValue(
":ABORTED", JOB_ABORTED);
796 query.
bindValue(
":ERRORED", JOB_ERRORED);
797 query.
bindValue(
":CANCELLED", JOB_CANCELLED);
805 if (query.
size() == 0)
807 jobsAreRunning =
false;
810 if ((totalSlept % 5s) == 0s)
812 message = QString(
"Waiting on %1 jobs still running for "
813 "chanid %2 @ %3").arg(query.
size())
814 .arg(chanid).arg(recstartts.toString(
Qt::ISODate));
815 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + message);
822 if (totalSlept <= maxSleep)
824 query.
prepare(
"DELETE FROM jobqueue "
825 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
827 query.
bindValue(
":STARTTIME", recstartts);
834 query.
prepare(
"SELECT id, type, status, comment FROM jobqueue "
835 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
836 "AND status <> :CANCELLED ORDER BY id;");
839 query.
bindValue(
":STARTTIME", recstartts);
840 query.
bindValue(
":CANCELLED", JOB_CANCELLED);
845 "to query list of Jobs left in Queue.", query);
849 LOG(VB_GENERAL, LOG_ERR,
LOC +
850 QString(
"In DeleteAllJobs: There are Jobs "
851 "left in the JobQueue that are still running for "
852 "chanid %1 @ %2.").arg(chanid)
857 LOG(VB_GENERAL, LOG_ERR,
LOC +
858 QString(
"Job ID %1: '%2' with status '%3' and comment '%4'")
859 .arg(query.
value(0).toString(),
862 query.
value(3).toString()));
877 const QDateTime& recstartts)
885 int thisJob =
GetJobID(jobType, chanid, recstartts);
888 if( thisJob !=
jobID)
890 msg = QString(
"JobType, chanid and starttime don't match jobID %1");
897 msg = QString(
"Can't remove running JobID %1");
905 query.
prepare(
"DELETE FROM jobqueue WHERE id = :ID;");
925 query.
prepare(
"UPDATE jobqueue SET cmds = :CMDS WHERE id = :ID;");
940 const QDateTime &recstartts,
int newCmds)
944 query.
prepare(
"UPDATE jobqueue SET cmds = :CMDS WHERE type = :TYPE "
945 "AND chanid = :CHANID AND starttime = :STARTTIME;");
950 query.
bindValue(
":STARTTIME", recstartts);
968 query.
prepare(
"UPDATE jobqueue SET flags = :FLAGS WHERE id = :ID;");
987 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + QString(
"ChangeJobStatus(%1, %2, '%3')")
992 query.
prepare(
"UPDATE jobqueue SET status = :STATUS, comment = :COMMENT "
993 "WHERE id = :ID AND status <> :NEWSTATUS;");
998 query.
bindValue(
":NEWSTATUS", newStatus);
1014 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + QString(
"ChangeJobComment(%1, '%2')")
1015 .arg(
jobID).arg(comment));
1019 query.
prepare(
"UPDATE jobqueue SET comment = :COMMENT "
1041 query.
prepare(
"UPDATE jobqueue SET args = :ARGS "
1061 if ((jInfo.pginfo->GetChanID() == chanid) &&
1062 (jInfo.pginfo->GetRecordingStartTime() == recstartts))
1076 return (status == JOB_QUEUED);
1081 return ((status != JOB_UNKNOWN) && (status != JOB_QUEUED) &&
1082 ((status & JOB_DONE) == 0));
1086 uint chanid,
const QDateTime &recstartts)
1098 int jobType,
uint chanid,
const QDateTime &recstartts)
1100 int tmpStatus =
GetJobStatus(jobType, chanid, recstartts);
1102 return (tmpStatus != JOB_UNKNOWN) && ((tmpStatus & JOB_DONE) == 0);
1106 int jobType,
uint chanid,
const QDateTime &recstartts)
1122 QString settingName =
1127 return tr(
"Unknown Job");
1131 #define JOBSTATUS_STATUSTEXT(A,B,C) case A: return C;
1140 return tr(
"Undefined");
1145 QString queueStartTimeStr;
1146 QString queueEndTimeStr;
1147 QTime queueStartTime;
1149 QTime curTime = QTime::currentTime();
1150 bool inTimeWindow =
false;
1151 orStartsWithinMins = orStartsWithinMins < 0min ? 0min : orStartsWithinMins;
1157 if (!queueStartTime.isValid())
1159 LOG(VB_GENERAL, LOG_ERR,
1160 QString(
"Invalid JobQueueWindowStart time '%1', using 00:00")
1161 .arg(queueStartTimeStr));
1162 queueStartTime = QTime(0, 0);
1166 if (!queueEndTime.isValid())
1168 LOG(VB_GENERAL, LOG_ERR,
1169 QString(
"Invalid JobQueueWindowEnd time '%1', using 23:59")
1170 .arg(queueEndTimeStr));
1171 queueEndTime = QTime(23, 59);
1174 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1175 QString(
"Currently set to run new jobs from %1 to %2")
1176 .arg(queueStartTimeStr, queueEndTimeStr));
1178 if ((queueStartTime <= curTime) && (curTime < queueEndTime))
1180 inTimeWindow =
true;
1182 else if ((queueStartTime > queueEndTime) &&
1183 ((curTime < queueEndTime) || (queueStartTime <= curTime)))
1185 inTimeWindow =
true;
1187 else if (orStartsWithinMins > 0min)
1190 if (curTime <= queueStartTime)
1193 if (queueStartTime.secsTo(curTime) <= duration_cast<std::chrono::seconds>(orStartsWithinMins).count())
1195 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1196 QString(
"Job run window will start within %1 minutes")
1197 .arg(orStartsWithinMins.count()));
1198 inTimeWindow =
true;
1205 QDateTime startDateTime = QDateTime(
1206 curDateTime.date(), queueStartTime, Qt::UTC).addDays(1);
1208 if (curDateTime.secsTo(startDateTime) <= duration_cast<std::chrono::seconds>(orStartsWithinMins).count())
1210 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1211 QString(
"Job run window will start "
1212 "within %1 minutes (tomorrow)")
1213 .arg(orStartsWithinMins.count()));
1214 inTimeWindow =
true;
1219 return inTimeWindow;
1226 QMap<int, JobQueueEntry> jobs;
1227 QMap<int, JobQueueEntry>::Iterator it;
1229 bool checkForQueuedJobs = (startingWithinMins <= 0min
1232 if (checkForQueuedJobs && startingWithinMins > 0min) {
1233 maxSchedRunTime = maxSchedRunTime.addSecs(duration_cast<std::chrono::seconds>(startingWithinMins).count());
1234 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1235 QString(
"HasRunningOrPendingJobs: checking for jobs "
1236 "starting before: %1")
1242 if (!jobs.empty()) {
1243 for (it = jobs.begin(); it != jobs.end(); ++it)
1245 int tmpStatus = (*it).status;
1246 if (tmpStatus == JOB_RUNNING) {
1247 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1248 QString(
"HasRunningOrPendingJobs: found running job"));
1252 if (checkForQueuedJobs) {
1253 if ((tmpStatus != JOB_UNKNOWN) && (!(tmpStatus & JOB_DONE))) {
1254 if (startingWithinMins <= 0min) {
1255 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1256 "HasRunningOrPendingJobs: found pending job");
1259 if ((*it).schedruntime <= maxSchedRunTime) {
1260 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1261 QString(
"HasRunningOrPendingJobs: found pending "
1262 "job scheduled to start at: %1")
1281 bool commflagWhileRecording =
1286 query.
prepare(
"SELECT j.id, j.chanid, j.starttime, j.inserttime, j.type, "
1287 "j.cmds, j.flags, j.status, j.statustime, j.hostname, "
1288 "j.args, j.comment, r.endtime, j.schedruntime "
1290 "LEFT JOIN recorded r "
1291 " ON j.chanid = r.chanid AND j.starttime = r.starttime "
1292 "ORDER BY j.schedruntime, j.id;");
1297 "query list of Jobs in Queue.", query);
1301 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1302 QString(
"GetJobsInQueue: findJobs search bitmask %1, "
1303 "found %2 total jobs")
1304 .arg(findJobs).arg(query.
size()));
1306 while (query.
next())
1308 bool wantThisJob =
false;
1310 thisJob.
id = query.
value(0).toInt();
1320 if (query.
value(1).toInt() == -1)
1323 logInfo = QString(
"jobID #%1").arg(thisJob.
id);
1328 logInfo = QString(
"chanid %1 @ %2").arg(thisJob.
chanid)
1333 ((!commflagWhileRecording) ||
1337 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1338 QString(
"GetJobsInQueue: Ignoring '%1' Job "
1339 "for %2 in %3 state. Endtime in future.")
1347 (thisJob.
status & JOB_DONE)) ||
1349 (!(thisJob.
status & JOB_DONE))) ||
1351 (thisJob.
status == JOB_ERRORED)) ||
1358 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1359 QString(
"GetJobsInQueue: Ignore '%1' Job for %2 in %3 state.")
1365 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1366 QString(
"GetJobsInQueue: Found '%1' Job for %2 in %3 state.")
1374 thisJob.
args = query.
value(10).toString();
1381 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1382 QString(
"GetJobsInQueue: Unknown Job Type: %1")
1383 .arg(thisJob.
type));
1387 jobs[jobCount++] = thisJob;
1397 if (!newHostname.isEmpty())
1399 query.
prepare(
"UPDATE jobqueue SET hostname = :NEWHOSTNAME "
1400 "WHERE hostname = :EMPTY AND id = :ID;");
1401 query.
bindValue(
":NEWHOSTNAME", newHostname);
1407 query.
prepare(
"UPDATE jobqueue SET hostname = :EMPTY "
1416 "Unable to set hostname to '%1' for "
1417 "job %2.").arg(newHostname).arg(
jobID),
1427 QString allowSetting;
1448 case JOB_PREVIEW: allowSetting =
"JobAllowPreview";
1450 default:
return false;
1461 query.
prepare(
"SELECT cmds FROM jobqueue WHERE id = :ID;");
1482 query.
prepare(
"SELECT args FROM jobqueue WHERE id = :ID;");
1489 return query.
value(0).toString();
1503 query.
prepare(
"SELECT flags FROM jobqueue WHERE id = :ID;");
1524 query.
prepare(
"SELECT status FROM jobqueue WHERE id = :ID;");
1541 int jobType,
uint chanid,
const QDateTime &recstartts)
1545 query.
prepare(
"SELECT status FROM jobqueue WHERE type = :TYPE "
1546 "AND chanid = :CHANID AND starttime = :STARTTIME;");
1550 query.
bindValue(
":STARTTIME", recstartts);
1566 QMap<int, JobQueueEntry> jobs;
1570 msg = QString(
"RecoverQueue: Checking for unfinished jobs to "
1572 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + msg);
1578 QMap<int, JobQueueEntry>::Iterator it;
1582 for (it = jobs.begin(); it != jobs.end(); ++it)
1584 int tmpCmds = (*it).cmds;
1585 int tmpStatus = (*it).status;
1588 logInfo = QString(
"jobID #%1").arg((*it).id);
1590 logInfo = QString(
"chanid %1 @ %2").arg((*it).chanid)
1591 .arg((*it).startts);
1593 if (((tmpStatus == JOB_STARTING) ||
1594 (tmpStatus == JOB_RUNNING) ||
1595 (tmpStatus == JOB_PAUSED) ||
1597 (tmpStatus == JOB_STOPPING)) &&
1600 ((*it).statustime < oldDate)))
1602 msg = QString(
"RecoverQueue: Recovering '%1' for %2 "
1606 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + msg);
1616 msg = QString(
"RecoverQueue: Ignoring '%1' for %2 "
1620 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + msg);
1633 delquery.
prepare(
"DELETE FROM jobqueue "
1634 "WHERE (status in (:FINISHED, :ABORTED, :CANCELLED) "
1635 "AND statustime < :DONEPURGEDATE) "
1636 "OR (status in (:ERRORED) "
1637 "AND statustime < :ERRORSPURGEDATE) ");
1638 delquery.
bindValue(
":FINISHED", JOB_FINISHED);
1639 delquery.
bindValue(
":ABORTED", JOB_ABORTED);
1640 delquery.
bindValue(
":CANCELLED", JOB_CANCELLED);
1641 delquery.
bindValue(
":ERRORED", JOB_ERRORED);
1642 delquery.
bindValue(
":DONEPURGEDATE", donePurgeDate);
1643 delquery.
bindValue(
":ERRORSPURGEDATE", errorsPurgeDate);
1645 if (!delquery.
exec())
1648 "old finished jobs.", delquery);
1654 if (!jobstarttsRaw.isValid())
1656 jobstarttsRaw = QDateTime::currentDateTime();
1657 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + QString(
"Invalid date/time passed, "
1659 jobstarttsRaw.toString()));
1665 "JobQueueWindowStart",
hostname,
"00:00")));
1668 "JobQueueWindowEnd",
hostname,
"23:59")));
1672 if (scheduleTime < windowStart || scheduleTime > windowEnd)
1674 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
"Time not within job queue window, " +
1688 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
1689 "ProcessJob(): Unable to open database connection");
1702 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
1703 QString(
"Unable to retrieve program info for chanid %1 @ %2")
1708 tr(
"Unable to retrieve program info from database"));
1738 tr(
"Program has been deleted"));
1763 tr(
"UNKNOWN JobType, unable to process!"));
1776 pthread_t childThread = 0;
1777 pthread_attr_t attr;
1778 pthread_attr_init(&attr);
1779 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1780 pthread_create(&childThread, &attr, ChildThreadRoutine, jts);
1781 pthread_attr_destroy(&attr);
1789 return "Commercial Detection";
1791 return "Unknown Job";
1793 QString descSetting =
1807 if (command.trimmed().isEmpty())
1808 command =
"mythtranscode";
1810 if (command ==
"mythtranscode")
1816 if (command.trimmed().isEmpty())
1817 command =
"mythcommflag";
1819 if (command ==
"mythcommflag")
1828 if (!command.isEmpty())
1830 command.replace(
"%JOBID%", QString(
"%1").arg(
id));
1833 if (!command.isEmpty() && tmpInfo)
1837 command.replace(
"%VERBOSELEVEL%", QString(
"%1").arg(
verboseMask));
1841 command.replace(
"%TRANSPROFILE%",
1843 "autodetect" : QString::number(transcoder));
1873 const char *m_suffix;
1877 static constexpr std::array<const PpTab_t,9> kPpTab {{
1878 {
"bytes", 9999, 0 },
1888 float fbytes =
bytes;
1890 unsigned int ii = 0;
1891 while (kPpTab[ii].m_max && fbytes > kPpTab[ii].m_max) {
1896 return QString(
"%1 %2")
1897 .arg(fbytes, 0,
'f', kPpTab[ii].m_precision)
1898 .arg(kPpTab[ii].m_suffix);
1921 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
1922 "The JobQueue cannot currently transcode files that do not "
1923 "have a chanid/starttime in the recorded table.");
1938 bool useCutlist = program_info->
HasCutlist() &&
1942 QString profilearg =
1944 "autodetect" : QString::number(transcoder);
1953 command = QString(
"%1 -j %2 --profile %3")
1954 .arg(path).arg(
jobID).arg(profilearg);
1956 command +=
" --honorcutlist";
1963 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
1964 QStringList tokens = command.split(
" ", QString::SkipEmptyParts);
1966 QStringList tokens = command.split(
" ", Qt::SkipEmptyParts);
1968 if (!tokens.empty())
1979 QString transcoderName;
1982 transcoderName =
"Autodetect";
1987 query.
prepare(
"SELECT name FROM recordingprofiles WHERE id = :ID;");
1991 transcoderName = query.
value(0).toString();
1996 transcoderName = QString(
"Autodetect(%1)").arg(transcoder);
2011 long long filesize = 0;
2012 long long origfilesize = QFileInfo(
filename).size();
2014 QString msg = QString(
"Transcode %1")
2017 QString details = QString(
"%1: %2 (%3)")
2021 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"%1 for %2")
2022 .arg(msg, details));
2024 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + QString(
"Running command: '%1'")
2027 GetMythDB()->GetDBManager()->CloseDatabases();
2035 tr(
"ERROR: Unable to find mythtranscode, check backend logs."));
2039 details = QString(
"%1: %2 does not exist or is not executable")
2042 LOG(VB_GENERAL, LOG_ERR,
LOC +
2043 QString(
"%1 for %2").arg(msg, details));
2047 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
"Transcode command restarting");
2055 if (status == JOB_FINISHED)
2066 filesize = st.size();
2069 QString comment = tr(
"%1: %2 => %3")
2070 .arg(transcoderName,
2078 details = QString(
"%1: %2 (%3)")
2087 QString(
"could not stat '%1'").arg(
filename);
2091 details = QString(
"%1: %2")
2103 QString comment = tr(
"exit status %1, job status was \"%2\"")
2109 details = QString(
"%1: %2 (%3)")
2117 LOG(VB_GENERAL, LOG_INFO,
LOC + msg +
": " + details);
2121 if (retrylimit == 0)
2123 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
"Retry limit exceeded for transcoder, "
2124 "setting job status to errored.");
2151 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
2152 "The JobQueue cannot currently perform lookups for items which do "
2153 "not have a chanid/starttime in the recorded table.");
2163 QString details = QString(
"%1 recorded from channel %3")
2169 QString msg = QString(
"Metadata Lookup failed. Could not open "
2170 "new database connection for %1. "
2171 "Program cannot be looked up.")
2173 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2176 tr(
"Could not open new database connection for "
2177 "metadata lookup."));
2179 delete program_info;
2183 LOG(VB_GENERAL, LOG_INFO,
2184 LOC +
"Metadata Lookup Starting for " + details);
2191 command = QString(
"%1 -j %2")
2192 .arg(path).arg(
jobID);
2195 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + QString(
"Running command: '%1'")
2198 GetMythDB()->GetDBManager()->CloseDatabases();
2200 int priority = LOG_NOTICE;
2208 comment = tr(
"Unable to find mythmetadatalookup");
2210 priority = LOG_WARNING;
2214 comment = tr(
"Aborted by user");
2216 priority = LOG_WARNING;
2220 comment = tr(
"Unable to open file or init decoder");
2222 priority = LOG_WARNING;
2226 comment = tr(
"Failed with exit status %1").arg(retVal);
2228 priority = LOG_WARNING;
2232 comment = tr(
"Metadata Lookup Complete.");
2238 QString msg = tr(
"Metadata Lookup %1",
"Job ID")
2241 if (!comment.isEmpty())
2242 details += QString(
" (%1)").arg(comment);
2244 if (priority <= LOG_WARNING)
2245 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
": " + details);
2271 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
2272 "The JobQueue cannot currently commflag files that do not "
2273 "have a chanid/starttime in the recorded table.");
2283 QString details = QString(
"%1 recorded from channel %3")
2289 QString msg = QString(
"Commercial Detection failed. Could not open "
2290 "new database connection for %1. "
2291 "Program cannot be flagged.")
2293 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2296 tr(
"Could not open new database connection for "
2297 "commercial detector."));
2299 delete program_info;
2303 LOG(VB_GENERAL, LOG_INFO,
2304 LOC +
"Commercial Detection Starting for " + details);
2306 uint breaksFound = 0;
2314 command = QString(
"%1 -j %2 --noprogress")
2315 .arg(path).arg(
jobID);
2321 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
2322 QStringList tokens = command.split(
" ", QString::SkipEmptyParts);
2324 QStringList tokens = command.split(
" ", Qt::SkipEmptyParts);
2326 if (!tokens.empty())
2331 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + QString(
"Running command: '%1'")
2334 GetMythDB()->GetDBManager()->CloseDatabases();
2336 int priority = LOG_NOTICE;
2344 comment = tr(
"Unable to find mythcommflag");
2346 priority = LOG_WARNING;
2350 comment = tr(
"Aborted by user");
2352 priority = LOG_WARNING;
2356 comment = tr(
"Unable to open file or init decoder");
2358 priority = LOG_WARNING;
2362 comment = tr(
"Failed with exit status %1").arg(breaksFound);
2364 priority = LOG_WARNING;
2368 comment = tr(
"%n commercial break(s)",
"", breaksFound);
2384 QString msg = tr(
"Commercial Detection %1",
"Job ID")
2387 if (!comment.isEmpty())
2388 details += QString(
" (%1)").arg(comment);
2390 if (priority <= LOG_WARNING)
2391 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
": " + details);
2425 msg = QString(
"Started %1 for %2 recorded from channel %3")
2431 msg = QString(
"Started %1 for jobID %2").arg(jobDesc).arg(
jobID);
2433 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(msg.toLocal8Bit().constData()));
2447 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + QString(
"Running command: '%1'")
2449 GetMythDB()->GetDBManager()->CloseDatabases();
2455 msg = QString(
"User Job '%1' failed, unable to find "
2456 "executable, check your PATH and backend logs.")
2458 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2459 LOG(VB_GENERAL, LOG_NOTICE,
LOC + QString(
"Current PATH: '%1'")
2460 .arg(qEnvironmentVariable(
"PATH")));
2463 tr(
"ERROR: Unable to find executable, check backend logs."));
2465 else if (result != 0)
2467 msg = QString(
"User Job '%1' failed.").arg(command);
2468 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2471 tr(
"ERROR: User Job returned non-zero, check logs."));
2477 msg = QString(
"Finished %1 for %2 recorded from channel %3")
2483 msg = QString(
"Finished %1 for jobID %2").arg(jobDesc).arg(
jobID);
2485 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(msg.toLocal8Bit().constData()));
2502 while ((x != 0) && ((x & 0x01) == 0))