MythTV  master
recordingrule.cpp
Go to the documentation of this file.
1 
2 #include "recordingrule.h"
3 
4 #include <utility>
5 
6 // libmythbase
7 #include "mythdb.h"
8 
9 // libmyth
10 #include "mythcorecontext.h"
11 
12 // libmythtv
13 #include "scheduledrecording.h" // For RescheduleMatch()
14 #include "playgroup.h" // For GetInitialName()
15 #include "recordingprofile.h" // For constants
16 #include "mythdate.h"
17 #include "mythsorthelper.h"
18 
19 static inline QString null_to_empty(const QString &str)
20 {
21  return str.isEmpty() ? "" : str;
22 }
23 
24 // If the GetNumSetting() calls here are ever removed, update schema
25 // upgrade 1302 in dbcheck.cpp to manually apply them to the Default
26 // template. Failing to do so will cause users upgrading from older
27 // versions to lose those settings.
28 
30  : m_findtime(QTime::fromString("00:00:00", Qt::ISODate)),
31  m_findid(QDate(1970, 1, 1).daysTo(MythDate::current().toLocalTime().date())
32  + 719528),
33  m_transcoder(RecordingProfile::kTranscoderAutodetect)
34 {
35  QDateTime dt = MythDate::current();
36  m_enddate = m_startdate = dt.date();
37  m_endtime = m_starttime = dt.time();
38 
40 }
41 
46 {
47  std::shared_ptr<MythSortHelper>sh = getMythSortHelper();
48 
49  if (m_sortTitle.isEmpty() and not m_title.isEmpty())
50  m_sortTitle = sh->doTitle(m_title);
51  if (m_sortSubtitle.isEmpty() and not m_subtitle.isEmpty())
52  m_sortSubtitle = sh->doTitle(m_subtitle);
53 }
54 
58 bool RecordingRule::Load(bool asTemplate)
59 {
60  if (m_recordID <= 0)
61  return false;
62 
64  query.prepare("SELECT type, search, "
65  "recpriority, prefinput, startoffset, endoffset, dupmethod, dupin, "
66  "inactive, profile, recgroup, storagegroup, playgroup, autoexpire, "
67  "maxepisodes, maxnewest, autocommflag, autotranscode, transcoder, "
68  "autouserjob1, autouserjob2, autouserjob3, autouserjob4, "
69  "autometadata, parentid, title, subtitle, description, season, episode, "
70  "category, starttime, startdate, endtime, enddate, seriesid, programid, "
71  "inetref, chanid, station, findday, findtime, findid, "
72  "next_record, last_record, last_delete, avg_delay, filter, recgroupid "
73  "FROM record WHERE recordid = :RECORDID ;");
74 
75  query.bindValue(":RECORDID", m_recordID);
76 
77  if (!query.exec())
78  {
79  MythDB::DBError("SELECT record", query);
80  return false;
81  }
82 
83  if (!query.next())
84  return false;
85 
86  // Schedule
87  if (!asTemplate)
88  {
89  m_type = static_cast<RecordingType>(query.value(0).toInt());
90  m_searchType = static_cast<RecSearchType>(query.value(1).toInt());
91  }
92  m_recPriority = query.value(2).toInt();
93  m_prefInput = query.value(3).toInt();
94  m_startOffset = query.value(4).toInt();
95  m_endOffset = query.value(5).toInt();
96  m_dupMethod = static_cast<RecordingDupMethodType>
97  (query.value(6).toInt());
98  m_dupIn = static_cast<RecordingDupInType>(query.value(7).toInt());
99  m_filter = query.value(47).toUInt();
100  m_isInactive = query.value(8).toBool();
101 
102  // Storage
103  m_recProfile = query.value(9).toString();
104  m_recGroupID = query.value(48).toUInt();
105  m_storageGroup = query.value(11).toString();
106  m_playGroup = query.value(12).toString();
107  m_autoExpire = query.value(13).toBool();
108  m_maxEpisodes = query.value(14).toInt();
109  m_maxNewest = query.value(15).toBool();
110 
111  // Post Process
112  m_autoCommFlag = query.value(16).toBool();
113  m_autoTranscode = query.value(17).toBool();
114  m_transcoder = query.value(18).toInt();
115  m_autoUserJob1 = query.value(19).toBool();
116  m_autoUserJob2 = query.value(20).toBool();
117  m_autoUserJob3 = query.value(21).toBool();
118  m_autoUserJob4 = query.value(22).toBool();
119  m_autoMetadataLookup = query.value(23).toBool();
120 
121  if (!asTemplate)
122  {
123  // Original rule id for override rule
124  m_parentRecID = query.value(24).toInt();
125 
126  // Recording metadata
127  m_title = query.value(25).toString();
128  m_subtitle = query.value(26).toString();
129  m_description = query.value(27).toString();
130  m_season = query.value(28).toUInt();
131  m_episode = query.value(29).toUInt();
132  m_category = query.value(30).toString();
133  m_starttime = query.value(31).toTime();
134  m_startdate = query.value(32).toDate();
135  m_endtime = query.value(33).toTime();
136  m_enddate = query.value(34).toDate();
137  m_seriesid = query.value(35).toString();
138  m_programid = query.value(36).toString();
139  m_inetref = query.value(37).toString();
140 
141  // Associated data for rule types
142  m_channelid = query.value(38).toInt();
143  m_station = query.value(39).toString();
144  m_findday = query.value(40).toInt();
145  m_findtime = query.value(41).toTime();
146  m_findid = query.value(42).toInt();
147 
148  // Statistic fields - Used to generate statistics about particular rules
149  // and influence watch list weighting
150  m_nextRecording = MythDate::as_utc(query.value(43).toDateTime());
151  m_lastRecorded = MythDate::as_utc(query.value(44).toDateTime());
152  m_lastDeleted = MythDate::as_utc(query.value(45).toDateTime());
153  m_averageDelay = query.value(46).toInt();
154  }
155 
158  m_template = (asTemplate || m_isTemplate) ?
159  query.value(30).toString() : "";
160 
161  if (!asTemplate)
162  m_loaded = true;
163 
165  return true;
166 }
167 
169 {
170  if (!proginfo)
171  return false;
172 
173  m_progInfo = proginfo;
174 
175  m_recordID = proginfo->GetRecordingRuleID();
176  if (m_recordID)
177  {
178  if (!Load())
179  return false;
180  }
181  else
182  LoadTemplate(proginfo->GetCategory(), proginfo->GetCategoryTypeString());
183 
184  if (m_type != kTemplateRecord &&
186  {
188  if (!proginfo->GetRecordingRuleID())
190  }
191 
193  m_loaded = true;
194  return true;
195 }
196 
213 bool RecordingRule::LoadBySearch(RecSearchType lsearch, const QString& textname,
214  const QString& forwhat, QString joininfo,
215  ProgramInfo *pginfo)
216 {
218 
219  int rid = 0;
220  query.prepare("SELECT recordid FROM record WHERE "
221  "search = :SEARCH AND description LIKE :FORWHAT");
222  query.bindValue(":SEARCH", lsearch);
223  query.bindValue(":FORWHAT", forwhat);
224 
225  if (query.exec())
226  {
227  if (query.next())
228  rid = query.value(0).toInt();
229  // else rid is zero, which is valid, we're looking at a new rule
230  }
231  else
232  {
233  MythDB::DBError("loadBySearch", query);
234  return false;
235  }
236 
237  if (rid)
238  {
239  m_recordID = rid;
240  if (!Load())
241  return false;
242  }
243  else
244  {
245  LoadTemplate("Default");
246 
247  QString searchType;
248  m_searchType = lsearch;
249  searchType = SearchTypeToString(m_searchType);
250 
251  QString ltitle = QString("%1 (%2)").arg(textname).arg(searchType);
252  m_title = ltitle;
253  m_sortTitle = nullptr;
254  m_subtitle = m_sortSubtitle = std::move(joininfo);
255  m_description = forwhat;
256 
257  if (pginfo)
258  {
259  m_findday =
260  (pginfo->GetScheduledStartTime().toLocalTime().date()
261  .dayOfWeek() + 1) % 7;
262  m_findtime = pginfo->GetScheduledStartTime().toLocalTime().time();
263  m_findid = QDate(1970, 1, 1).daysTo(
264  pginfo->GetScheduledStartTime().toLocalTime().date()) + 719528;
265  }
266  }
267 
269  m_loaded = true;
270  return true;
271 }
272 
273 bool RecordingRule::LoadTemplate(const QString& category, const QString& categoryType)
274 {
275  QString lcategory = category.isEmpty() ? "Default" : category;
276  QString lcategoryType = categoryType.isEmpty() ? "Default" : categoryType;
277 
279  query.prepare("SELECT recordid, category, "
280  " (category = :CAT1) AS catmatch, "
281  " (category = :CATTYPE1) AS typematch "
282  "FROM record "
283  "WHERE type = :TEMPLATE AND "
284  " (category = :CAT2 OR category = :CATTYPE2 "
285  " OR category = 'Default') "
286  "ORDER BY catmatch DESC, typematch DESC"
287  );
288  query.bindValue(":TEMPLATE", kTemplateRecord);
289  query.bindValue(":CAT1", lcategory);
290  query.bindValue(":CAT2", lcategory);
291  query.bindValue(":CATTYPE1", lcategoryType);
292  query.bindValue(":CATTYPE2", lcategoryType);
293 
294  if (!query.exec())
295  {
296  MythDB::DBError("LoadByTemplate", query);
297  return false;
298  }
299 
300  if (!query.next())
301  return false;
302 
303  int savedRecordID = m_recordID;
304  m_recordID = query.value(0).toInt();
305  bool result = Load(true);
306  m_recordID = savedRecordID;
307 
308  return result;
309 }
310 
312 {
313  if (m_recordID > 0)
314  return false;
315 
316  if (category.compare(tr("Default"), Qt::CaseInsensitive) == 0)
317  {
318  category = "Default";
319  m_title = tr("Default (Template)");
321  }
322  else
323  {
324  //: %1 is the category
325  m_title = tr("%1 (Template)").arg(category);
327  }
328 
330  m_recordID = 0;
333  m_loaded = true;
334  m_isTemplate = true;
335 
336  return true;
337 }
338 
339 bool RecordingRule::ModifyPowerSearchByID(int rid, const QString& textname,
340  QString forwhat, QString joininfo)
341 {
342  if (rid <= 0)
343  return false;
344 
345  m_recordID = rid;
346  if (!Load() || m_searchType != kPowerSearch)
347  return false;
348 
349  QString ltitle = QString("%1 (%2)").arg(textname)
350  .arg(tr("Power Search"));
351  m_title = ltitle;
352  m_sortTitle = nullptr;
353  m_subtitle = m_sortSubtitle = std::move(joininfo);
354  m_description = std::move(forwhat);
355 
357  m_loaded = true;
358  return true;
359 }
360 
362 {
363  if (m_recordID <= 0)
364  return false;
365 
367  return false;
368 
369  m_isOverride = true;
371  m_recordID = 0;
373  m_isInactive = false;
374 
377 
379 
380  return true;
381 }
382 
383 bool RecordingRule::Save(bool sendSig)
384 {
385  QString sql = "SET type = :TYPE, search = :SEARCHTYPE, "
386  "recpriority = :RECPRIORITY, prefinput = :INPUT, "
387  "startoffset = :STARTOFFSET, endoffset = :ENDOFFSET, "
388  "dupmethod = :DUPMETHOD, dupin = :DUPIN, "
389  "filter = :FILTER, "
390  "inactive = :INACTIVE, profile = :RECPROFILE, "
391  "recgroup = :RECGROUP, "
392  "recgroupid = :RECGROUPID, "
393  "storagegroup = :STORAGEGROUP, "
394  "playgroup = :PLAYGROUP, autoexpire = :AUTOEXPIRE, "
395  "maxepisodes = :MAXEPISODES, maxnewest = :MAXNEWEST, "
396  "autocommflag = :AUTOCOMMFLAG, "
397  "autotranscode = :AUTOTRANSCODE, "
398  "transcoder = :TRANSCODER, autouserjob1 = :AUTOUSERJOB1, "
399  "autouserjob2 = :AUTOUSERJOB2, "
400  "autouserjob3 = :AUTOUSERJOB3, "
401  "autouserjob4 = :AUTOUSERJOB4, "
402  "autometadata = :AUTOMETADATA, "
403  "parentid = :PARENTID, title = :TITLE, "
404  "subtitle = :SUBTITLE, season = :SEASON, episode = :EPISODE, "
405  "description = :DESCRIPTION, category = :CATEGORY, "
406  "starttime = :STARTTIME, startdate = :STARTDATE, "
407  "endtime = :ENDTIME, enddate = :ENDDATE, seriesid = :SERIESID, "
408  "programid = :PROGRAMID, inetref = :INETREF, chanid = :CHANID, "
409  "station = :STATION, findday = :FINDDAY, "
410  "findtime = :FINDTIME, findid = :FINDID, "
411  "next_record = :NEXTREC, last_record = :LASTREC, "
412  "last_delete = :LASTDELETE, avg_delay = :AVGDELAY ";
413 
414  QString sqlquery;
415  if (m_recordID > 0 || (m_recordTable != "record" && m_tempID > 0))
416  {
417  sqlquery = QString("UPDATE %1 %2 WHERE recordid = :RECORDID;")
418  .arg(m_recordTable).arg(sql);
419  }
420  else
421  {
422  sqlquery = QString("INSERT INTO %1 %2;").arg(m_recordTable).arg(sql);
423  }
424 
426  query.prepare(sqlquery);
427  query.bindValue(":TYPE", m_type);
428  query.bindValue(":SEARCHTYPE", m_searchType);
429  query.bindValue(":RECPRIORITY", m_recPriority);
430  query.bindValue(":INPUT", m_prefInput);
431  query.bindValue(":STARTOFFSET", m_startOffset);
432  query.bindValue(":ENDOFFSET", m_endOffset);
433  query.bindValue(":DUPMETHOD", m_dupMethod);
434  query.bindValue(":DUPIN", m_dupIn);
435  query.bindValue(":FILTER", m_filter);
436  query.bindValue(":INACTIVE", m_isInactive);
437  query.bindValue(":RECPROFILE", null_to_empty(m_recProfile));
438  // Temporary, remove once transition to recgroupid is complete
440  query.bindValue(":RECGROUPID", m_recGroupID);
441  query.bindValue(":STORAGEGROUP", null_to_empty(m_storageGroup));
442  query.bindValue(":PLAYGROUP", null_to_empty(m_playGroup));
443  query.bindValue(":AUTOEXPIRE", m_autoExpire);
444  query.bindValue(":MAXEPISODES", m_maxEpisodes);
445  query.bindValue(":MAXNEWEST", m_maxNewest);
446  query.bindValue(":AUTOCOMMFLAG", m_autoCommFlag);
447  query.bindValue(":AUTOTRANSCODE", m_autoTranscode);
448  query.bindValue(":TRANSCODER", m_transcoder);
449  query.bindValue(":AUTOUSERJOB1", m_autoUserJob1);
450  query.bindValue(":AUTOUSERJOB2", m_autoUserJob2);
451  query.bindValue(":AUTOUSERJOB3", m_autoUserJob3);
452  query.bindValue(":AUTOUSERJOB4", m_autoUserJob4);
453  query.bindValue(":AUTOMETADATA", m_autoMetadataLookup);
454  query.bindValue(":PARENTID", m_parentRecID);
455  query.bindValue(":TITLE", m_title);
456  query.bindValue(":SUBTITLE", null_to_empty(m_subtitle));
457  query.bindValue(":DESCRIPTION", null_to_empty(m_description));
458  query.bindValue(":SEASON", m_season);
459  query.bindValue(":EPISODE", m_episode);
460  query.bindValue(":CATEGORY", null_to_empty(m_category));
461  query.bindValue(":STARTTIME", m_starttime);
462  query.bindValue(":STARTDATE", m_startdate);
463  query.bindValue(":ENDTIME", m_endtime);
464  query.bindValue(":ENDDATE", m_enddate);
465  query.bindValue(":SERIESID", null_to_empty(m_seriesid));
466  query.bindValue(":PROGRAMID", null_to_empty(m_programid));
467  query.bindValue(":INETREF", null_to_empty(m_inetref));
468  query.bindValue(":CHANID", m_channelid);
469  query.bindValue(":STATION", null_to_empty(m_station));
470  query.bindValue(":FINDDAY", m_findday);
471  query.bindValue(":FINDTIME", m_findtime);
472  query.bindValue(":FINDID", m_findid);
473  query.bindValue(":NEXTREC", m_nextRecording);
474  query.bindValue(":LASTREC", m_lastRecorded);
475  query.bindValue(":LASTDELETE", m_lastDeleted);
476  query.bindValue(":AVGDELAY", m_averageDelay);
477 
478  if (m_recordTable != "record" && m_tempID > 0)
479  query.bindValue(":RECORDID", m_tempID);
480  else if (m_recordID > 0)
481  query.bindValue(":RECORDID", m_recordID);
482 
483  if (!query.exec())
484  {
485  MythDB::DBError("UPDATE/INSERT record", query);
486  return false;
487  }
488 
489  if (m_recordTable != "record" && m_tempID <= 0)
490  m_tempID = query.lastInsertId().toInt();
491  else if (m_recordID <= 0)
492  m_recordID = query.lastInsertId().toInt();
493 
494  if (sendSig)
496  QString("SaveRule %1").arg(m_title));
497 
498  return true;
499 }
500 
501 bool RecordingRule::Delete(bool sendSig)
502 {
503  if (m_recordID < 0)
504  return false;
505 
507  query.prepare("DELETE FROM record WHERE recordid = :RECORDID");
508  query.bindValue(":RECORDID", m_recordID);
509  if (!query.exec())
510  {
511  MythDB::DBError("ScheduledRecording::remove -- record", query);
512  return false;
513  }
514 
515  query.prepare("DELETE FROM oldfind WHERE recordid = :RECORDID");
516  query.bindValue(":RECORDID", m_recordID);
517  if (!query.exec())
518  {
519  MythDB::DBError("ScheduledRecording::remove -- oldfind", query);
520  }
521 
523  {
524  query.prepare("DELETE FROM program WHERE manualid = :RECORDID");
525  query.bindValue(":RECORDID", m_recordID);
526  if (!query.exec())
527  {
528  MythDB::DBError("ScheduledRecording::remove -- oldfind", query);
529  }
530  }
531 
532  if (sendSig)
534  QString("DeleteRule %1").arg(m_title));
535 
536  // Set m_recordID to zero, the rule is no longer in the database so it's
537  // not valid. Should you want, this allows a rule to be removed from the
538  // database and then re-inserted with Save()
539  m_recordID = 0;
540 
541  return true;
542 }
543 
544 void RecordingRule::ToMap(InfoMap &infoMap) const
545 {
546  if (m_title == "Default (Template)")
547  {
548  infoMap["title"] = tr("Default (Template)");
549  infoMap["sorttitle"] = tr("Default (Template)");
550  }
551  else
552  {
553  infoMap["title"] = m_title;
554  infoMap["sorttitle"] = m_sortTitle;
555  }
556  infoMap["subtitle"] = m_subtitle;
557  infoMap["sortsubtitle"] = m_sortSubtitle;
558  infoMap["description"] = m_description;
559  infoMap["season"] = QString::number(m_season);
560  infoMap["episode"] = QString::number(m_episode);
561 
562  if (m_category == "Default")
563  infoMap["category"] = tr("Default", "category");
564  else
565  infoMap["category"] = m_category;
566  infoMap["callsign"] = m_station;
567 
568  QDateTime starttm(m_startdate, m_starttime, Qt::UTC);
569  infoMap["starttime"] = MythDate::toString(starttm, MythDate::kTime);
570  infoMap["startdate"] = MythDate::toString(
572 
573  QDateTime endtm(m_enddate, m_endtime, Qt::UTC);
574  infoMap["endtime"] = MythDate::toString(endtm, MythDate::kTime);
575  infoMap["enddate"] = MythDate::toString(
577 
578  infoMap["inetref"] = m_inetref;
579  infoMap["chanid"] = m_channelid;
580  infoMap["channel"] = m_station;
581 
582  QDateTime startts(m_startdate, m_starttime, Qt::UTC);
583  QDateTime endts(m_enddate, m_endtime, Qt::UTC);
584 
585  int seconds = startts.secsTo(endts);
586  int minutes = seconds / 60;
587  int hours = minutes / 60;
588  minutes = minutes % 60;
589 
590  infoMap["lenmins"] = QCoreApplication::translate("(Common)", "%n minute(s)",
591  "", minutes);
592 
593  QString minstring = QCoreApplication::translate("(Common)", "%n minute(s)",
594  "", minutes);
595 
596  QString hourstring = QCoreApplication::translate("(Common)", "%n hour(s)",
597  "", hours);
598 
599  if (hours > 0)
600  {
601  //: Time duration, %1 is replaced by the hours, %2 by the minutes
602  infoMap["lentime"] = QCoreApplication::translate("(Common)", "%1 %2",
603  "Hours and minutes").arg(hourstring).arg(minstring);
604  }
605  else
606  infoMap["lentime"] = minstring;
607 
608 
609  infoMap["timedate"] = MythDate::toString(
610  startts, MythDate::kDateTimeFull | MythDate::kSimplify) + " - " +
612 
613  infoMap["shorttimedate"] =
615  startts, MythDate::kDateTimeShort | MythDate::kSimplify) + " - " +
617 
619  {
620  QDateTime ldt =
621  QDateTime(MythDate::current().toLocalTime().date(), m_findtime,
622  Qt::LocalTime);
623  QString findfrom = MythDate::toString(ldt, MythDate::kTime);
624  if (m_type == kWeeklyRecord)
625  {
626  int daynum = (m_findday + 5) % 7 + 1;
627  findfrom = QString("%1, %2")
628  .arg(gCoreContext->GetQLocale().dayName(daynum, QLocale::ShortFormat))
629  .arg(findfrom);
630  }
631  infoMap["subtitle"] = tr("(%1 or later) %3",
632  "e.g. (Sunday or later) program "
633  "subtitle").arg(findfrom)
634  .arg(m_subtitle);
635  }
636 
637  infoMap["searchtype"] = SearchTypeToString(m_searchType);
638  if (m_searchType != kNoSearch)
639  infoMap["searchforwhat"] = m_description;
640 
641  using namespace MythDate;
642  if (m_nextRecording.isValid())
643  {
644  infoMap["nextrecording"] = MythDate::toString(
646  }
647  if (m_lastRecorded.isValid())
648  {
649  infoMap["lastrecorded"] = MythDate::toString(
651  }
652  if (m_lastDeleted.isValid())
653  {
654  infoMap["lastdeleted"] = MythDate::toString(
656  }
657 
658  infoMap["ruletype"] = toString(m_type);
659  infoMap["rectype"] = toString(m_type);
660 
661  if (m_template == "Default")
662  infoMap["template"] = tr("Default", "Default template");
663  else
664  infoMap["template"] = m_template;
665 }
666 
667 void RecordingRule::UseTempTable(bool usetemp, const QString& table)
668 {
670 
671  if (usetemp)
672  {
673  m_recordTable = table;
674 
675  query.prepare("SELECT GET_LOCK(:LOCK, 2);");
676  query.bindValue(":LOCK", "DiffSchedule");
677  if (!query.exec())
678  {
679  MythDB::DBError("Obtaining lock in testRecording", query);
680  return;
681  }
682 
683  query.prepare(QString("DROP TABLE IF EXISTS %1;").arg(table));
684  if (!query.exec())
685  {
686  MythDB::DBError("Deleting old table in testRecording", query);
687  return;
688  }
689 
690  query.prepare(QString("CREATE TABLE %1 SELECT * FROM record;")
691  .arg(table));
692  if (!query.exec())
693  {
694  MythDB::DBError("Create new temp table", query);
695  return;
696  }
697 
698  query.prepare(QString("ALTER TABLE %1 MODIFY recordid int(10) "
699  "UNSIGNED NOT NULL AUTO_INCREMENT primary key;")
700  .arg(table));
701  if (!query.exec())
702  {
703  MythDB::DBError("Modify recordid column to include "
704  "auto-increment", query);
705  return;
706  }
707 
708  if (m_recordID > 0)
710 
711  Save(false);
712  }
713  else
714  {
715  query.prepare("SELECT RELEASE_LOCK(:LOCK);");
716  query.bindValue(":LOCK", "DiffSchedule");
717  if (!query.exec())
718  {
719  MythDB::DBError("Free lock", query);
720  return;
721  }
722  m_recordTable = "record";
723  m_tempID = 0;
724  }
725 }
726 
728 {
729  if (!m_progInfo)
730  return;
731 
745  if (m_recordID <= 0)
746  {
747  m_findday =
748  (m_progInfo->GetScheduledStartTime().toLocalTime().date()
749  .dayOfWeek() + 1) % 7;
750  m_findtime = m_progInfo->GetScheduledStartTime().toLocalTime().time();
751  m_findid = QDate(1970, 1, 1).daysTo(
752  m_progInfo->GetScheduledStartTime().toLocalTime().date()) + 719528;
753  }
754  else
755  {
756  if (m_findid > 0)
758  else
759  {
760  QDate epoch(1970, 1, 1);
761  m_findid = epoch.daysTo(
762  m_progInfo->GetScheduledStartTime().toLocalTime().date())
763  + 719528;
764  }
765  }
767 
768  if (m_inetref.isEmpty())
769  {
773  }
775 }
776 
778 {
780  query.prepare("SELECT SUM(1 << filterid) FROM recordfilter "
781  "WHERE filterid >= 0 AND filterid < :NUMFILTERS AND "
782  " TRIM(clause) <> '' AND newruledefault <> 0");
784  if (!query.exec())
785  {
786  MythDB::DBError("GetDefaultFilter", query);
787  return 0;
788  }
789 
790  if (!query.next())
791  return 0;
792 
793  return query.value(0).toUInt();
794 }
795 
797 {
798  QString searchTypeString;
799 
800  switch (searchType)
801  {
802  case kNoSearch:
803  searchTypeString = ""; // Allow themers to decide what to display
804  break;
805  case kPowerSearch:
806  searchTypeString = tr("Power Search");
807  break;
808  case kTitleSearch:
809  searchTypeString = tr("Title Search");
810  break;
811  case kKeywordSearch:
812  searchTypeString = tr("Keyword Search");
813  break;
814  case kPeopleSearch:
815  searchTypeString = tr("People Search");
816  break;
817  default:
818  searchTypeString = tr("Unknown Search");
819  break;
820  }
821 
822  return searchTypeString;
823 }
824 
826 {
827  QStringList result;
828 
830  query.prepare("SELECT category "
831  "FROM record "
832  "WHERE type = :TEMPLATE "
833  "ORDER BY category = 'Default' DESC, category"
834  );
835  query.bindValue(":TEMPLATE", kTemplateRecord);
836 
837  if (!query.exec())
838  {
839  MythDB::DBError("LoadByTemplate", query);
840  return result;
841  }
842 
843  while (query.next())
844  result << query.value(0).toString();
845 
846  return result;
847 }
848 
849 bool RecordingRule::IsValid(QString &msg) const
850 {
851  bool isOverride = false;
852  switch (m_type)
853  {
854  case kSingleRecord:
855  case kDailyRecord:
856  case kAllRecord:
857  case kWeeklyRecord:
858  case kOneRecord:
859  case kTemplateRecord:
860  break;
861  case kOverrideRecord:
862  case kDontRecord:
863  isOverride = true;
864  break;
865  case kNotRecording:
866  default:
867  msg = QString("Invalid recording type.");
868  return false;
869  }
870 
871  bool isNormal = false;
872  bool isSearch = false;
873  bool isManual = false;
874  switch (m_searchType)
875  {
876  case kNoSearch:
877  isNormal = true;
878  break;
879  case kPowerSearch:
880  case kTitleSearch:
881  case kKeywordSearch:
882  case kPeopleSearch:
883  isSearch = true;
884  break;
885  case kManualSearch:
886  isManual = true;
887  break;
888  default:
889  msg = QString("Invalid search type.");
890  return false;
891  }
892 
893  if ((isNormal && (m_type == kDailyRecord || m_type == kWeeklyRecord)) ||
894  (isSearch && (m_type != kDailyRecord && m_type != kWeeklyRecord &&
895  m_type != kOneRecord && m_type != kAllRecord)) ||
896  (isManual && (m_type != kDailyRecord && m_type != kWeeklyRecord &&
898  {
899  msg = QString("Invalid recording type/search type.");
900  return false;
901  }
902 
903  if ((m_parentRecID && !isOverride) ||
904  (!m_parentRecID && isOverride))
905  {
906  msg = QString("Invalid parentID/override.");
907  return false;
908  }
909 
910  if (m_title.isEmpty())
911  {
912  msg = QString("Invalid title.");
913  return false;
914  }
915 
916  if (m_searchType == kPowerSearch)
917  {
919  query.prepare(QString("SELECT NULL FROM (program, channel) "
920  "%1 WHERE %2")
922  if (m_description.contains(';') || !query.exec())
923  {
924  msg = QString("Invalid custom search values.");
925  return false;
926  }
927  }
928  else if (isSearch)
929  {
930  if (m_description.isEmpty())
931  {
932  msg = QString("Invalid search value.");
933  return false;
934  }
935  }
936 
937  if (!isSearch)
938  {
939  if (!m_startdate.isValid() || !m_starttime.isValid() ||
940  !m_enddate.isValid() || !m_endtime.isValid())
941  {
942  msg = QString("Invalid start/end date/time.");
943  return false;
944  }
945  int secsto = QDateTime(m_startdate, m_starttime)
946  .secsTo(QDateTime(m_enddate, m_endtime));
947  if (secsto <= 0 || secsto > (8 * 3600))
948  {
949  msg = QString("Invalid duration.");
950  return false;
951  }
952 
953  if (!m_channelid || m_station.isEmpty())
954  {
955  msg = QString("Invalid channel.");
956  return false;
957  }
958  }
959 
960  if (m_findday < 0 || m_findday > 6 || !m_findtime.isValid())
961  {
962  msg = QString("Invalid find values.");
963  return false;
964  }
965 
966  if (m_recPriority < -99 || m_recPriority > 99)
967  {
968  msg = QString("Invalid priority.");
969  return false;
970  }
971 
972  if (m_startOffset < -480 || m_startOffset > 480 ||
973  m_endOffset < -480 || m_endOffset > 480)
974  {
975  msg = QString("Invalid start/end offset.");
976  return false;
977  }
978 
979  if (m_prefInput < 0)
980  {
981  msg = QString("Invalid preferred input.");
982  return false;
983  }
984 
985  unsigned valid_mask = (1 << kNumFilters) - 1;
986  if ((m_filter & valid_mask) != m_filter)
987  {
988  msg = QString("Invalid filter value.");
989  return false;
990  }
991 
992  if (m_recProfile.isEmpty() || (m_recGroupID == 0) ||
993  m_storageGroup.isEmpty() || m_playGroup.isEmpty())
994  {
995  msg = QString("Invalid group value.");
996  return false;
997  }
998 
999  if (m_maxEpisodes < 0)
1000  {
1001  msg = QString("Invalid max episodes value.");
1002  return false;
1003  }
1004 
1005  if (m_dupIn & ~(kDupsInAll | kDupsNewEpi))
1006  {
1007  msg = QString("Invalid duplicate scope.");
1008  return false;
1009  }
1010 
1013  {
1014  msg = QString("Invalid duplicate method.");
1015  return false;
1016  }
1017 
1018  if (m_transcoder < 0)
1019  {
1020  msg = QString("Invalid transcoder value.");
1021  return false;
1022  }
1023 
1024  return true;
1025 }
RecordingRule::m_isOverride
bool m_isOverride
Definition: recordingrule.h:153
RecordingRule::m_channelid
int m_channelid
Definition: recordingrule.h:100
ProgramInfo::GetSortTitle
QString GetSortTitle(void) const
Definition: programinfo.h:360
RecordingRule::LoadTemplate
bool LoadTemplate(const QString &category, const QString &categoryType="Default")
Definition: recordingrule.cpp:273
RecordingRule::LoadByProgram
bool LoadByProgram(const ProgramInfo *proginfo)
Definition: recordingrule.cpp:168
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:783
kDupCheckDesc
@ kDupCheckDesc
Definition: recordingtypes.h:62
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:126
RecordingRule::m_autoTranscode
bool m_autoTranscode
Definition: recordingrule.h:133
RecordingRule::ModifyPowerSearchByID
bool ModifyPowerSearchByID(int rid, const QString &textname, QString forwhat, QString joininfo="")
Definition: recordingrule.cpp:339
RecordingRule::m_enddate
QDate m_enddate
Definition: recordingrule.h:92
RecordingRule::m_recordTable
QString m_recordTable
Definition: recordingrule.h:148
RecordingRule::m_playGroup
QString m_playGroup
Definition: recordingrule.h:123
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:80
RecordingRule::m_seriesid
QString m_seriesid
Definition: recordingrule.h:86
RecordingRule::m_parentRecID
int m_parentRecID
Definition: recordingrule.h:73
RecordingRule::m_description
QString m_description
Definition: recordingrule.h:83
RecordingRule::m_template
QString m_template
Definition: recordingrule.h:164
RecordingRule::m_autoCommFlag
bool m_autoCommFlag
Definition: recordingrule.h:132
RecordingRule::m_inetref
QString m_inetref
Definition: recordingrule.h:89
getMythSortHelper
std::shared_ptr< MythSortHelper > getMythSortHelper(void)
Get a pointer to the MythSortHelper singleton.
Definition: mythsorthelper.cpp:132
mythdb.h
RecordingRule::m_maxNewest
bool m_maxNewest
Definition: recordingrule.h:128
RecordingRule::m_category
QString m_category
Definition: recordingrule.h:84
RecordingRule::Save
bool Save(bool sendSig=true)
Definition: recordingrule.cpp:383
RecordingRule::m_nextRecording
QDateTime m_nextRecording
Definition: recordingrule.h:143
RecordingRule::m_starttime
QTime m_starttime
Definition: recordingrule.h:93
MythDate::as_utc
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
Definition: mythdate.cpp:23
PlayGroup::GetInitialName
static QString GetInitialName(const ProgramInfo *pi)
Definition: playgroup.cpp:224
RecordingRule::GetDefaultFilter
static unsigned GetDefaultFilter(void)
Definition: recordingrule.cpp:777
kDailyRecord
@ kDailyRecord
Definition: recordingtypes.h:23
kDupCheckSubThenDesc
@ kDupCheckSubThenDesc
Definition: recordingtypes.h:64
RecordingRule::m_progInfo
const ProgramInfo * m_progInfo
Definition: recordingrule.h:168
kDupCheckSub
@ kDupCheckSub
Definition: recordingtypes.h:61
MSqlQuery::lastInsertId
QVariant lastInsertId()
Return the id of the last inserted row.
Definition: mythdbcon.cpp:888
RecordingRule::m_title
QString m_title
Definition: recordingrule.h:79
RecordingRule::m_sortSubtitle
QString m_sortSubtitle
Definition: recordingrule.h:82
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:198
arg
arg(title).arg(filename).arg(doDelete))
ProgramInfo::GetChannelSchedulingID
QString GetChannelSchedulingID(void) const
This is the unique programming identifier of a channel.
Definition: programinfo.h:381
ProgramInfo::GetCategory
QString GetCategory(void) const
Definition: programinfo.h:367
RecordingRule::m_averageDelay
int m_averageDelay
Definition: recordingrule.h:142
RecordingRule::m_lastDeleted
QDateTime m_lastDeleted
Definition: recordingrule.h:145
RecordingDupMethodType
RecordingDupMethodType
Definition: recordingtypes.h:58
RecordingRule::m_endOffset
int m_endOffset
Definition: recordingrule.h:112
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
category
QString category
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1422
RecordingRule::kNumFilters
static const int kNumFilters
Definition: recordingrule.h:37
ProgramInfo::GetScheduledEndTime
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:395
playgroup.h
kKeywordSearch
@ kKeywordSearch
Definition: recordingtypes.h:76
mythsorthelper.h
RecordingRule::m_dupIn
RecordingDupInType m_dupIn
Definition: recordingrule.h:116
RecordingRule::m_isInactive
bool m_isInactive
Recording rule is enabled?
Definition: recordingrule.h:76
RecordingRule::m_season
uint m_season
Definition: recordingrule.h:96
MythDate::kDateTimeShort
@ kDateTimeShort
Default local time.
Definition: mythdate.h:21
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
kDupsInAll
@ kDupsInAll
Definition: recordingtypes.h:47
RecordingRule::m_findid
int m_findid
Definition: recordingrule.h:104
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
RecordingRule::Load
bool Load(bool asTemplate=false)
Load a single rule from the recorded table.
Definition: recordingrule.cpp:58
ProgramInfo::GetInetRef
QString GetInetRef(void) const
Definition: programinfo.h:435
RecordingRule::m_startOffset
int m_startOffset
Definition: recordingrule.h:111
RecordingDupInType
RecordingDupInType
Definition: recordingtypes.h:43
RecordingRule::GetTemplateNames
static QStringList GetTemplateNames(void)
Definition: recordingrule.cpp:825
toString
QString toString(MarkTypes type)
Definition: programtypes.cpp:26
RecordingRule::m_isTemplate
bool m_isTemplate
Definition: recordingrule.h:157
RecordingRule::m_episode
uint m_episode
Definition: recordingrule.h:97
mythdate.h
RecordingRule::RecordingRule
RecordingRule()
Definition: recordingrule.cpp:29
ProgramInfo::GetScheduledStartTime
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:388
RecordingRule::IsValid
bool IsValid(QString &msg) const
Definition: recordingrule.cpp:849
MythCoreContext::GetQLocale
QLocale GetQLocale(void)
Definition: mythcorecontext.cpp:1855
RecordingRule::m_autoUserJob4
bool m_autoUserJob4
Definition: recordingrule.h:137
kPowerSearch
@ kPowerSearch
Definition: recordingtypes.h:74
kTemplateRecord
@ kTemplateRecord
Definition: recordingtypes.h:32
RecordingInfo::GetRecgroupString
static QString GetRecgroupString(uint recGroupID)
Temporary helper during transition from string to ID.
Definition: recordinginfo.cpp:1624
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:359
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
ProgramInfo::GetDescription
QString GetDescription(void) const
Definition: programinfo.h:363
RecordingRule::m_autoUserJob2
bool m_autoUserJob2
Definition: recordingrule.h:135
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:178
RecordingRule::AssignProgramInfo
void AssignProgramInfo()
Definition: recordingrule.cpp:727
RecordingRule::m_findtime
QTime m_findtime
callsign?
Definition: recordingrule.h:103
RecordingRule::m_lastRecorded
QDateTime m_lastRecorded
Definition: recordingrule.h:144
RecordingRule::m_autoExpire
bool m_autoExpire
Definition: recordingrule.h:127
RecordingRule::m_recProfile
QString m_recProfile
Definition: recordingrule.h:121
RecordingRule::m_tempID
int m_tempID
Definition: recordingrule.h:149
RecordingRule::m_searchType
RecSearchType m_searchType
Definition: recordingrule.h:114
RecordingRule::m_type
RecordingType m_type
Definition: recordingrule.h:113
RecSearchType
RecSearchType
Definition: recordingtypes.h:72
RecordingRule::m_subtitle
QString m_subtitle
Definition: recordingrule.h:81
RecordingRule::UseTempTable
void UseTempTable(bool usetemp, const QString &table="record_tmp")
Definition: recordingrule.cpp:667
MSqlQuery::SchedCon
static MSqlQueryInfo SchedCon()
Returns dedicated connection. (Required for using temporary SQL tables.)
Definition: mythdbcon.cpp:565
scheduledrecording.h
RecordingRule::m_findday
int m_findday
Day of the week for once per week etc.
Definition: recordingrule.h:106
kNoSearch
@ kNoSearch
Definition: recordingtypes.h:73
RecordingRule::m_filter
unsigned m_filter
Definition: recordingrule.h:117
ProgramInfo::GetFindID
uint GetFindID(void) const
Definition: programinfo.h:468
kManualSearch
@ kManualSearch
Definition: recordingtypes.h:78
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
ProgramInfo::GetSeriesID
QString GetSeriesID(void) const
Definition: programinfo.h:433
RecordingRule::MakeTemplate
bool MakeTemplate(QString category)
Definition: recordingrule.cpp:311
RecordingRule::m_maxEpisodes
int m_maxEpisodes
Definition: recordingrule.h:126
ProgramInfo::GetSortSubtitle
QString GetSortSubtitle(void) const
Definition: programinfo.h:362
kTitleSearch
@ kTitleSearch
Definition: recordingtypes.h:75
RecordingRule::m_programid
QString m_programid
Definition: recordingrule.h:87
kOneRecord
@ kOneRecord
Definition: recordingtypes.h:27
RecordingRule::m_sortTitle
QString m_sortTitle
Definition: recordingrule.h:80
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
RecordingRule::m_recGroupID
uint m_recGroupID
Definition: recordingrule.h:124
RecordingRule::m_endtime
QTime m_endtime
Definition: recordingrule.h:94
MythDate::kSimplify
@ kSimplify
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:23
kWeeklyRecord
@ kWeeklyRecord
Definition: recordingtypes.h:26
RecordingRule::m_storageGroup
QString m_storageGroup
Definition: recordingrule.h:122
ProgramInfo::GetChanID
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:370
ProgramInfo::GetEpisode
uint GetEpisode(void) const
Definition: programinfo.h:365
RecordingRule::m_transcoder
int m_transcoder
Definition: recordingrule.h:131
RecordingRule::m_autoUserJob1
bool m_autoUserJob1
Definition: recordingrule.h:134
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:68
RecordingRule::ToMap
void ToMap(InfoMap &infoMap) const
Definition: recordingrule.cpp:544
RecordingRule::m_recordID
int m_recordID
Unique Recording Rule ID.
Definition: recordingrule.h:72
MythDate::kAddYear
@ kAddYear
Add year to string if not included.
Definition: mythdate.h:22
ProgramInfo::GetSeason
uint GetSeason(void) const
Definition: programinfo.h:364
mythcorecontext.h
kOverrideRecord
@ kOverrideRecord
Definition: recordingtypes.h:28
RecordingRule::m_dupMethod
RecordingDupMethodType m_dupMethod
Definition: recordingrule.h:115
MythDate
Definition: mythdate.cpp:8
ProgramInfo::GetCategoryTypeString
QString GetCategoryTypeString(void) const
Returns catType as a string.
Definition: programinfo.cpp:1797
RecordingRule::ensureSortFields
void ensureSortFields(void)
Ensure that the sortTitle and sortSubtitle fields are set.
Definition: recordingrule.cpp:45
kNotRecording
@ kNotRecording
Definition: recordingtypes.h:21
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:864
kDupCheckNone
@ kDupCheckNone
Definition: recordingtypes.h:60
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:14
kSingleRecord
@ kSingleRecord
Definition: recordingtypes.h:22
RecordingRule::m_loaded
bool m_loaded
Definition: recordingrule.h:172
RecordingRule::Delete
bool Delete(bool sendSig=true)
Definition: recordingrule.cpp:501
MythDate::kDateFull
@ kDateFull
Default local time.
Definition: mythdate.h:16
RecordingRule::MakeOverride
bool MakeOverride(void)
Definition: recordingrule.cpp:361
kAllRecord
@ kAllRecord
Definition: recordingtypes.h:25
recordingprofile.h
ProgramInfo::GetProgramID
QString GetProgramID(void) const
Definition: programinfo.h:434
RecordingProfile
Definition: recordingprofile.h:40
MythDate::kDateTimeFull
@ kDateTimeFull
Default local time.
Definition: mythdate.h:20
kDupsNewEpi
@ kDupsNewEpi
Definition: recordingtypes.h:48
RecordingRule::m_station
QString m_station
Definition: recordingrule.h:101
MythDate::kTime
@ kTime
Default local time.
Definition: mythdate.h:19
ProgramInfo::GetRecordingRuleID
uint GetRecordingRuleID(void) const
Definition: programinfo.h:447
recordingrule.h
RecordingRule::m_recPriority
int m_recPriority
Definition: recordingrule.h:109
RecordingRule::m_autoUserJob3
bool m_autoUserJob3
Definition: recordingrule.h:136
ScheduledRecording::RescheduleMatch
static void RescheduleMatch(uint recordid, uint sourceid, uint mplexid, const QDateTime &maxstarttime, const QString &why)
Definition: scheduledrecording.h:17
RecordingRule::LoadBySearch
bool LoadBySearch(RecSearchType lsearch, const QString &textname, const QString &forwhat, QString joininfo="", ProgramInfo *pginfo=nullptr)
Load a recording rule based on search parameters.
Definition: recordingrule.cpp:213
query
MSqlQuery query(MSqlQuery::InitCon())
RecordingType
RecordingType
Definition: recordingtypes.h:20
kPeopleSearch
@ kPeopleSearch
Definition: recordingtypes.h:77
kDontRecord
@ kDontRecord
Definition: recordingtypes.h:29
RecordingRule::m_startdate
QDate m_startdate
Definition: recordingrule.h:91
RecordingRule::m_autoMetadataLookup
bool m_autoMetadataLookup
Definition: recordingrule.h:138
null_to_empty
static QString null_to_empty(const QString &str)
Definition: recordingrule.cpp:19
RecordingRule::m_prefInput
int m_prefInput
Definition: recordingrule.h:110
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808
RecordingRule::SearchTypeToString
static QString SearchTypeToString(RecSearchType searchType)
Definition: recordingrule.cpp:796
ProgramInfo::GetSubtitle
QString GetSubtitle(void) const
Definition: programinfo.h:361