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)
1118 case JOB_PREVIEW:
return tr(
"Preview Generation");
1123 QString settingName =
1128 return tr(
"Unknown Job");
1132 #define JOBSTATUS_STATUSTEXT(A,B,C) case A: return C;
1141 return tr(
"Undefined");
1146 QString queueStartTimeStr;
1147 QString queueEndTimeStr;
1148 QTime queueStartTime;
1150 QTime curTime = QTime::currentTime();
1151 bool inTimeWindow =
false;
1152 orStartsWithinMins = orStartsWithinMins < 0min ? 0min : orStartsWithinMins;
1158 if (!queueStartTime.isValid())
1160 LOG(VB_GENERAL, LOG_ERR,
1161 QString(
"Invalid JobQueueWindowStart time '%1', using 00:00")
1162 .arg(queueStartTimeStr));
1163 queueStartTime = QTime(0, 0);
1167 if (!queueEndTime.isValid())
1169 LOG(VB_GENERAL, LOG_ERR,
1170 QString(
"Invalid JobQueueWindowEnd time '%1', using 23:59")
1171 .arg(queueEndTimeStr));
1172 queueEndTime = QTime(23, 59);
1175 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1176 QString(
"Currently set to run new jobs from %1 to %2")
1177 .arg(queueStartTimeStr, queueEndTimeStr));
1179 if ((queueStartTime <= curTime) && (curTime < queueEndTime))
1181 inTimeWindow =
true;
1183 else if ((queueStartTime > queueEndTime) &&
1184 ((curTime < queueEndTime) || (queueStartTime <= curTime)))
1186 inTimeWindow =
true;
1188 else if (orStartsWithinMins > 0min)
1191 if (curTime <= queueStartTime)
1194 if (queueStartTime.secsTo(curTime) <= duration_cast<std::chrono::seconds>(orStartsWithinMins).count())
1196 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1197 QString(
"Job run window will start within %1 minutes")
1198 .arg(orStartsWithinMins.count()));
1199 inTimeWindow =
true;
1206 QDateTime startDateTime = QDateTime(
1207 curDateTime.date(), queueStartTime, Qt::UTC).addDays(1);
1209 if (curDateTime.secsTo(startDateTime) <= duration_cast<std::chrono::seconds>(orStartsWithinMins).count())
1211 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1212 QString(
"Job run window will start "
1213 "within %1 minutes (tomorrow)")
1214 .arg(orStartsWithinMins.count()));
1215 inTimeWindow =
true;
1220 return inTimeWindow;
1227 QMap<int, JobQueueEntry> jobs;
1228 QMap<int, JobQueueEntry>::Iterator it;
1230 bool checkForQueuedJobs = (startingWithinMins <= 0min
1233 if (checkForQueuedJobs && startingWithinMins > 0min) {
1234 maxSchedRunTime = maxSchedRunTime.addSecs(duration_cast<std::chrono::seconds>(startingWithinMins).count());
1235 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1236 QString(
"HasRunningOrPendingJobs: checking for jobs "
1237 "starting before: %1")
1243 if (!jobs.empty()) {
1244 for (it = jobs.begin(); it != jobs.end(); ++it)
1246 int tmpStatus = (*it).status;
1247 if (tmpStatus == JOB_RUNNING) {
1248 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1249 QString(
"HasRunningOrPendingJobs: found running job"));
1253 if (checkForQueuedJobs) {
1254 if ((tmpStatus != JOB_UNKNOWN) && (!(tmpStatus & JOB_DONE))) {
1255 if (startingWithinMins <= 0min) {
1256 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1257 "HasRunningOrPendingJobs: found pending job");
1260 if ((*it).schedruntime <= maxSchedRunTime) {
1261 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1262 QString(
"HasRunningOrPendingJobs: found pending "
1263 "job scheduled to start at: %1")
1282 bool commflagWhileRecording =
1287 query.
prepare(
"SELECT j.id, j.chanid, j.starttime, j.inserttime, j.type, "
1288 "j.cmds, j.flags, j.status, j.statustime, j.hostname, "
1289 "j.args, j.comment, r.endtime, j.schedruntime "
1291 "LEFT JOIN recorded r "
1292 " ON j.chanid = r.chanid AND j.starttime = r.starttime "
1293 "ORDER BY j.schedruntime, j.id;");
1298 "query list of Jobs in Queue.", query);
1302 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1303 QString(
"GetJobsInQueue: findJobs search bitmask %1, "
1304 "found %2 total jobs")
1305 .arg(findJobs).arg(query.
size()));
1307 while (query.
next())
1309 bool wantThisJob =
false;
1311 thisJob.
id = query.
value(0).toInt();
1321 if (query.
value(1).toInt() == -1)
1324 logInfo = QString(
"jobID #%1").arg(thisJob.
id);
1329 logInfo = QString(
"chanid %1 @ %2").arg(thisJob.
chanid)
1334 ((!commflagWhileRecording) ||
1338 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1339 QString(
"GetJobsInQueue: Ignoring '%1' Job "
1340 "for %2 in %3 state. Endtime in future.")
1348 (thisJob.
status & JOB_DONE)) ||
1350 (!(thisJob.
status & JOB_DONE))) ||
1352 (thisJob.
status == JOB_ERRORED)) ||
1359 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1360 QString(
"GetJobsInQueue: Ignore '%1' Job for %2 in %3 state.")
1366 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1367 QString(
"GetJobsInQueue: Found '%1' Job for %2 in %3 state.")
1375 thisJob.
args = query.
value(10).toString();
1382 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
1383 QString(
"GetJobsInQueue: Unknown Job Type: %1")
1384 .arg(thisJob.
type));
1388 jobs[jobCount++] = thisJob;
1398 if (!newHostname.isEmpty())
1400 query.
prepare(
"UPDATE jobqueue SET hostname = :NEWHOSTNAME "
1401 "WHERE hostname = :EMPTY AND id = :ID;");
1402 query.
bindValue(
":NEWHOSTNAME", newHostname);
1408 query.
prepare(
"UPDATE jobqueue SET hostname = :EMPTY "
1417 "Unable to set hostname to '%1' for "
1418 "job %2.").arg(newHostname).arg(
jobID),
1428 QString allowSetting;
1449 case JOB_PREVIEW: allowSetting =
"JobAllowPreview";
1451 default:
return false;
1462 query.
prepare(
"SELECT cmds FROM jobqueue WHERE id = :ID;");
1483 query.
prepare(
"SELECT args FROM jobqueue WHERE id = :ID;");
1490 return query.
value(0).toString();
1504 query.
prepare(
"SELECT flags FROM jobqueue WHERE id = :ID;");
1525 query.
prepare(
"SELECT status FROM jobqueue WHERE id = :ID;");
1542 int jobType,
uint chanid,
const QDateTime &recstartts)
1546 query.
prepare(
"SELECT status FROM jobqueue WHERE type = :TYPE "
1547 "AND chanid = :CHANID AND starttime = :STARTTIME;");
1551 query.
bindValue(
":STARTTIME", recstartts);
1567 QMap<int, JobQueueEntry> jobs;
1571 msg = QString(
"RecoverQueue: Checking for unfinished jobs to "
1573 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + msg);
1579 QMap<int, JobQueueEntry>::Iterator it;
1583 for (it = jobs.begin(); it != jobs.end(); ++it)
1585 int tmpCmds = (*it).cmds;
1586 int tmpStatus = (*it).status;
1589 logInfo = QString(
"jobID #%1").arg((*it).id);
1591 logInfo = QString(
"chanid %1 @ %2").arg((*it).chanid)
1592 .arg((*it).startts);
1594 if (((tmpStatus == JOB_STARTING) ||
1595 (tmpStatus == JOB_RUNNING) ||
1596 (tmpStatus == JOB_PAUSED) ||
1598 (tmpStatus == JOB_STOPPING)) &&
1601 ((*it).statustime < oldDate)))
1603 msg = QString(
"RecoverQueue: Recovering '%1' for %2 "
1607 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + msg);
1617 msg = QString(
"RecoverQueue: Ignoring '%1' for %2 "
1621 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + msg);
1634 delquery.
prepare(
"DELETE FROM jobqueue "
1635 "WHERE (status in (:FINISHED, :ABORTED, :CANCELLED) "
1636 "AND statustime < :DONEPURGEDATE) "
1637 "OR (status in (:ERRORED) "
1638 "AND statustime < :ERRORSPURGEDATE) ");
1639 delquery.
bindValue(
":FINISHED", JOB_FINISHED);
1640 delquery.
bindValue(
":ABORTED", JOB_ABORTED);
1641 delquery.
bindValue(
":CANCELLED", JOB_CANCELLED);
1642 delquery.
bindValue(
":ERRORED", JOB_ERRORED);
1643 delquery.
bindValue(
":DONEPURGEDATE", donePurgeDate);
1644 delquery.
bindValue(
":ERRORSPURGEDATE", errorsPurgeDate);
1646 if (!delquery.
exec())
1649 "old finished jobs.", delquery);
1655 if (!jobstarttsRaw.isValid())
1657 jobstarttsRaw = QDateTime::currentDateTime();
1658 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + QString(
"Invalid date/time passed, "
1660 jobstarttsRaw.toString()));
1666 "JobQueueWindowStart",
hostname,
"00:00")));
1669 "JobQueueWindowEnd",
hostname,
"23:59")));
1673 if (scheduleTime < windowStart || scheduleTime > windowEnd)
1675 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
"Time not within job queue window, " +
1689 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
1690 "ProcessJob(): Unable to open database connection");
1703 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
1704 QString(
"Unable to retrieve program info for chanid %1 @ %2")
1709 tr(
"Unable to retrieve program info from database"));
1739 tr(
"Program has been deleted"));
1764 tr(
"UNKNOWN JobType, unable to process!"));
1777 pthread_t childThread = 0;
1778 pthread_attr_t attr;
1779 pthread_attr_init(&attr);
1780 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1781 pthread_create(&childThread, &attr, ChildThreadRoutine, jts);
1782 pthread_attr_destroy(&attr);
1790 return "Commercial Detection";
1792 return "Unknown Job";
1794 QString descSetting =
1808 if (command.trimmed().isEmpty())
1809 command =
"mythtranscode";
1811 if (command ==
"mythtranscode")
1817 if (command.trimmed().isEmpty())
1818 command =
"mythcommflag";
1820 if (command ==
"mythcommflag")
1829 if (!command.isEmpty())
1831 command.replace(
"%JOBID%", QString(
"%1").arg(
id));
1834 if (!command.isEmpty() && tmpInfo)
1838 command.replace(
"%VERBOSELEVEL%", QString(
"%1").arg(
verboseMask));
1842 command.replace(
"%TRANSPROFILE%",
1844 "autodetect" : QString::number(transcoder));
1874 const char *m_suffix;
1878 static constexpr std::array<const PpTab_t,9> kPpTab {{
1879 {
"bytes", 9999, 0 },
1889 float fbytes =
bytes;
1891 unsigned int ii = 0;
1892 while (kPpTab[ii].m_max && fbytes > kPpTab[ii].m_max) {
1897 return QString(
"%1 %2")
1898 .arg(fbytes, 0,
'f', kPpTab[ii].m_precision)
1899 .arg(kPpTab[ii].m_suffix);
1922 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
1923 "The JobQueue cannot currently transcode files that do not "
1924 "have a chanid/starttime in the recorded table.");
1939 bool useCutlist = program_info->
HasCutlist() &&
1943 QString profilearg =
1945 "autodetect" : QString::number(transcoder);
1954 command = QString(
"%1 -j %2 --profile %3")
1955 .arg(path).arg(
jobID).arg(profilearg);
1957 command +=
" --honorcutlist";
1964 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
1965 QStringList tokens = command.split(
" ", QString::SkipEmptyParts);
1967 QStringList tokens = command.split(
" ", Qt::SkipEmptyParts);
1969 if (!tokens.empty())
1980 QString transcoderName;
1983 transcoderName =
"Autodetect";
1988 query.
prepare(
"SELECT name FROM recordingprofiles WHERE id = :ID;");
1992 transcoderName = query.
value(0).toString();
1997 transcoderName = QString(
"Autodetect(%1)").arg(transcoder);
2012 long long filesize = 0;
2013 long long origfilesize = QFileInfo(
filename).size();
2015 QString msg = QString(
"Transcode %1")
2018 QString details = QString(
"%1: %2 (%3)")
2022 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"%1 for %2")
2023 .arg(msg, details));
2025 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + QString(
"Running command: '%1'")
2028 GetMythDB()->GetDBManager()->CloseDatabases();
2036 tr(
"ERROR: Unable to find mythtranscode, check backend logs."));
2040 details = QString(
"%1: %2 does not exist or is not executable")
2043 LOG(VB_GENERAL, LOG_ERR,
LOC +
2044 QString(
"%1 for %2").arg(msg, details));
2048 LOG(VB_JOBQUEUE, LOG_INFO,
LOC +
"Transcode command restarting");
2056 if (status == JOB_FINISHED)
2067 filesize = st.size();
2070 QString comment = tr(
"%1: %2 => %3")
2071 .arg(transcoderName,
2079 details = QString(
"%1: %2 (%3)")
2088 QString(
"could not stat '%1'").arg(
filename);
2092 details = QString(
"%1: %2")
2104 QString comment = tr(
"exit status %1, job status was \"%2\"")
2110 details = QString(
"%1: %2 (%3)")
2118 LOG(VB_GENERAL, LOG_INFO,
LOC + msg +
": " + details);
2122 if (retrylimit == 0)
2124 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
"Retry limit exceeded for transcoder, "
2125 "setting job status to errored.");
2152 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
2153 "The JobQueue cannot currently perform lookups for items which do "
2154 "not have a chanid/starttime in the recorded table.");
2164 QString details = QString(
"%1 recorded from channel %3")
2170 QString msg = QString(
"Metadata Lookup failed. Could not open "
2171 "new database connection for %1. "
2172 "Program cannot be looked up.")
2174 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2177 tr(
"Could not open new database connection for "
2178 "metadata lookup."));
2180 delete program_info;
2184 LOG(VB_GENERAL, LOG_INFO,
2185 LOC +
"Metadata Lookup Starting for " + details);
2192 command = QString(
"%1 -j %2")
2193 .arg(path).arg(
jobID);
2196 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + QString(
"Running command: '%1'")
2199 GetMythDB()->GetDBManager()->CloseDatabases();
2201 int priority = LOG_NOTICE;
2209 comment = tr(
"Unable to find mythmetadatalookup");
2211 priority = LOG_WARNING;
2215 comment = tr(
"Aborted by user");
2217 priority = LOG_WARNING;
2221 comment = tr(
"Unable to open file or init decoder");
2223 priority = LOG_WARNING;
2227 comment = tr(
"Failed with exit status %1").arg(retVal);
2229 priority = LOG_WARNING;
2233 comment = tr(
"Metadata Lookup Complete.");
2239 QString msg = tr(
"Metadata Lookup %1",
"Job ID")
2242 if (!comment.isEmpty())
2243 details += QString(
" (%1)").arg(comment);
2245 if (priority <= LOG_WARNING)
2246 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
": " + details);
2272 LOG(VB_JOBQUEUE, LOG_ERR,
LOC +
2273 "The JobQueue cannot currently commflag files that do not "
2274 "have a chanid/starttime in the recorded table.");
2284 QString details = QString(
"%1 recorded from channel %3")
2290 QString msg = QString(
"Commercial Detection failed. Could not open "
2291 "new database connection for %1. "
2292 "Program cannot be flagged.")
2294 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2297 tr(
"Could not open new database connection for "
2298 "commercial detector."));
2300 delete program_info;
2304 LOG(VB_GENERAL, LOG_INFO,
2305 LOC +
"Commercial Detection Starting for " + details);
2307 uint breaksFound = 0;
2315 command = QString(
"%1 -j %2 --noprogress")
2316 .arg(path).arg(
jobID);
2322 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
2323 QStringList tokens = command.split(
" ", QString::SkipEmptyParts);
2325 QStringList tokens = command.split(
" ", Qt::SkipEmptyParts);
2327 if (!tokens.empty())
2332 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + QString(
"Running command: '%1'")
2335 GetMythDB()->GetDBManager()->CloseDatabases();
2337 int priority = LOG_NOTICE;
2345 comment = tr(
"Unable to find mythcommflag");
2347 priority = LOG_WARNING;
2351 comment = tr(
"Aborted by user");
2353 priority = LOG_WARNING;
2357 comment = tr(
"Unable to open file or init decoder");
2359 priority = LOG_WARNING;
2363 comment = tr(
"Failed with exit status %1").arg(breaksFound);
2365 priority = LOG_WARNING;
2369 comment = tr(
"%n commercial break(s)",
"", breaksFound);
2385 QString msg = tr(
"Commercial Detection %1",
"Job ID")
2388 if (!comment.isEmpty())
2389 details += QString(
" (%1)").arg(comment);
2391 if (priority <= LOG_WARNING)
2392 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
": " + details);
2426 msg = QString(
"Started %1 for %2 recorded from channel %3")
2432 msg = QString(
"Started %1 for jobID %2").arg(jobDesc).arg(
jobID);
2434 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(msg.toLocal8Bit().constData()));
2448 LOG(VB_JOBQUEUE, LOG_INFO,
LOC + QString(
"Running command: '%1'")
2450 GetMythDB()->GetDBManager()->CloseDatabases();
2456 msg = QString(
"User Job '%1' failed, unable to find "
2457 "executable, check your PATH and backend logs.")
2459 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2460 LOG(VB_GENERAL, LOG_NOTICE,
LOC + QString(
"Current PATH: '%1'")
2461 .arg(qEnvironmentVariable(
"PATH")));
2464 tr(
"ERROR: Unable to find executable, check backend logs."));
2466 else if (result != 0)
2468 msg = QString(
"User Job '%1' failed.").arg(command);
2469 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2472 tr(
"ERROR: User Job returned non-zero, check logs."));
2478 msg = QString(
"Finished %1 for %2 recorded from channel %3")
2484 msg = QString(
"Finished %1 for jobID %2").arg(jobDesc).arg(
jobID);
2486 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(msg.toLocal8Bit().constData()));
2503 while ((x != 0) && ((x & 0x01) == 0))