11 #else // if !__linux__ 12 # include <sys/param.h> 14 # include <sys/mount.h> 20 #include <sys/types.h> 22 #include <QStringList> 51 #define LOC QString("Scheduler: ") 52 #define LOC_WARN QString("Scheduler, Warning: ") 53 #define LOC_ERR QString("Scheduler, Error: ") 58 QString tmptable,
Scheduler *master_sched) :
60 recordTable(tmptable),
61 priorityTable(
"powerpriority"),
63 reclist_changed(
false),
64 specsched(master_sched),
65 schedulingEnabled(
true),
69 m_mainServer(nullptr),
71 m_isShuttingDown(
false),
73 livetvTime(QDateTime()),
74 lastPrepareTime(QDateTime()),
75 m_openEnd(openEndNever)
79 char *
debug = getenv(
"DEBUG_CONFLICTS");
88 if (tmptable ==
"powerpriority_tmp")
103 start(QThread::LowPriority);
169 if (!query.
exec(
"SELECT count(*) FROM capturecard") || !query.
next())
178 LOG(VB_GENERAL, LOG_ERR,
LOC +
179 "No capture cards are defined in the database.\n\t\t\t" 180 "Perhaps you should re-read the installation instructions?");
184 query.
prepare(
"SELECT sourceid,name FROM videosource ORDER BY sourceid;");
199 "WHERE sourceid = :SOURCEID " 203 if (!subquery.
exec())
207 else if (!subquery.
next())
209 LOG(VB_GENERAL, LOG_WARNING,
LOC +
210 QString(
"Listings source '%1' is defined, " 211 "but is not attached to a card input.")
212 .arg(query.
value(1).toString()));
222 LOG(VB_GENERAL, LOG_ERR,
LOC +
223 "No channel sources defined in the database");
272 return aprec < bprec;
287 int cmp = a->
GetTitle().compare(
b->GetTitle(), Qt::CaseInsensitive);
293 Qt::CaseInsensitive);
298 cmp = a->
GetChanNum().compare(
b->GetChanNum(), Qt::CaseInsensitive);
307 Qt::CaseInsensitive);
344 return atype > btype;
348 int bpast = (
b->GetRecordingStartTime() < pasttime && !
b->IsReactivated());
350 return apast < bpast;
400 return atype > btype;
404 int bpast = (
b->GetRecordingStartTime() < pasttime && !
b->IsReactivated());
406 return apast < bpast;
441 LOG(VB_SCHEDULE, LOG_INFO,
"BuildWorkList...");
446 LOG(VB_SCHEDULE, LOG_INFO,
"AddNewRecords...");
448 LOG(VB_SCHEDULE, LOG_INFO,
"AddNotListed...");
451 LOG(VB_SCHEDULE, LOG_INFO,
"Sort by time...");
453 LOG(VB_SCHEDULE, LOG_INFO,
"PruneOverlaps...");
456 LOG(VB_SCHEDULE, LOG_INFO,
"Sort by priority...");
458 LOG(VB_SCHEDULE, LOG_INFO,
"BuildListMaps...");
460 LOG(VB_SCHEDULE, LOG_INFO,
"SchedNewRecords...");
462 LOG(VB_SCHEDULE, LOG_INFO,
"SchedLiveTV...");
464 LOG(VB_SCHEDULE, LOG_INFO,
"ClearListMaps...");
469 LOG(VB_SCHEDULE, LOG_INFO,
"Sort by time...");
471 LOG(VB_SCHEDULE, LOG_INFO,
"PruneRedundants...");
474 LOG(VB_SCHEDULE, LOG_INFO,
"Sort by time...");
476 LOG(VB_SCHEDULE, LOG_INFO,
"ClearWorkList...");
488 struct timeval fillstart, fillend;
489 float matchTime, checkTime, placeTime;
497 where =
"WHERE recordid IS NULL ";
499 thequery = QString(
"CREATE TEMPORARY TABLE recordmatch ") +
500 "SELECT * FROM recordmatch " + where +
"; ";
504 bool ok = query.
exec();
512 thequery =
"ALTER TABLE recordmatch " 513 " ADD UNIQUE INDEX (recordid, chanid, starttime); ";
521 thequery =
"ALTER TABLE recordmatch " 522 " ADD INDEX (chanid, starttime, manualid); ";
532 gettimeofday(&fillstart,
nullptr);
534 gettimeofday(&fillend,
nullptr);
535 matchTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
536 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
538 LOG(VB_SCHEDULE, LOG_INFO,
"CreateTempTables...");
541 gettimeofday(&fillstart,
nullptr);
542 LOG(VB_SCHEDULE, LOG_INFO,
"UpdateDuplicates...");
544 gettimeofday(&fillend,
nullptr);
545 checkTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
546 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
548 gettimeofday(&fillstart,
nullptr);
550 gettimeofday(&fillend,
nullptr);
551 placeTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
552 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
554 LOG(VB_SCHEDULE, LOG_INFO,
"DeleteTempTables...");
558 queryDrop.
prepare(
"DROP TABLE recordmatch;");
559 if (!queryDrop.
exec())
566 msg.sprintf(
"Speculative scheduled %d items in %.1f " 567 "= %.2f match + %.2f check + %.2f place",
569 static_cast<double>(matchTime + checkTime + placeTime),
570 static_cast<double>(matchTime),
571 static_cast<double>(checkTime),
572 static_cast<double>(placeTime));
573 LOG(VB_GENERAL, LOG_INFO, msg);
585 for (; it != schedList.
end(); ++it)
596 LOG(VB_SCHEDULE, LOG_INFO,
"--- print list start ---");
597 LOG(VB_SCHEDULE, LOG_INFO,
"Title - Subtitle Ch Station " 598 "Day Start End G I T N Pri");
601 for ( ; i != list.end(); ++i)
605 if (onlyFutureRecordings &&
614 LOG(VB_SCHEDULE, LOG_INFO,
"--- print list end ---");
625 .leftJustified(34 -
prefix.length(),
' ',
true);
627 outstr += QString(
"%1 %2 %3 %4-%5 %6 %7 ")
634 .arg(QString::number(p->
GetInputID()).rightJustified(2,
' '));
635 outstr += QString(
"%1 %2 %3")
642 LOG(VB_SCHEDULE, LOG_INFO, outstr);
650 for (; dreciter !=
reclist.end(); ++dreciter)
672 LOG(VB_GENERAL, LOG_INFO,
673 QString(
"Updating status for %1 on cardid [%2] (%3 => %4)")
705 const QDateTime &startts,
707 const QDateTime &recendts)
712 for (; dreciter !=
reclist.end(); ++dreciter)
722 LOG(VB_GENERAL, LOG_INFO,
723 QString(
"Updating status for %1 on cardid [%2] (%3 => %4)")
789 LOG(VB_GENERAL, LOG_ERR,
790 QString(
"Failed to change end time on card %1 to %2")
801 for (; i !=
reclist.end(); ++i)
840 for (; it != slavelist.
end(); ++it)
846 for ( ; ri !=
reclist.end(); ++ri)
855 Qt::CaseInsensitive) == 0)
865 LOG(VB_GENERAL, LOG_INFO,
866 QString(
"setting %1/%2/\"%3\" as %4")
874 LOG(VB_GENERAL, LOG_NOTICE,
875 QString(
"%1/%2/\"%3\" is already recording on card %4")
890 LOG(VB_GENERAL, LOG_INFO,
891 QString(
"setting %1/%2/\"%3\" as aborted")
905 LOG(VB_GENERAL, LOG_INFO,
906 QString(
"adding %1/%2/\"%3\" as recording")
919 for ( ; ri !=
reclist.end(); ++ri)
941 LOG(VB_GENERAL, LOG_INFO, QString(
"setting %1/%2/\"%3\" as aborted")
951 for (; i !=
reclist.end(); ++i)
999 for (it = reclist.begin(); it != reclist.end(); ++it)
1007 reclist.resize(dst);
1027 *(dreciter++) =
nullptr;
1036 QMap<uint, uint> badinputs;
1056 conflictlist->push_back(p);
1062 QMap<uint, uint>::iterator it;
1063 for (it = badinputs.begin(); it != badinputs.end(); ++it)
1066 QString(
"Ignored %1 entries for invalid input %2")
1067 .arg(badinputs[it.value()]).arg(it.key()));
1101 uint *paffinity)
const 1104 for ( ; j != cardlist.end(); ++j)
1116 msg = QString(
"comparing with '%1' ").arg(q->
GetTitle());
1120 const vector <uint> &conflicting_inputs =
1122 if (
find(conflicting_inputs.begin(), conflicting_inputs.end(),
1123 q->
GetInputID()) == conflicting_inputs.end())
1126 msg +=
" cardid== ";
1135 msg +=
" no-overlap ";
1155 msg +=
" no-overlap ";
1164 LOG(VB_SCHEDULE, LOG_INFO, msg);
1165 LOG(VB_SCHEDULE, LOG_INFO,
1166 QString(
" cardid's: [%1], [%2] Share an input group" 1167 "mplexid's: %3, %4")
1181 LOG(VB_SCHEDULE, LOG_INFO,
"Found conflict");
1184 *paffinity += affinity;
1189 LOG(VB_SCHEDULE, LOG_INFO,
"No conflict");
1192 *paffinity += affinity;
1200 bool checkAll)
const 1210 return firstConflict;
1239 RecIter i = showinglist.begin();
1240 for ( ; i != showinglist.end(); ++i)
1301 uint bestaffinity = 0;
1303 RecIter j = showinglist->begin();
1304 for ( ; j != showinglist->end(); ++j)
1360 PrintRec(q, QString(
" %1:").arg(affinity));
1361 if (!best || affinity > bestaffinity)
1364 bestaffinity = affinity;
1372 QString msg = QString(
1373 "Moved \"%1\" on chanid: %2 from card: %3 to %4 at %5 " 1374 "to avoid LiveTV conflict")
1378 LOG(VB_GENERAL, LOG_INFO, msg);
1398 LOG(VB_SCHEDULE, LOG_DEBUG,
1399 "+ = schedule this showing to be recorded");
1400 LOG(VB_SCHEDULE, LOG_DEBUG,
1401 "n: = could schedule this showing with affinity");
1402 LOG(VB_SCHEDULE, LOG_DEBUG,
1403 "n# = could not schedule this showing, with affinity");
1404 LOG(VB_SCHEDULE, LOG_DEBUG,
1405 "! = conflict caused by this showing");
1406 LOG(VB_SCHEDULE, LOG_DEBUG,
1407 "/ = retry this showing, same priority pass");
1408 LOG(VB_SCHEDULE, LOG_DEBUG,
1409 "? = retry this showing, lower priority pass");
1410 LOG(VB_SCHEDULE, LOG_DEBUG,
1411 "> = try another showing for this program");
1412 LOG(VB_SCHEDULE, LOG_DEBUG,
1413 "- = unschedule a showing in favor of another one");
1434 int recpriority = (*i)->GetRecordingPriority();
1439 (*i)->GetRecordingPriority() != recpriority)
1443 int recpriority2 = (*i)->GetRecordingPriority2();
1444 LOG(VB_SCHEDULE, LOG_DEBUG, QString(
"Trying priority %1/%2...")
1445 .arg(recpriority).arg(recpriority2));
1449 LOG(VB_SCHEDULE, LOG_DEBUG, QString(
"Retrying priority %1/%2...")
1450 .arg(recpriority).arg(recpriority2));
1455 LOG(VB_SCHEDULE, LOG_DEBUG, QString(
"Retrying priority %1/*...")
1465 int recpriority,
int recpriority2)
1470 for ( ; i != end; ++i)
1472 if ((*i)->GetRecordingPriority() != recpriority ||
1473 (*i)->GetRecordingPriority2() != recpriority2 ||
1480 (*i)->GetRecordingPriority() != recpriority ||
1481 (*i)->GetRecordingPriority2() != recpriority2)
1486 uint bestaffinity = 0;
1489 for ( ; i != end; ++i)
1491 if ((*i)->GetRecordingPriority() != recpriority ||
1492 (*i)->GetRecordingPriority2() != recpriority2 ||
1493 (*i)->GetRecordingStartTime() !=
1495 (*i)->GetRecordingRuleID() !=
1497 (*i)->GetTitle() != first->
GetTitle() ||
1512 PrintRec(*i, QString(
" %1#").arg(affinity));
1517 PrintRec(*i, QString(
" %1:").arg(affinity));
1518 if (!best || affinity > bestaffinity)
1521 bestaffinity = affinity;
1542 bool samePriority,
bool livetv)
1545 for ( ; i != end; ++i)
1548 retry_list.push_back(*i);
1552 i = retry_list.begin();
1553 for ( ; i != retry_list.end(); ++i)
1595 int lastrecpri2 = 0;
1678 QMap<int, QDateTime> nextRecMap;
1704 query.
prepare(
"SELECT recordid, next_record FROM record;");
1710 while (query.
next())
1712 int recid = query.
value(0).toInt();
1715 if (next_record == nextRecMap[recid])
1718 if (nextRecMap[recid].isValid())
1720 subquery.
prepare(
"UPDATE record SET next_record = :NEXTREC " 1721 "WHERE recordid = :RECORDID;");
1723 subquery.
bindValue(
":NEXTREC", nextRecMap[recid]);
1724 if (!subquery.
exec())
1727 else if (next_record.isValid())
1729 subquery.
prepare(
"UPDATE record " 1730 "SET next_record = NULL " 1731 "WHERE recordid = :RECORDID;");
1733 if (!subquery.
exec())
1745 strlist << QString::number(retlist.size());
1747 while (!retlist.empty())
1752 retlist.pop_front();
1773 bool hasconflicts =
false;
1776 for (; it !=
reclist.end(); ++it)
1778 if (recRuleId > 0 &&
1779 (*it)->GetRecordingRuleID() != static_cast<uint>(recRuleId))
1782 hasconflicts =
true;
1786 return hasconflicts;
1793 bool hasconflicts =
false;
1796 for (; it !=
reclist.end(); ++it)
1798 if (recRuleId > 0 &&
1799 (*it)->GetRecordingRuleID() != static_cast<uint>(recRuleId))
1803 hasconflicts =
true;
1807 return hasconflicts;
1814 QMap<QString,ProgramInfo*> recMap;
1816 for (; it !=
reclist.end(); ++it)
1821 recMap[(*it)->MakeUniqueKey()] =
new ProgramInfo(**it);
1851 strList << QString::number(hasconflicts);
1852 strList << QString::number(retlist.size());
1854 while (!retlist.empty())
1859 retlist.pop_front();
1871 strList << QString::number(schedlist.size());
1873 while (!schedlist.empty())
1878 schedlist.pop_front();
1893 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"AddRecording() recid: %1")
1902 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Not adding recording, " +
1903 QString(
"'%1' is already in reclist.")
1909 LOG(VB_SCHEDULE, LOG_INFO,
LOC +
1910 QString(
"Adding '%1' to reclist.").arg(pi.
GetTitle()));
1927 QString(
"AddRecording %1").arg(pi.
GetTitle()));
1935 LOG(VB_GENERAL, LOG_ERR,
LOC +
1936 "IsBusyRecording() -> true, no tvList or no rcinfo");
1947 bool is_busy = rctv1->
IsBusy(&busy_input, -1);
1959 vector<uint> &inputids =
sinputinfomap[inputid].conflicting_inputs;
1960 vector<uint> &group_inputs =
sinputinfomap[inputid].group_inputs;
1961 for (
uint i = 0; i < inputids.size(); i++)
1963 if (!
m_tvList->contains(inputids[i]))
1966 LOG(VB_SCHEDULE, LOG_ERR,
LOC +
1967 QString(
"IsBusyRecording() -> true, rctv(NULL) for input %2")
1974 if (rctv2->
IsBusy(&busy_input, -1))
1995 std::find(group_inputs.begin(), group_inputs.end(),
1996 inputids[i]) != group_inputs.end())
2013 query.
prepare(
"UPDATE oldrecorded SET recstatus = :RSABORTED " 2014 " WHERE recstatus = :RSRECORDING OR " 2015 " recstatus = :RSTUNING OR " 2016 " recstatus = :RSFAILING");
2025 query.
prepare(
"UPDATE oldrecorded SET recstatus = :RSMISSED " 2026 "WHERE recstatus = :RSWILLRECORD OR " 2027 " recstatus = :RSPENDING");
2036 query.
prepare(
"UPDATE oldrecorded SET recstatus = :RSPREVIOUS " 2037 "WHERE recstatus = :RSCURRENT");
2046 query.
prepare(
"UPDATE oldrecorded SET future = 0 " 2047 "WHERE future > 0 AND " 2048 " endtime < (NOW() - INTERVAL 475 MINUTE)");
2075 int prerollseconds = 0;
2076 int wakeThreshold = 300;
2079 bool blockShutdown =
2081 bool firstRun =
true;
2084 QDateTime idleSince = QDateTime();
2085 int schedRunTime = 0;
2086 bool statuschanged =
false;
2088 QDateTime nextWakeTime = nextStartTime;
2102 nextWakeTime = min(nextWakeTime, nextStartTime);
2104 int secs_to_next = curtime.secsTo(nextStartTime);
2105 int sched_sleep = max(curtime.msecsTo(nextWakeTime), qint64(0));
2107 sched_sleep = min(sched_sleep, 15000);
2109 int const kSleepCheck = 300;
2110 bool checkSlaves = curtime >= nextSleepCheck;
2114 if ((secs_to_next > -60 && secs_to_next < schedRunTime) ||
2115 (!haveRequests && !checkSlaves))
2119 LOG(VB_SCHEDULE, LOG_INFO,
2120 QString(
"sleeping for %1 ms " 2121 "(s2n: %2 sr: %3 qr: %4 cs: %5)")
2122 .arg(sched_sleep).arg(secs_to_next).arg(schedRunTime)
2123 .arg(haveRequests).arg(checkSlaves));
2147 statuschanged =
true;
2150 schedRunTime = max(
int(((
t.elapsed() + 999) / 1000) * 1.5 + 2),
2172 checkSlaves =
false;
2182 nextWakeTime = nextSleepCheck;
2186 for ( ; startIter !=
reclist.end(); ++startIter)
2188 if ((*startIter)->GetRecordingStatus() !=
2189 (*startIter)->oldrecstatus)
2202 **it, statuschanged, nextStartTime, nextWakeTime,
2216 int secsleft = curtime.secsTo((*it)->GetRecordingStartTime());
2217 if ((secsleft - prerollseconds) <= wakeThreshold)
2237 if (idleSince.isValid())
2245 statuschanged =
false;
2252 const QString &title,
const QString &subtitle,
2253 const QString &descrip,
2254 const QString &programid)
2257 QString filterClause;
2260 if (!title.isEmpty())
2262 filterClause +=
"AND p.title = :TITLE ";
2263 bindings[
":TITLE"] = title;
2267 if (programid !=
"**any**")
2269 filterClause +=
"AND (0 ";
2270 if (!subtitle.isEmpty())
2273 filterClause +=
"OR p.subtitle = :SUBTITLE1 " 2274 "OR p.description = :SUBTITLE2 ";
2275 bindings[
":SUBTITLE1"] = subtitle;
2276 bindings[
":SUBTITLE2"] = subtitle;
2278 if (!descrip.isEmpty())
2281 filterClause +=
"OR p.description = :DESCRIP1 " 2282 "OR p.subtitle = :DESCRIP2 ";
2283 bindings[
":DESCRIP1"] = descrip;
2284 bindings[
":DESCRIP2"] = descrip;
2286 if (!programid.isEmpty())
2288 filterClause +=
"OR p.programid = :PROGRAMID ";
2289 bindings[
":PROGRAMID"] = programid;
2291 filterClause +=
") ";
2294 query.
prepare(QString(
"UPDATE recordmatch rm " 2296 " ON rm.recordid = r.recordid " 2297 "INNER JOIN program p " 2298 " ON rm.chanid = p.chanid " 2299 " AND rm.starttime = p.starttime " 2300 " AND rm.manualid = p.manualid " 2301 "SET oldrecduplicate = -1 " 2302 "WHERE p.generic = 0 " 2303 " AND r.type NOT IN (%2, %3, %4) ")
2309 MSqlBindings::const_iterator it;
2310 for (it = bindings.begin(); it != bindings.end(); ++it)
2315 if (findid && programid !=
"**any**")
2317 query.
prepare(
"UPDATE recordmatch rm " 2318 "SET oldrecduplicate = -1 " 2319 "WHERE rm.recordid = :RECORDID " 2320 " AND rm.findid = :FINDID");
2334 struct timeval fillstart, fillend;
2335 float matchTime, checkTime, placeTime;
2337 gettimeofday(&fillstart,
nullptr);
2339 bool deleteFuture =
false;
2340 bool runCheck =
false;
2346 if (request.size() >= 1)
2347 tokens = request[0].split(
' ', QString::SkipEmptyParts);
2349 if (request.size() < 1 || tokens.size() < 1)
2351 LOG(VB_GENERAL, LOG_ERR,
"Empty Reschedule request received");
2355 LOG(VB_GENERAL, LOG_INFO, QString(
"Reschedule requested for %1")
2356 .arg(request.join(
" | ")));
2358 if (tokens[0] ==
"MATCH")
2360 if (tokens.size() < 5)
2362 LOG(VB_GENERAL, LOG_ERR,
2363 QString(
"Invalid RescheduleMatch request received (%1)")
2368 uint recordid = tokens[1].toUInt();
2369 uint sourceid = tokens[2].toUInt();
2370 uint mplexid = tokens[3].toUInt();
2372 deleteFuture =
true;
2380 else if (tokens[0] ==
"CHECK")
2382 if (tokens.size() < 4 || request.size() < 5)
2384 LOG(VB_GENERAL, LOG_ERR,
2385 QString(
"Invalid RescheduleCheck request received (%1)")
2390 uint recordid = tokens[2].toUInt();
2391 uint findid = tokens[3].toUInt();
2392 QString title = request[1];
2393 QString subtitle = request[2];
2394 QString descrip = request[3];
2395 QString programid = request[4];
2404 else if (tokens[0] !=
"PLACE")
2406 LOG(VB_GENERAL, LOG_ERR,
2407 QString(
"Unknown Reschedule request received (%1)")
2417 query.
prepare(
"DELETE oldrecorded FROM oldrecorded " 2418 "LEFT JOIN recordmatch ON " 2419 " recordmatch.chanid = oldrecorded.chanid AND " 2420 " recordmatch.starttime = oldrecorded.starttime " 2421 "WHERE oldrecorded.future > 0 AND " 2422 " recordmatch.recordid IS NULL");
2427 gettimeofday(&fillend,
nullptr);
2428 matchTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
2429 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
2431 LOG(VB_SCHEDULE, LOG_INFO,
"CreateTempTables...");
2434 gettimeofday(&fillstart,
nullptr);
2437 LOG(VB_SCHEDULE, LOG_INFO,
"UpdateDuplicates...");
2440 gettimeofday(&fillend,
nullptr);
2441 checkTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
2442 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
2444 gettimeofday(&fillstart,
nullptr);
2446 gettimeofday(&fillend,
nullptr);
2447 placeTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
2448 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
2450 LOG(VB_SCHEDULE, LOG_INFO,
"DeleteTempTables...");
2460 LOG(VB_GENERAL, LOG_INFO,
"Reschedule interrupted, will retry");
2465 msg.sprintf(
"Scheduled %d items in %.1f " 2466 "= %.2f match + %.2f check + %.2f place",
2468 static_cast<double>(matchTime + checkTime + placeTime),
2469 static_cast<double>(matchTime),
2470 static_cast<double>(checkTime),
2471 static_cast<double>(placeTime));
2472 LOG(VB_GENERAL, LOG_INFO, msg);
2476 for ( ; it !=
reclist.end(); ++it)
2507 bool blockShutdown =
true;
2512 QString startupParam =
"user";
2516 for ( ; firstRunIter !=
reclist.end(); ++firstRunIter)
2526 ((firstRunIter !=
reclist.end()) &&
2527 ((curtime.secsTo((*firstRunIter)->GetRecordingStartTime()) -
2530 LOG(VB_GENERAL, LOG_INFO,
LOC +
"AUTO-Startup assumed");
2531 startupParam =
"auto";
2535 blockShutdown =
false;
2539 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Seem to be woken up by USER");
2551 return blockShutdown;
2557 static const int sysEventSecs[5] = { 120, 90, 60, 30, 0 };
2561 int secsleft = curtime.secsTo(nextrectime);
2572 bool pendingEventSent =
false;
2573 while (sysEventSecs[i] != 0)
2575 if ((secsleft <= sysEventSecs[i]) &&
2578 if (!pendingEventSent)
2581 QString(
"REC_PENDING SECS %1").arg(secsleft), &ri);
2585 pendingEventSent =
true;
2592 for (i = 0; sysEventSecs[i] != 0; i++)
2600 for ( ; it !=
reclist.end(); ++it)
2601 keys.insert((*it)->MakeUniqueKey());
2602 keys.insert(
"something");
2605 QSet<QString>::iterator sit =
sysEvents[i].begin();
2608 if (!keys.contains(*sit))
2619 LOG(VB_SCHEDULE, LOG_INFO,
LOC +
2620 QString(
"Slave Backend %1 is being awakened to record: %2")
2627 ((secsleft - prerollseconds) < 210) &&
2631 LOG(VB_SCHEDULE, LOG_INFO,
LOC +
2632 QString(
"Slave Backend %1 not available yet, " 2633 "trying to wake it up again.")
2640 ((secsleft - prerollseconds) < 150) &&
2643 LOG(VB_GENERAL, LOG_WARNING,
LOC +
2644 QString(
"Slave Backend %1 has NOT come " 2645 "back from sleep yet in 150 seconds. Setting " 2646 "slave status to unknown and attempting " 2647 "to reschedule around its tuners.")
2650 QMap<int, EncoderLink*>::iterator it =
m_tvList->begin();
2651 for (; it !=
m_tvList->end(); ++it)
2653 if ((*it)->GetHostName() == nexttv->
GetHostName())
2663 QDateTime &nextStartTime, QDateTime &nextWakeTime,
2671 int origprerollseconds = prerollseconds;
2678 if (nextWakeTime.secsTo(nextrectime) - prerollseconds > 300)
2680 nextStartTime = min(nextStartTime, nextrectime);
2684 if (curtime < nextrectime)
2685 nextWakeTime = min(nextWakeTime, nextrectime);
2691 int secsleft = curtime.secsTo(nextrectime);
2696 if (secsleft - prerollseconds > 60)
2698 nextStartTime = min(nextStartTime, nextrectime.addSecs(-30));
2699 nextWakeTime = min(nextWakeTime,
2700 nextrectime.addSecs(-prerollseconds - 60));
2715 if (secsleft - prerollseconds > 35)
2717 nextStartTime = min(nextStartTime, nextrectime.addSecs(-30));
2718 nextWakeTime = min(nextWakeTime,
2719 nextrectime.addSecs(-prerollseconds - 35));
2728 QString msg = QString(
"Invalid cardid [%1] for %2")
2730 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2734 statuschanged =
true;
2742 QString msg = QString(
"SUPPRESSED recording \"%1\" on channel: " 2743 "%2 on cardid: [%3], sourceid %4. Tuner " 2744 "is locked by an external application.")
2749 LOG(VB_GENERAL, LOG_NOTICE, msg);
2753 statuschanged =
true;
2764 if (prerollseconds > 0)
2772 if (isBusyRecording)
2775 nextWakeTime = min(nextWakeTime, curtime.addSecs(5));
2780 if (secsleft - prerollseconds > 30)
2782 nextStartTime = min(nextStartTime, nextrectime.addSecs(-30));
2783 nextWakeTime = min(nextWakeTime,
2784 nextrectime.addSecs(-prerollseconds - 30));
2792 LOG(VB_SCHEDULE, LOG_WARNING,
2793 QString(
"WARNING: Slave Backend %1 has NOT come " 2794 "back from sleep yet. Recording can " 2795 "not begin yet for: %2")
2801 LOG(VB_SCHEDULE, LOG_WARNING,
2802 QString(
"WARNING: Slave Backend %1 has NOT come " 2803 "back from sleep yet. Setting slave " 2804 "status to unknown and attempting " 2805 "to reschedule around its tuners.")
2808 QMap<int, EncoderLink *>::Iterator enciter =
2810 for (; enciter !=
m_tvList->end(); ++enciter)
2820 nextStartTime = min(nextStartTime, nextrectime);
2821 nextWakeTime = min(nextWakeTime, curtime.addSecs(1));
2828 QString recording_dir;
2847 MythEvent me(QString(
"ADD_CHILD_INPUT %1")
2850 nextWakeTime = min(nextWakeTime, curtime.addSecs(1));
2866 if (secsleft - prerollseconds > 0)
2868 nextStartTime = min(nextStartTime, nextrectime);
2869 nextWakeTime = min(nextWakeTime,
2870 nextrectime.addSecs(-prerollseconds));
2875 recstartts = QDateTime(
2877 QTime(recstartts.time().hour(), recstartts.time().minute()), Qt::UTC);
2881 QString details = QString(
"%1: channel %2 on cardid [%3], sourceid %4")
2906 statuschanged =
true;
2919 bool doSchedAfterStart =
2928 QString(
"Started recording") :
2930 QString(
"Tuning recording") :
2931 QString(
"Canceled recording (%1)")
2934 LOG(VB_GENERAL, LOG_INFO, QString(
"%1: %2").arg(msg).arg(details));
2942 MythEvent me(QString(
"FORCE_DELETE_RECORDING %1 %2")
2955 LOG(VB_SCHEDULE, LOG_DEBUG,
2956 QString(
"Assigning input for %1/%2/\"%3\"")
2967 for (
uint i = 0; !bestid && i < inputs.size(); ++i)
2969 uint inputid = inputs[i];
2976 for ( ; j !=
reclist.end(); ++j)
2980 prerollseconds + 60)
2999 LOG(VB_SCHEDULE, LOG_DEBUG,
3000 QString(
"Input %1 has a pending recording").arg(inputid));
3009 LOG(VB_SCHEDULE, LOG_DEBUG,
3010 QString(
"Input %1 is recording").arg(inputid));
3015 LOG(VB_SCHEDULE, LOG_DEBUG,
3016 QString(
"Input %1 is recording but will be free")
3025 LOG(VB_SCHEDULE, LOG_DEBUG,
3026 QString(
"Input %1 is recording but has to stop")
3032 LOG(VB_SCHEDULE, LOG_DEBUG,
3033 QString(
"Input %1 is recording but could be free")
3045 bool isbusy = rctv->
IsBusy(&busy_info, -1);
3051 LOG(VB_SCHEDULE, LOG_DEBUG,
3052 QString(
"Input %1 is free").arg(inputid));
3058 LOG(VB_SCHEDULE, LOG_DEBUG,
3059 QString(
"Input %1 is on livetv but has to stop")
3070 LOG(VB_SCHEDULE, LOG_INFO,
3071 QString(
"Assigned input %1 for %2/%3/\"%4\"")
3078 LOG(VB_SCHEDULE, LOG_WARNING,
3079 QString(
"Failed to assign input for %1/%2/\"%3\"")
3088 bool &blockShutdown, QDateTime &idleSince,
3090 bool &statuschanged)
3093 uint logmask = VB_IDLE;
3094 int tm = QTime::currentTime().msecsSinceStartOfDay() / 900000;
3097 logmask = VB_GENERAL;
3111 LOG(VB_GENERAL, LOG_NOTICE,
"Client is connected, removing startup block on shutdown");
3112 blockShutdown =
false;
3120 bool recording =
false;
3122 QMap<int, EncoderLink *>::Iterator it;
3126 if ((*it)->IsBusy())
3133 if (!blocking && !recording)
3140 if (idleSince.isValid())
3142 MythEvent me(QString(
"SHUTDOWN_COUNTDOWN -1"));
3145 idleSince = QDateTime();
3150 if (statuschanged || !idleSince.isValid())
3152 bool wasValid = idleSince.isValid();
3154 idleSince = curtime;
3157 for ( ; idleIter !=
reclist.end(); ++idleIter)
3158 if ((*idleIter)->GetRecordingStatus() ==
3160 (*idleIter)->GetRecordingStatus() ==
3164 if (idleIter !=
reclist.end())
3166 if ((curtime.secsTo((*idleIter)->GetRecordingStartTime()) -
3170 LOG(logmask, LOG_NOTICE,
"Blocking shutdown because " 3171 "a recording is due to " 3173 idleSince = QDateTime();
3184 if (guideRunTime.isValid() &&
3186 (curtime.secsTo(guideRunTime) <
3189 LOG(logmask, LOG_NOTICE,
"Blocking shutdown because " 3190 "mythfilldatabase is due to " 3192 idleSince = QDateTime();
3197 if (idleSince.isValid())
3200 if (wasValid && !idleSince.isValid())
3202 MythEvent me(QString(
"SHUTDOWN_COUNTDOWN -1"));
3207 if (idleSince.isValid())
3220 LOG(VB_GENERAL, LOG_WARNING,
3221 "Waited more than 60" 3222 " seconds for shutdown to complete" 3223 " - resetting idle time");
3224 idleSince = QDateTime();
3230 blockShutdown, logmask))
3236 MythEvent me(QString(
"SHUTDOWN_COUNTDOWN -1"));
3242 int itime = idleSince.secsTo(curtime);
3246 msg = QString(
"I\'m idle now... shutdown will " 3247 "occur in %1 seconds.")
3249 LOG(VB_GENERAL, LOG_NOTICE, msg);
3250 MythEvent me(QString(
"SHUTDOWN_COUNTDOWN %1")
3256 msg = QString(
"%1 secs left to system shutdown!")
3258 LOG(logmask, LOG_NOTICE, msg);
3259 MythEvent me(QString(
"SHUTDOWN_COUNTDOWN %1")
3269 LOG(logmask, LOG_NOTICE,
"Blocking shutdown because " 3270 "of an active encoder");
3272 LOG(logmask, LOG_NOTICE,
"Blocking shutdown because " 3273 "of a connected client");
3276 if (idleSince.isValid())
3278 MythEvent me(QString(
"SHUTDOWN_COUNTDOWN -1"));
3281 idleSince = QDateTime();
3288 bool &blockShutdown,
uint logmask)
3290 (void)prerollseconds;
3291 bool retval =
false;
3301 LOG(logmask, LOG_INFO,
3302 "CheckShutdownServer returned - OK to shutdown");
3306 LOG(logmask, LOG_NOTICE,
3307 "CheckShutdownServer returned - Not OK to shutdown");
3309 idleSince = QDateTime();
3312 LOG(logmask, LOG_NOTICE,
3313 "CheckShutdownServer returned - Not OK to shutdown, " 3321 idleSince = QDateTime();
3326 m_noAutoShutdown =
true;
3330 LOG(VB_GENERAL, LOG_NOTICE,
3331 "CheckShutdownServer returned - Not OK");
3334 LOG(VB_GENERAL, LOG_NOTICE, QString(
3335 "CheckShutdownServer returned - Error %1").arg(state));
3350 for ( ; recIter !=
reclist.end(); ++recIter)
3356 QDateTime restarttime;
3361 .addSecs((-1) * prerollseconds);
3369 && guideRefreshTime.isValid()
3371 && (restarttime.isNull() || guideRefreshTime < restarttime))
3372 restarttime = guideRefreshTime;
3374 if (restarttime.isValid())
3378 restarttime = restarttime.addSecs((-1) * add);
3381 "hh:mm yyyy-MM-dd");
3383 "echo \'Wakeuptime would " 3384 "be $time if command " 3387 if (setwakeup_cmd.isEmpty())
3389 LOG(VB_GENERAL, LOG_NOTICE,
3390 "SetWakeuptimeCommand is empty, shutdown aborted");
3391 idleSince = QDateTime();
3395 if (wakeup_timeformat ==
"time_t")
3398 setwakeup_cmd.replace(
"$time",
3399 #
if QT_VERSION < QT_VERSION_CHECK(5,8,0)
3400 time_ts.setNum(restarttime.toTime_t())
3402 time_ts.setNum(restarttime.toSecsSinceEpoch())
3407 setwakeup_cmd.replace(
3408 "$time", restarttime.toLocalTime().toString(wakeup_timeformat));
3410 LOG(VB_GENERAL, LOG_NOTICE,
3411 QString(
"Running the command to set the next " 3412 "scheduled wakeup time :-\n\t\t\t\t") + setwakeup_cmd);
3417 LOG(VB_GENERAL, LOG_ERR,
3418 "SetWakeuptimeCommand failed, shutdown aborted");
3419 idleSince = QDateTime();
3434 "sudo /sbin/halt -p");
3436 if (!halt_cmd.isEmpty())
3441 LOG(VB_GENERAL, LOG_NOTICE,
3442 QString(
"Running the command to shutdown " 3443 "this computer :-\n\t\t\t\t") + halt_cmd);
3450 LOG(VB_GENERAL, LOG_ERR,
"ServerHaltCommand failed, shutdown aborted");
3455 idleSince = QDateTime();
3461 int prerollseconds = 0;
3466 bool someSlavesCanSleep =
false;
3467 QMap<int, EncoderLink *>::Iterator enciter =
m_tvList->begin();
3468 for (; enciter !=
m_tvList->end(); ++enciter)
3473 someSlavesCanSleep =
true;
3476 if (!someSlavesCanSleep)
3479 LOG(VB_SCHEDULE, LOG_INFO,
3480 "Scheduler, Checking for slaves that can be shut down");
3482 int sleepThreshold =
3485 LOG(VB_SCHEDULE, LOG_DEBUG,
3486 QString(
" Getting list of slaves that will be active in the " 3487 "next %1 minutes.") .arg(sleepThreshold / 60));
3489 LOG(VB_SCHEDULE, LOG_DEBUG,
"Checking scheduler's reclist");
3492 QStringList SlavesInUse;
3493 for ( ; recIter !=
reclist.end(); ++recIter)
3504 secsleft = curtime.secsTo(
3506 if (secsleft > sleepThreshold)
3517 LOG(VB_SCHEDULE, LOG_DEBUG,
3518 QString(
" Slave %1 will be in use in %2 minutes")
3521 LOG(VB_SCHEDULE, LOG_DEBUG,
3522 QString(
" Slave %1 is in use currently " 3530 LOG(VB_SCHEDULE, LOG_DEBUG,
" Checking inuseprograms table:");
3533 query.
prepare(
"SELECT DISTINCT hostname, recusage FROM inuseprograms " 3534 "WHERE lastupdatetime > :ONEHOURAGO ;");
3535 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
3538 while(query.
next()) {
3539 SlavesInUse << query.
value(0).toString();
3540 LOG(VB_SCHEDULE, LOG_DEBUG,
3541 QString(
" Slave %1 is marked as in use by a %2")
3542 .arg(query.
value(0).toString())
3543 .arg(query.
value(1).toString()));
3547 LOG(VB_SCHEDULE, LOG_DEBUG, QString(
" Shutting down slaves which will " 3548 "be inactive for the next %1 minutes and can be put to sleep.")
3549 .arg(sleepThreshold / 60));
3552 for (; enciter !=
m_tvList->end(); ++enciter)
3561 QString sleepCommand =
3564 QString wakeUpCommand =
3568 if (!sleepCommand.isEmpty() && !wakeUpCommand.isEmpty())
3572 LOG(VB_SCHEDULE, LOG_DEBUG,
3573 QString(
" Commanding %1 to go to sleep.")
3578 QMap<int, EncoderLink *>::Iterator slviter =
3580 for (; slviter !=
m_tvList->end(); ++slviter)
3585 LOG(VB_SCHEDULE, LOG_DEBUG,
3586 QString(
" Marking card %1 on slave %2 " 3587 "as falling asleep.")
3596 LOG(VB_GENERAL, LOG_ERR,
LOC +
3597 QString(
"Unable to shutdown %1 slave backend, setting " 3598 "sleep status to undefined.").arg(thisHost));
3599 QMap<int, EncoderLink *>::Iterator slviter =
3601 for (; slviter !=
m_tvList->end(); ++slviter)
3617 LOG(VB_GENERAL, LOG_NOTICE,
3618 QString(
"Tried to Wake Up %1, but this is the " 3619 "master backend and it is not asleep.")
3620 .arg(slaveHostname));
3627 if (wakeUpCommand.isEmpty()) {
3628 LOG(VB_GENERAL, LOG_NOTICE,
3629 QString(
"Trying to Wake Up %1, but this slave " 3630 "does not have a WakeUpCommand set.").arg(slaveHostname));
3632 QMap<int, EncoderLink *>::Iterator enciter =
m_tvList->begin();
3633 for (; enciter !=
m_tvList->end(); ++enciter)
3644 QMap<int, EncoderLink *>::Iterator enciter =
m_tvList->begin();
3645 for (; enciter !=
m_tvList->end(); ++enciter)
3648 if (setWakingStatus && (enc->
GetHostName() == slaveHostname))
3655 LOG(VB_SCHEDULE, LOG_NOTICE, QString(
"Executing '%1' to wake up slave.")
3656 .arg(wakeUpCommand));
3668 QStringList SlavesThatCanWake;
3670 QMap<int, EncoderLink *>::Iterator enciter =
m_tvList->begin();
3671 for (; enciter !=
m_tvList->end(); ++enciter)
3682 (!SlavesThatCanWake.contains(thisSlave)))
3683 SlavesThatCanWake << thisSlave;
3687 for (; slave < SlavesThatCanWake.count(); slave++)
3689 thisSlave = SlavesThatCanWake[slave];
3690 LOG(VB_SCHEDULE, LOG_NOTICE,
3691 QString(
"Scheduler, Sending wakeup command to slave: %1")
3701 query.
prepare(QString(
"SELECT type,title,station,startdate,starttime, " 3703 "FROM %1 WHERE recordid = :RECORDID").arg(
recordTable));
3705 if (!query.
exec() || query.
size() != 1)
3715 QString title = query.
value(1).toString();
3716 QString station = query.
value(2).toString() ;
3717 QDateTime startdt = QDateTime(query.
value(3).toDate(),
3718 query.
value(4).toTime(), Qt::UTC);
3719 int duration = startdt.secsTo(
3720 QDateTime(query.
value(5).toDate(),
3721 query.
value(6).toTime(), Qt::UTC));
3723 query.
prepare(
"SELECT chanid from channel " 3724 "WHERE callsign = :STATION");
3732 vector<uint> chanidlist;
3733 while (query.
next())
3734 chanidlist.push_back(query.
value(0).toUInt());
3740 QDateTime lstartdt = startdt.toLocalTime();
3755 weekday = (lstartdt.date().dayOfWeek() < 6);
3756 daysoff = lstartdt.date().daysTo(
3758 startdt = QDateTime(lstartdt.date().addDays(daysoff),
3759 lstartdt.time(), Qt::LocalTime).toUTC();
3765 daysoff = lstartdt.date().daysTo(
3767 daysoff = (daysoff + 6) / 7 * 7;
3768 startdt = QDateTime(lstartdt.date().addDays(daysoff),
3769 lstartdt.time(), Qt::LocalTime).toUTC();
3772 LOG(VB_GENERAL, LOG_ERR,
3773 QString(
"Invalid rectype for manual recordid %1").arg(recordid));
3779 for (
int i = 0; i < (int)chanidlist.size(); i++)
3781 if (weekday && startdt.toLocalTime().date().dayOfWeek() >= 6)
3784 query.
prepare(
"REPLACE INTO program (chanid, starttime, endtime," 3785 " title, subtitle, manualid, generic) " 3786 "VALUES (:CHANID, :STARTTIME, :ENDTIME, :TITLE," 3787 " :SUBTITLE, :RECORDID, 1)");
3788 query.
bindValue(
":CHANID", chanidlist[i]);
3790 query.
bindValue(
":ENDTIME", startdt.addSecs(duration));
3792 query.
bindValue(
":SUBTITLE", startdt.toLocalTime());
3801 daysoff += skipdays;
3802 startdt = QDateTime(lstartdt.date().addDays(daysoff),
3803 lstartdt.time(), Qt::LocalTime).toUTC();
3815 query = QString(
"SELECT recordid,search,subtitle,description " 3816 "FROM %1 WHERE search <> %2 AND " 3817 "(recordid = %3 OR %4 = 0) ")
3829 while (result.
next())
3831 QString
prefix = QString(
":NR%1").arg(count);
3832 qphrase = result.
value(3).toString();
3838 LOG(VB_GENERAL, LOG_ERR,
3839 QString(
"Invalid search key in recordid %1")
3840 .arg(result.
value(0).toString()));
3844 QString bindrecid =
prefix +
"RECID";
3845 QString bindphrase =
prefix +
"PHRASE";
3846 QString bindlikephrase1 =
prefix +
"LIKEPHRASE1";
3847 QString bindlikephrase2 =
prefix +
"LIKEPHRASE2";
3848 QString bindlikephrase3 =
prefix +
"LIKEPHRASE3";
3850 bindings[bindrecid] = result.
value(0).toString();
3855 qphrase.remove(QRegExp(
"^\\s*AND\\s+", Qt::CaseInsensitive));
3856 qphrase.remove(
';');
3857 from << result.
value(2).toString();
3858 where << (QString(
"%1.recordid = ").arg(
recordTable) + bindrecid +
3859 QString(
" AND program.manualid = 0 AND ( %2 )")
3863 bindings[bindlikephrase1] = QString(
"%") + qphrase +
"%";
3865 where << (QString(
"%1.recordid = ").arg(
recordTable) + bindrecid +
" AND " 3866 "program.manualid = 0 AND " 3867 "program.title LIKE " + bindlikephrase1);
3870 bindings[bindlikephrase1] = QString(
"%") + qphrase +
"%";
3871 bindings[bindlikephrase2] = QString(
"%") + qphrase +
"%";
3872 bindings[bindlikephrase3] = QString(
"%") + qphrase +
"%";
3874 where << (QString(
"%1.recordid = ").arg(
recordTable) + bindrecid +
3875 " AND program.manualid = 0" 3876 " AND (program.title LIKE " + bindlikephrase1 +
3877 " OR program.subtitle LIKE " + bindlikephrase2 +
3878 " OR program.description LIKE " + bindlikephrase3 +
")");
3881 bindings[bindphrase] = qphrase;
3882 from <<
", people, credits";
3883 where << (QString(
"%1.recordid = ").arg(
recordTable) + bindrecid +
" AND " 3884 "program.manualid = 0 AND " 3885 "people.name LIKE " + bindphrase +
" AND " 3886 "credits.person = people.person AND " 3887 "program.chanid = credits.chanid AND " 3888 "program.starttime = credits.starttime");
3893 where << (QString(
"%1.recordid = ").arg(
recordTable) + bindrecid +
3895 QString(
"program.manualid = %1.recordid ")
3899 LOG(VB_GENERAL, LOG_ERR,
3900 QString(
"Unknown RecSearchType (%1) for recordid %2")
3901 .arg(result.
value(1).toInt())
3902 .arg(result.
value(0).toString()));
3903 bindings.remove(bindrecid);
3910 if (recordid == 0 || from.count() == 0)
3912 QString recidmatch =
"";
3914 recidmatch =
"RECTABLE.recordid = :NRRECORDID AND ";
3915 QString s1 = recidmatch +
3916 "RECTABLE.type <> :NRTEMPLATE AND " 3917 "RECTABLE.search = :NRST AND " 3918 "program.manualid = 0 AND " 3919 "program.title = RECTABLE.title ";
3921 QString s2 = recidmatch +
3922 "RECTABLE.type <> :NRTEMPLATE AND " 3923 "RECTABLE.search = :NRST AND " 3924 "program.manualid = 0 AND " 3925 "program.seriesid <> '' AND " 3926 "program.seriesid = RECTABLE.seriesid ";
3936 bindings[
":NRRECORDID"] = recordid;
3942 " WHEN RECTABLE.type IN (%1, %2, %3) THEN 0 " 3943 " WHEN RECTABLE.type IN (%4, %5, %6) THEN -1 " 3944 " ELSE (program.generic - 1) " 3950 "(CASE RECTABLE.type " 3952 " THEN RECTABLE.findid " 3954 " THEN to_days(date_sub(convert_tz(program.starttime, 'UTC', 'SYSTEM'), " 3955 " interval time_format(RECTABLE.findtime, '%H:%i') hour_minute)) " 3957 " THEN floor((to_days(date_sub(convert_tz(program.starttime, 'UTC', " 3958 " 'SYSTEM'), interval time_format(RECTABLE.findtime, '%H:%i') " 3959 " hour_minute)) - RECTABLE.findday)/7) * 7 + RECTABLE.findday " 3961 " THEN RECTABLE.findid " 3970 const QDateTime &maxstarttime)
3972 struct timeval dbstart, dbend;
3976 QString deleteClause;
3977 QString filterClause = QString(
" AND program.endtime > " 3978 "(NOW() - INTERVAL 480 MINUTE)");
3982 deleteClause +=
" AND recordmatch.recordid = :RECORDID";
3983 bindings[
":RECORDID"] = recordid;
3987 deleteClause +=
" AND channel.sourceid = :SOURCEID";
3988 filterClause +=
" AND channel.sourceid = :SOURCEID";
3989 bindings[
":SOURCEID"] = sourceid;
3993 deleteClause +=
" AND channel.mplexid = :MPLEXID";
3994 filterClause +=
" AND channel.mplexid = :MPLEXID";
3995 bindings[
":MPLEXID"] = mplexid;
3997 if (maxstarttime.isValid())
3999 deleteClause +=
" AND recordmatch.starttime <= :MAXSTARTTIME";
4000 filterClause +=
" AND program.starttime <= :MAXSTARTTIME";
4001 bindings[
":MAXSTARTTIME"] = maxstarttime;
4004 query.prepare(QString(
"DELETE recordmatch FROM recordmatch, channel " 4005 "WHERE recordmatch.chanid = channel.chanid")
4007 MSqlBindings::const_iterator it;
4008 for (it = bindings.begin(); it != bindings.end(); ++it)
4009 query.bindValue(it.key(), it.value());
4016 bindings.remove(
":RECORDID");
4018 query.prepare(
"SELECT filterid, clause FROM recordfilter " 4019 "WHERE filterid >= 0 AND filterid < :NUMFILTERS AND " 4020 " TRIM(clause) <> ''");
4027 while (query.next())
4029 filterClause += QString(
" AND (((RECTABLE.filter & %1) = 0) OR (%2))")
4030 .arg(1 << query.value(0).toInt()).arg(query.value(1).toString());
4034 query.prepare(
"SELECT NULL from record " 4035 "WHERE type = :FINDONE AND findid <= 0;");
4042 else if (query.size())
4044 QDate epoch(1970, 1, 1);
4047 query.prepare(
"UPDATE record set findid = :FINDID " 4048 "WHERE type = :FINDONE AND findid <= 0;");
4049 query.bindValue(
":FINDID", findtoday);
4056 QStringList fromclauses, whereclauses;
4062 for (clause = 0; clause < fromclauses.count(); ++clause)
4064 LOG(VB_SCHEDULE, LOG_INFO, QString(
"Query %1: %2/%3")
4065 .arg(clause).arg(fromclauses[clause])
4066 .arg(whereclauses[clause]));
4070 for (clause = 0; clause < fromclauses.count(); ++clause)
4072 QString query2 = QString(
4073 "REPLACE INTO recordmatch (recordid, chanid, starttime, manualid, " 4074 " oldrecduplicate, findid) " 4075 "SELECT RECTABLE.recordid, program.chanid, program.starttime, " 4076 " IF(search = %1, RECTABLE.recordid, 0), ").arg(
kManualSearch) +
4078 "FROM (RECTABLE, program INNER JOIN channel " 4079 " ON channel.chanid = program.chanid) ") + fromclauses[clause] + QString(
4080 " WHERE ") + whereclauses[clause] +
4081 QString(
" AND channel.visible = 1 ") +
4082 filterClause + QString(
" AND " 4085 " (RECTABLE.type = %1 " 4086 " OR RECTABLE.type = %2 " 4087 " OR RECTABLE.type = %3 " 4088 " OR RECTABLE.type = %4) " 4090 " ((RECTABLE.type = %6 " 4091 " OR RECTABLE.type = %7 " 4092 " OR RECTABLE.type = %8)" 4094 " ADDTIME(RECTABLE.startdate, RECTABLE.starttime) = program.starttime " 4096 " RECTABLE.station = channel.callsign) " 4108 LOG(VB_SCHEDULE, LOG_INFO, QString(
" |-- Start DB Query %1...")
4111 gettimeofday(&dbstart,
nullptr);
4115 for (it = bindings.begin(); it != bindings.end(); ++it)
4117 if (query2.contains(it.key()))
4121 bool ok = result.
exec();
4122 gettimeofday(&dbend,
nullptr);
4130 LOG(VB_SCHEDULE, LOG_INFO, QString(
" |-- %1 results in %2 sec.")
4132 .arg(((dbend.tv_sec - dbstart.tv_sec) * 1000000 +
4133 (dbend.tv_usec - dbstart.tv_usec)) / 1000000.0));
4137 LOG(VB_SCHEDULE, LOG_INFO,
" +-- Done.");
4146 result.
prepare(
"DROP TABLE IF EXISTS sched_temp_record;");
4152 result.
prepare(
"CREATE TEMPORARY TABLE sched_temp_record " 4159 result.
prepare(
"INSERT sched_temp_record SELECT * from record;");
4167 result.
prepare(
"DROP TABLE IF EXISTS sched_temp_recorded;");
4173 result.
prepare(
"CREATE TEMPORARY TABLE sched_temp_recorded " 4180 result.
prepare(
"INSERT sched_temp_recorded SELECT * from recorded;");
4194 result.
prepare(
"DROP TABLE IF EXISTS sched_temp_record;");
4199 result.
prepare(
"DROP TABLE IF EXISTS sched_temp_recorded;");
4207 if (schedTmpRecord ==
"record")
4208 schedTmpRecord =
"sched_temp_record";
4210 QString rmquery = QString(
4211 "UPDATE recordmatch " 4212 " INNER JOIN RECTABLE ON (recordmatch.recordid = RECTABLE.recordid) " 4213 " INNER JOIN program p ON (recordmatch.chanid = p.chanid AND " 4214 " recordmatch.starttime = p.starttime AND " 4215 " recordmatch.manualid = p.manualid) " 4216 " LEFT JOIN oldrecorded ON " 4218 " RECTABLE.dupmethod > 1 AND " 4219 " oldrecorded.duplicate <> 0 AND " 4220 " p.title = oldrecorded.title AND " 4224 " (p.programid <> '' " 4225 " AND p.programid = oldrecorded.programid) " 4229 " (p.programid = '' OR oldrecorded.programid = '' OR " 4230 " LEFT(p.programid, LOCATE('/', p.programid)) <> " 4231 " LEFT(oldrecorded.programid, LOCATE('/', oldrecorded.programid))) " :
4232 " (p.programid = '' OR oldrecorded.programid = '') " )
4235 " (((RECTABLE.dupmethod & 0x02) = 0) OR (p.subtitle <> '' " 4236 " AND p.subtitle = oldrecorded.subtitle)) " 4238 " (((RECTABLE.dupmethod & 0x04) = 0) OR (p.description <> '' " 4239 " AND p.description = oldrecorded.description)) " 4241 " (((RECTABLE.dupmethod & 0x08) = 0) OR " 4242 " (p.subtitle <> '' AND " 4243 " (p.subtitle = oldrecorded.subtitle OR " 4244 " (oldrecorded.subtitle = '' AND " 4245 " p.subtitle = oldrecorded.description))) OR " 4246 " (p.subtitle = '' AND p.description <> '' AND " 4247 " (p.description = oldrecorded.subtitle OR " 4248 " (oldrecorded.subtitle = '' AND " 4249 " p.description = oldrecorded.description)))) " 4253 " LEFT JOIN sched_temp_recorded recorded ON " 4255 " RECTABLE.dupmethod > 1 AND " 4256 " recorded.duplicate <> 0 AND " 4257 " p.title = recorded.title AND " 4258 " p.generic = 0 AND " 4259 " recorded.recgroup NOT IN ('LiveTV','Deleted') " 4262 " (p.programid <> '' " 4263 " AND p.programid = recorded.programid) " 4267 " (p.programid = '' OR recorded.programid = '' OR " 4268 " LEFT(p.programid, LOCATE('/', p.programid)) <> " 4269 " LEFT(recorded.programid, LOCATE('/', recorded.programid))) " :
4270 " (p.programid = '' OR recorded.programid = '') ")
4273 " (((RECTABLE.dupmethod & 0x02) = 0) OR (p.subtitle <> '' " 4274 " AND p.subtitle = recorded.subtitle)) " 4276 " (((RECTABLE.dupmethod & 0x04) = 0) OR (p.description <> '' " 4277 " AND p.description = recorded.description)) " 4279 " (((RECTABLE.dupmethod & 0x08) = 0) OR " 4280 " (p.subtitle <> '' AND " 4281 " (p.subtitle = recorded.subtitle OR " 4282 " (recorded.subtitle = '' AND " 4283 " p.subtitle = recorded.description))) OR " 4284 " (p.subtitle = '' AND p.description <> '' AND " 4285 " (p.description = recorded.subtitle OR " 4286 " (recorded.subtitle = '' AND " 4287 " p.description = recorded.description)))) " 4291 " LEFT JOIN oldfind ON " 4292 " (oldfind.recordid = recordmatch.recordid AND " 4293 " oldfind.findid = recordmatch.findid) " 4294 " SET oldrecduplicate = (oldrecorded.endtime IS NOT NULL), " 4295 " recduplicate = (recorded.endtime IS NOT NULL), " 4296 " findduplicate = (oldfind.findid IS NOT NULL), " 4297 " oldrecstatus = oldrecorded.recstatus " 4298 " WHERE p.endtime >= (NOW() - INTERVAL 480 MINUTE) " 4299 " AND oldrecduplicate = -1 " 4301 rmquery.replace(
"RECTABLE", schedTmpRecord);
4315 if (schedTmpRecord ==
"record")
4316 schedTmpRecord =
"sched_temp_record";
4318 struct timeval dbstart, dbend;
4322 QMap<int, bool> cardMap;
4323 QMap<int, EncoderLink *>::Iterator enciter =
m_tvList->begin();
4324 for (; enciter !=
m_tvList->end(); ++enciter)
4331 QMap<int, bool> tooManyMap;
4332 bool checkTooMany =
false;
4336 rlist.
prepare(QString(
"SELECT recordid, title, maxepisodes, maxnewest " 4337 "FROM %1").arg(schedTmpRecord));
4345 while (rlist.
next())
4347 int recid = rlist.
value(0).toInt();
4349 int maxEpisodes = rlist.
value(2).toInt();
4350 int maxNewest = rlist.
value(3).toInt();
4352 tooManyMap[recid] =
false;
4355 if (maxEpisodes && !maxNewest)
4359 epicnt.
prepare(
"SELECT DISTINCT chanid, progstart, progend " 4361 "WHERE recordid = :RECID AND preserve = 0 " 4362 "AND recgroup NOT IN ('LiveTV','Deleted');");
4367 if (epicnt.
size() >= maxEpisodes - 1)
4370 if (epicnt.
size() >= maxEpisodes)
4372 tooManyMap[recid] =
true;
4373 checkTooMany =
true;
4389 QString pwrpri =
"channel.recpriority + capturecard.recpriority";
4392 pwrpri += QString(
" + " 4393 "(capturecard.cardid = RECTABLE.prefinput) * %1").arg(prefinputpri);
4396 pwrpri += QString(
" + (program.hdtv > 0 OR " 4397 "FIND_IN_SET('HDTV', program.videoprop) > 0) * %1").arg(hdtvpriority);
4400 pwrpri += QString(
" + " 4401 "(FIND_IN_SET('WIDESCREEN', program.videoprop) > 0) * %1").arg(wspriority);
4404 pwrpri += QString(
" + " 4405 "(FIND_IN_SET('SIGNED', program.subtitletypes) > 0) * %1").arg(slpriority);
4408 pwrpri += QString(
" + " 4409 "(FIND_IN_SET('ONSCREEN', program.subtitletypes) > 0) * %1").arg(onscrpriority);
4412 pwrpri += QString(
" + " 4413 "(FIND_IN_SET('NORMAL', program.subtitletypes) > 0 OR " 4414 "program.closecaptioned > 0 OR program.subtitled > 0) * %1").arg(ccpriority);
4417 pwrpri += QString(
" + " 4418 "(FIND_IN_SET('HARDHEAR', program.subtitletypes) > 0 OR " 4419 "FIND_IN_SET('HARDHEAR', program.audioprop) > 0) * %1").arg(hhpriority);
4422 pwrpri += QString(
" + " 4423 "(FIND_IN_SET('VISUALIMPAIR', program.audioprop) > 0) * %1").arg(adpriority);
4427 result.
prepare(QString(
"SELECT recpriority, selectclause FROM %1;")
4436 while (result.
next())
4438 if (result.
value(0).toInt())
4440 QString sclause = result.
value(1).toString();
4441 sclause.remove(QRegExp(
"^\\s*AND\\s+", Qt::CaseInsensitive));
4442 sclause.remove(
';');
4443 pwrpri += QString(
" + (%1) * %2").arg(sclause)
4444 .arg(result.
value(0).toInt());
4447 pwrpri += QString(
" AS powerpriority ");
4449 pwrpri.replace(
"program.",
"p.");
4450 pwrpri.replace(
"channel.",
"c.");
4451 QString query = QString(
4453 " c.chanid, c.sourceid, p.starttime, " 4454 " p.endtime, p.title, p.subtitle, " 4455 " p.description, c.channum, c.callsign, " 4456 " c.name, oldrecduplicate, p.category, " 4457 " RECTABLE.recpriority, RECTABLE.dupin, recduplicate, " 4458 " findduplicate, RECTABLE.type, RECTABLE.recordid, " 4459 " p.starttime - INTERVAL RECTABLE.startoffset " 4460 " minute AS recstartts, " 4461 " p.endtime + INTERVAL RECTABLE.endoffset " 4462 " minute AS recendts, " 4463 " p.previouslyshown, " 4464 " RECTABLE.recgroup, RECTABLE.dupmethod, c.commmethod, " 4465 " capturecard.cardid, 0, p.seriesid, " 4466 " p.programid, RECTABLE.inetref, p.category_type, " 4467 " p.airdate, p.stars, p.originalairdate, " 4468 " RECTABLE.inactive, RECTABLE.parentid, recordmatch.findid, " 4469 " RECTABLE.playgroup, oldrecstatus.recstatus, " 4470 " oldrecstatus.reactivate, p.videoprop+0, " 4471 " p.subtitletypes+0, p.audioprop+0, RECTABLE.storagegroup, " 4472 " capturecard.hostname, recordmatch.oldrecstatus, NULL, " 4473 " oldrecstatus.future, capturecard.schedorder, " 4474 " p.syndicatedepisodenumber, p.partnumber, p.parttotal, " 4475 " c.mplexid, capturecard.displayname, " 4476 " p.season, p.episode, p.totalepisodes, ") +
4479 "INNER JOIN RECTABLE ON (recordmatch.recordid = RECTABLE.recordid) " 4480 "INNER JOIN program AS p " 4481 "ON ( recordmatch.chanid = p.chanid AND " 4482 " recordmatch.starttime = p.starttime AND " 4483 " recordmatch.manualid = p.manualid ) " 4484 "INNER JOIN channel AS c " 4485 "ON ( c.chanid = p.chanid ) " 4486 "INNER JOIN capturecard " 4487 "ON ( c.sourceid = capturecard.sourceid AND " 4488 " ( capturecard.schedorder <> 0 OR " 4489 " capturecard.parentid = 0 ) ) " 4490 "LEFT JOIN oldrecorded as oldrecstatus " 4491 "ON ( oldrecstatus.station = c.callsign AND " 4492 " oldrecstatus.starttime = p.starttime AND " 4493 " oldrecstatus.title = p.title ) " 4494 "WHERE p.endtime > (NOW() - INTERVAL 480 MINUTE) " 4495 "ORDER BY RECTABLE.recordid DESC, p.starttime, p.title, c.callsign, " 4497 query.replace(
"RECTABLE", schedTmpRecord);
4499 LOG(VB_SCHEDULE, LOG_INFO, QString(
" |-- Start DB Query..."));
4501 gettimeofday(&dbstart,
nullptr);
4508 gettimeofday(&dbend,
nullptr);
4510 LOG(VB_SCHEDULE, LOG_INFO,
4511 QString(
" |-- %1 results in %2 sec. Processing...")
4513 .arg(((dbend.tv_sec - dbstart.tv_sec) * 1000000 +
4514 (dbend.tv_usec - dbstart.tv_usec)) / 1000000.0));
4518 while (result.
next())
4524 uint recordid = result.
value(17).toUInt();
4526 QString title = result.
value(4).toString();
4527 QString callsign = result.
value(8).toString();
4531 && recordid == lastp->GetRecordingRuleID()
4532 && startts == lastp->GetScheduledStartTime()
4533 && title == lastp->GetTitle()
4534 && callsign == lastp->GetChannelSchedulingID())
4537 uint mplexid = result.
value(51).toUInt();
4538 if (mplexid == 32767)
4541 QString inputname = result.
value(52).toString();
4542 if (inputname.isEmpty())
4543 inputname = QString(
"Input %1").arg(result.
value(24).toUInt());
4548 result.
value(5).toString(),
4550 result.
value(6).toString(),
4551 result.
value(53).toInt(),
4552 result.
value(54).toInt(),
4553 result.
value(55).toInt(),
4554 result.
value(48).toString(),
4555 result.
value(11).toString(),
4557 result.
value(0).toUInt(),
4558 result.
value(7).toString(),
4560 result.
value(9).toString(),
4562 result.
value(21).toString(),
4563 result.
value(36).toString(),
4565 result.
value(43).toString(),
4566 result.
value(42).toString(),
4568 result.
value(30).toUInt(),
4569 result.
value(49).toUInt(),
4570 result.
value(50).toUInt(),
4572 result.
value(26).toString(),
4573 result.
value(27).toString(),
4574 result.
value(28).toString(),
4577 result.
value(12).toInt(),
4584 result.
value(31).toDouble(),
4585 (result.
value(32).isNull()) ? QDate() :
4589 result.
value(20).toInt(),
4592 result.
value(38).toInt(),
4595 result.
value(34).toUInt(),
4600 result.
value(1).toUInt(),
4601 result.
value(24).toUInt(),
4603 result.
value(35).toUInt(),
4606 result.
value(40).toUInt(),
4607 result.
value(39).toUInt(),
4608 result.
value(41).toUInt(),
4609 result.
value(46).toInt(),
4610 result.
value(47).toInt(),
4612 result.
value(24).toUInt(),
4630 for ( ; rec !=
worklist.end(); ++rec)
4652 tmpList.push_back(p);
4666 LOG(VB_GENERAL, LOG_WARNING,
LOC +
4667 QString(
"Channel %1, Title %2 %3 cardinput.schedorder = %4, " 4668 "it must be >0 to record from this input.")
4710 bool inactive = result.
value(33).toInt();
4727 tmpList.push_back(p);
4730 LOG(VB_SCHEDULE, LOG_INFO,
" +-- Cleanup...");
4732 for ( ;
tmp != tmpList.end(); ++
tmp)
4738 struct timeval dbstart, dbend;
4741 QString query = QString(
4742 "SELECT RECTABLE.title, RECTABLE.subtitle, " 4743 " RECTABLE.description, RECTABLE.season, " 4744 " RECTABLE.episode, RECTABLE.category, " 4745 " RECTABLE.chanid, channel.channum, " 4746 " RECTABLE.station, channel.name, " 4747 " RECTABLE.recgroup, RECTABLE.playgroup, " 4748 " RECTABLE.seriesid, RECTABLE.programid, " 4749 " RECTABLE.inetref, RECTABLE.recpriority, " 4750 " RECTABLE.startdate, RECTABLE.starttime, " 4751 " RECTABLE.enddate, RECTABLE.endtime, " 4752 " RECTABLE.recordid, RECTABLE.type, " 4753 " RECTABLE.dupin, RECTABLE.dupmethod, " 4754 " RECTABLE.findid, " 4755 " RECTABLE.startoffset, RECTABLE.endoffset, " 4756 " channel.commmethod " 4758 "INNER JOIN channel ON (channel.chanid = RECTABLE.chanid) " 4759 "LEFT JOIN recordmatch on RECTABLE.recordid = recordmatch.recordid " 4760 "WHERE (type = %1 OR type = %2) AND " 4761 " recordmatch.chanid IS NULL")
4767 LOG(VB_SCHEDULE, LOG_INFO, QString(
" |-- Start DB Query..."));
4769 gettimeofday(&dbstart,
nullptr);
4772 bool ok = result.
exec();
4773 gettimeofday(&dbend,
nullptr);
4781 LOG(VB_SCHEDULE, LOG_INFO,
4782 QString(
" |-- %1 results in %2 sec. Processing...")
4784 .arg(((dbend.tv_sec - dbstart.tv_sec) * 1000000 +
4785 (dbend.tv_usec - dbstart.tv_usec)) / 1000000.0));
4789 while (result.
next())
4793 result.
value(16).toDate(), result.
value(17).toTime(), Qt::UTC);
4795 result.
value(18).toDate(), result.
value(19).toTime(), Qt::UTC);
4797 QDateTime recstartts = startts.addSecs(result.
value(25).toInt() * -60);
4798 QDateTime recendts = endts.addSecs( result.
value(26).toInt() * +60);
4800 if (recstartts >= recendts)
4803 recstartts = startts;
4814 result.
value(0).toString(),
4816 (sor) ? result.
value(1).toString() : QString(),
4818 (sor) ? result.
value(2).toString() : QString(),
4819 result.
value(3).toUInt(),
4820 result.
value(4).toUInt(),
4823 result.
value(6).toUInt(),
4824 result.
value(7).toString(),
4825 result.
value(8).toString(),
4826 result.
value(9).toString(),
4828 result.
value(10).toString(),
4829 result.
value(11).toString(),
4831 result.
value(12).toString(),
4832 result.
value(13).toString(),
4833 result.
value(14).toString(),
4835 result.
value(15).toInt(),
4838 recstartts, recendts,
4842 result.
value(20).toUInt(),
4848 result.
value(24).toUInt(),
4852 tmpList.push_back(p);
4856 for ( ;
tmp != tmpList.end(); ++
tmp)
4867 QString sortColumn =
"title";
4875 sortColumn =
"record.title";
4878 sortColumn =
"record.recpriority";
4881 sortColumn =
"record.last_record";
4889 sortColumn =
"record.next_record IS NULL, record.next_record";
4892 sortColumn =
"record.type";
4896 QString order =
"ASC";
4900 QString query = QString(
4901 "SELECT record.title, record.subtitle, " 4902 " record.description, record.season, " 4903 " record.episode, record.category, " 4904 " record.chanid, channel.channum, " 4905 " record.station, channel.name, " 4906 " record.recgroup, record.playgroup, " 4907 " record.seriesid, record.programid, " 4908 " record.inetref, record.recpriority, " 4909 " record.startdate, record.starttime, " 4910 " record.enddate, record.endtime, " 4911 " record.recordid, record.type, " 4912 " record.dupin, record.dupmethod, " 4914 " channel.commmethod " 4916 "LEFT JOIN channel ON channel.callsign = record.station " 4917 "GROUP BY recordid " 4920 query = query.arg(sortColumn).arg(order);
4931 while (result.
next())
4934 QDateTime startts = QDateTime(result.
value(16).toDate(),
4935 result.
value(17).toTime(), Qt::UTC);
4936 QDateTime endts = QDateTime(result.
value(18).toDate(),
4937 result.
value(19).toTime(), Qt::UTC);
4939 if (!startts.isValid())
4942 if (!endts.isValid())
4946 result.
value(0).toString(), QString(),
4947 result.
value(1).toString(), QString(),
4948 result.
value(2).toString(), result.
value(3).toUInt(),
4949 result.
value(4).toUInt(), result.
value(5).toString(),
4951 result.
value(6).toUInt(), result.
value(7).toString(),
4952 result.
value(8).toString(), result.
value(9).toString(),
4954 result.
value(10).toString(), result.
value(11).toString(),
4956 result.
value(12).toString(), result.
value(13).toString(),
4957 result.
value(14).toString(),
4959 result.
value(15).toInt(),
4966 result.
value(20).toUInt(), rectype,
4970 result.
value(24).toUInt(),
4991 else if (a->
isLocal() ==
b->isLocal())
5006 else if (!a->
isLocal() &&
b->isLocal())
5023 if (
b->getTotalSpace() == 0)
5027 (
b->getFreeSpace() * 100.0) /
b->getTotalSpace())
5072 QString recording_dir;
5076 "LiveTV", cur, cur.addSecs(3600), cardid,
5081 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"FindNextLiveTVDir: next dir is '%1'")
5082 .arg(recording_dir));
5089 const QString &title,
5091 const QString &storagegroup,
5092 const QDateTime &recstartts,
5093 const QDateTime &recendts,
5095 QString &recording_dir,
5098 LOG(VB_SCHEDULE, LOG_INFO,
LOC +
"FillRecordingDir: Starting");
5103 if (cnt++ % 20 == 0)
5104 LOG(VB_SCHEDULE, LOG_WARNING,
"Waiting for main server.");
5105 std::this_thread::sleep_for(std::chrono::milliseconds(50));
5110 QMap<QString, FileSystemInfo>::Iterator fsit;
5111 QMap<QString, FileSystemInfo>::Iterator fsit2;
5114 QStringList recsCounted;
5115 list<FileSystemInfo *> fsInfoList;
5116 list<FileSystemInfo *>::iterator fslistit;
5118 recording_dir.clear();
5120 if (dirlist.size() == 1)
5122 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5123 QString(
"FillRecordingDir: The only directory in the %1 Storage " 5124 "Group is %2, so it will be used by default.")
5125 .arg(storagegroup) .arg(dirlist[0]));
5126 recording_dir = dirlist[0];
5127 LOG(VB_SCHEDULE, LOG_INFO,
LOC +
"FillRecordingDir: Finished");
5132 int weightPerRecording =
5134 int weightPerPlayback =
5136 int weightPerCommFlag =
5138 int weightPerTranscode =
5141 QString storageScheduler =
5143 int localStartingWeight =
5145 (storageScheduler !=
"Combination") ? 0
5146 : (
int)(-1.99 * weightPerRecording));
5147 int remoteStartingWeight =
5153 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5154 "FillRecordingDir: Calculating initial FS Weights.");
5161 QString msg = QString(
" %1:%2").arg(fs->
getHostname())
5165 tmpWeight = localStartingWeight;
5166 msg +=
" is local (" + QString::number(tmpWeight) +
")";
5170 tmpWeight = remoteStartingWeight;
5171 msg +=
" is remote (+" + QString::number(tmpWeight) +
")";
5181 msg +=
", has SGweightPerDir offset of " 5182 + QString::number(tmpWeight) +
")";
5184 msg +=
". initial dir weight = " + QString::number(fs->
getWeight());
5185 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, msg);
5187 fsInfoList.push_back(fs);
5190 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5191 "FillRecordingDir: Adjusting FS Weights from inuseprograms.");
5194 saveRecDir.
prepare(
"UPDATE inuseprograms " 5195 "SET recdir = :RECDIR " 5196 "WHERE chanid = :CHANID AND " 5197 " starttime = :STARTTIME");
5200 "SELECT i.chanid, i.starttime, r.endtime, recusage, rechost, recdir " 5201 "FROM inuseprograms i, recorded r " 5202 "WHERE DATE_ADD(lastupdatetime, INTERVAL 16 MINUTE) > NOW() AND " 5203 " i.chanid = r.chanid AND " 5204 " i.starttime = r.starttime");
5212 while (query.
next())
5214 uint recChanid = query.
value(0).toUInt();
5217 QString recUsage( query.
value(3).toString());
5218 QString recHost( query.
value(4).toString());
5219 QString recDir( query.
value(5).toString());
5221 if (recDir.isEmpty())
5225 recDir = recDir.isEmpty() ?
"_UNKNOWN_" : recDir;
5227 saveRecDir.
bindValue(
":RECDIR", recDir);
5228 saveRecDir.
bindValue(
":CHANID", recChanid);
5229 saveRecDir.
bindValue(
":STARTTIME", recStart);
5230 if (!saveRecDir.
exec())
5233 if (recDir ==
"_UNKNOWN_")
5236 for (fslistit = fsInfoList.begin();
5237 fslistit != fsInfoList.end(); ++fslistit)
5243 int weightOffset = 0;
5247 if (recEnd > recstartts.addSecs(maxOverlap))
5249 weightOffset += weightPerRecording;
5250 recsCounted << QString::number(recChanid) +
":" +
5255 weightOffset += weightPerPlayback;
5257 weightOffset += weightPerCommFlag;
5259 weightOffset += weightPerTranscode;
5263 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
5264 QString(
" %1 @ %2 in use by '%3' on %4:%5, FSID " 5265 "#%6, FSID weightOffset +%7.")
5268 .arg(recUsage).arg(recHost).arg(recDir)
5269 .arg(fs->
getFSysID()).arg(weightOffset));
5278 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
5279 QString(
" %1:%2 => old weight %3 plus " 5281 .arg(
fs2->getHostname())
5282 .arg(
fs2->getPath())
5283 .arg(
fs2->getWeight())
5285 .arg(
fs2->getWeight() + weightOffset));
5287 fs2->setWeight(
fs2->getWeight() + weightOffset);
5297 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5298 "FillRecordingDir: Adjusting FS Weights from scheduler.");
5304 if ((recendts < thispg->GetRecordingStartTime()) ||
5309 (recsCounted.contains(QString(
"%1:%2").arg(thispg->
GetChanID())
5314 for (fslistit = fsInfoList.begin();
5315 fslistit != fsInfoList.end(); ++fslistit)
5321 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
5322 QString(
"%1 @ %2 will record on %3:%4, FSID #%5, " 5323 "weightPerRecording +%6.")
5327 .arg(fs->
getFSysID()).arg(weightPerRecording));
5335 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
5336 QString(
" %1:%2 => old weight %3 plus %4 = %5")
5337 .arg(
fs2->getHostname()).arg(
fs2->getPath())
5338 .arg(
fs2->getWeight()).arg(weightPerRecording)
5339 .arg(
fs2->getWeight() + weightPerRecording));
5341 fs2->setWeight(
fs2->getWeight() + weightPerRecording);
5349 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
5350 QString(
"Using '%1' Storage Scheduler directory sorting algorithm.")
5351 .arg(storageScheduler));
5353 if (storageScheduler ==
"BalancedFreeSpace")
5355 else if (storageScheduler ==
"BalancedPercFreeSpace")
5357 else if (storageScheduler ==
"BalancedDiskIO")
5364 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
5365 "--- FillRecordingDir Sorted fsInfoList start ---");
5366 for (fslistit = fsInfoList.begin();fslistit != fsInfoList.end();
5370 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, QString(
"%1:%2")
5372 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, QString(
" Location : %1")
5373 .arg((fs->
isLocal()) ?
"local" :
"remote"));
5374 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, QString(
" weight : %1")
5376 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, QString(
" free space : %5")
5379 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
5380 "--- FillRecordingDir Sorted fsInfoList end ---");
5389 long long maxSizeKB = (maxByterate + maxByterate/3) *
5390 recstartts.secsTo(recendts) / 1024;
5392 bool simulateAutoExpire =
5395 (fsInfoList.size() > 1));
5409 for (
unsigned int pass = 1; pass <= 3; pass++)
5411 bool foundDir =
false;
5413 if ((pass == 2) && simulateAutoExpire)
5416 QMap <int , long long> remainingSpaceKB;
5417 for (fslistit = fsInfoList.begin();
5418 fslistit != fsInfoList.end(); ++fslistit)
5420 remainingSpaceKB[(*fslistit)->getFSysID()] =
5421 (*fslistit)->getFreeSpace();
5428 for(pginfolist_t::iterator it=expiring.begin();
5429 it != expiring.end(); ++it)
5433 for (fslistit = fsInfoList.begin();
5434 fslistit != fsInfoList.end(); ++fslistit)
5437 if ((*it)->GetHostname() != (*fslistit)->getHostname())
5441 if (!dirlist.contains((*fslistit)->getPath()))
5445 (*fslistit)->
getPath() +
"/" + (*it)->GetPathname();
5450 QFile checkFile(filename);
5452 if (checkFile.exists())
5460 QString backuppath = (*it)->GetPathname();
5462 bool foundSlave =
false;
5464 QMap<int, EncoderLink *>::Iterator enciter =
5466 for (; enciter !=
m_tvList->end(); ++enciter)
5468 if ((*enciter)->GetHostName() ==
5471 (*enciter)->CheckFile(programinfo);
5489 LOG(VB_GENERAL, LOG_ERR,
5490 QString(
"Unable to match '%1' " 5491 "to any file system. Ignoring it.")
5492 .arg((*it)->GetBasename()));
5498 (*it)->GetFilesize() / 1024;
5501 long long desiredSpaceKB =
5505 (desiredSpaceKB + maxSizeKB))
5507 recording_dir = fs->
getPath();
5510 LOG(VB_FILE, LOG_INFO,
5511 QString(
"pass 2: '%1' will record in '%2' " 5512 "although there is only %3 MB free and the " 5513 "AutoExpirer wants at least %4 MB. This " 5514 "directory has the highest priority files " 5515 "to be expired from the AutoExpire list and " 5516 "there are enough that the Expirer should " 5517 "be able to free up space for this recording.")
5518 .arg(title).arg(recording_dir)
5520 .arg(desiredSpaceKB / 1024));
5531 for (fslistit = fsInfoList.begin();
5532 fslistit != fsInfoList.end(); ++fslistit)
5534 long long desiredSpaceKB = 0;
5541 (dirlist.contains(fs->
getPath())) &&
5545 recording_dir = fs->
getPath();
5549 LOG(VB_FILE, LOG_INFO,
5550 QString(
"pass 1: '%1' will record in " 5551 "'%2' which has %3 MB free. This recording " 5552 "could use a max of %4 MB and the " 5553 "AutoExpirer wants to keep %5 MB free.")
5557 .arg(maxSizeKB / 1024)
5558 .arg(desiredSpaceKB / 1024));
5560 LOG(VB_FILE, LOG_INFO,
5561 QString(
"pass %1: '%2' will record in " 5562 "'%3' although there is only %4 MB free and " 5563 "the AutoExpirer wants at least %5 MB. " 5564 "Something will have to be deleted or expired " 5565 "in order for this recording to complete " 5567 .arg(pass).arg(title)
5570 .arg(desiredSpaceKB / 1024));
5582 LOG(VB_SCHEDULE, LOG_INFO,
LOC +
"FillRecordingDir: Finished");
5588 QList<FileSystemInfo> fsInfos;
5595 QMap <int, bool> fsMap;
5596 QList<FileSystemInfo>::iterator it1;
5597 for (it1 = fsInfos.begin(); it1 != fsInfos.end(); ++it1)
5599 fsMap[it1->getFSysID()] =
true;
5600 fsInfoCache[it1->getHostname() +
":" + it1->getPath()] = *it1;
5603 LOG(VB_FILE, LOG_INFO,
LOC +
5604 QString(
"FillDirectoryInfoCache: found %1 unique filesystems")
5605 .arg(fsMap.size()));
5616 if (secsleft - prerollseconds > 120)
5620 QMap<int, EncoderLink *>::Iterator enciter =
m_tvList->begin();
5621 for (; enciter !=
m_tvList->end(); ++enciter)
5666 bool autoStart =
false;
5668 QDateTime startupTime = QDateTime();
5674 if (startupTime.isValid())
5682 max(startupSecs, 15 * 60))
5684 LOG(VB_GENERAL, LOG_INFO,
5685 "Close to auto-start time, AUTO-Startup assumed");
5690 max(startupSecs, 15 * 60))
5692 LOG(VB_GENERAL, LOG_INFO,
5693 "Close to MythFillDB suggested run time, AUTO-Startup to fetch guide data?");
5698 LOG(VB_GENERAL, LOG_DEBUG,
5699 "NOT close to auto-start time, USER-initiated startup assumed");
5701 else if (!s.isEmpty())
5702 LOG(VB_GENERAL, LOG_ERR,
LOC +
5703 QString(
"Invalid MythShutdownWakeupTime specified in database (%1)")
5714 QMap<uint, QSet<uint> > inputSets;
5715 query.
prepare(
"SELECT DISTINCT ci1.cardid, ci2.cardid " 5716 "FROM capturecard ci1, capturecard ci2, " 5717 " inputgroup ig1, inputgroup ig2 " 5718 "WHERE ci1.cardid = ig1.cardinputid AND " 5719 " ci2.cardid = ig2.cardinputid AND" 5720 " ig1.inputgroupid = ig2.inputgroupid AND " 5721 " ci1.cardid <= ci2.cardid " 5722 "ORDER BY ci1.cardid, ci2.cardid");
5728 while (query.
next())
5732 inputSets[id0].insert(id1);
5733 inputSets[id1].insert(id0);
5736 QMap<uint, QSet<uint> >::iterator mit;
5737 for (mit = inputSets.begin(); mit != inputSets.end(); ++mit)
5739 uint inputid = mit.key();
5747 QSet<uint> fullset = mit.value();
5748 QSet<uint> checkset;
5749 QSet<uint>::const_iterator sit;
5750 while (checkset != fullset)
5753 for (sit = checkset.begin(); sit != checkset.end(); ++sit)
5754 fullset += inputSets[*sit];
5761 for (sit = checkset.begin(); sit != checkset.end(); ++sit)
5763 LOG(VB_SCHEDULE, LOG_INFO,
5764 QString(
"Assigning input %1 to conflict set %2")