MythTV  master
mythtv/programs/mythcommflag/main.cpp
Go to the documentation of this file.
1 // POSIX headers
2 #include <unistd.h>
3 #include <sys/time.h> // for gettimeofday
4 
5 // ANSI C headers
6 #include <cstdlib>
7 #include <cstdio>
8 #include <ctime>
9 #include <cmath>
10 
11 // C++ headers
12 #include <string>
13 #include <iostream>
14 #include <fstream>
15 using namespace std;
16 
17 // Qt headers
18 #include <QCoreApplication>
19 #include <QString>
20 #include <QRegExp>
21 #include <QDir>
22 #include <QEvent>
23 
24 // MythTV headers
25 #include "mythmiscutil.h"
26 #include "mythdate.h"
27 #include "exitcodes.h"
28 #include "mythcontext.h"
29 #include "mythdb.h"
30 #include "mythversion.h"
31 #include "mythcommflagplayer.h"
32 #include "programinfo.h"
33 #include "remoteutil.h"
34 #include "remotefile.h"
35 #include "tvremoteutil.h"
36 #include "jobqueue.h"
37 #include "remoteencoder.h"
38 #include "ringbuffer.h"
39 #include "commandlineparser.h"
40 #include "mythtranslation.h"
41 #include "loggingserver.h"
42 #include "mythlogging.h"
43 #include "signalhandling.h"
44 #include "cleanupguard.h"
45 
46 // Commercial Flagging headers
47 #include "CommDetectorBase.h"
48 #include "CommDetectorFactory.h"
49 #include "SlotRelayer.h"
50 #include "CustomEventRelayer.h"
51 
52 #define LOC QString("MythCommFlag: ")
53 #define LOC_WARN QString("MythCommFlag, Warning: ")
54 #define LOC_ERR QString("MythCommFlag, Error: ")
55 
56 namespace
57 {
58  void cleanup()
59  {
60  delete gContext;
61  gContext = nullptr;
63  }
64 }
65 
66 int quiet = 0;
67 bool progress = true;
68 bool force = false;
69 
71 
72 bool watchingRecording = false;
76 int recorderNum = -1;
77 
78 int jobID = -1;
79 int lastCmd = -1;
80 
81 static QMap<QString,SkipTypes> *init_skip_types();
82 QMap<QString,SkipTypes> *skipTypes = init_skip_types();
83 
84 static QMap<QString,SkipTypes> *init_skip_types(void)
85 {
86  QMap<QString,SkipTypes> *tmp = new QMap<QString,SkipTypes>;
87  (*tmp)["commfree"] = COMM_DETECT_COMMFREE;
88  (*tmp)["uninit"] = COMM_DETECT_UNINIT;
89  (*tmp)["off"] = COMM_DETECT_OFF;
90  (*tmp)["blank"] = COMM_DETECT_BLANKS;
91  (*tmp)["blanks"] = COMM_DETECT_BLANKS;
92  (*tmp)["scene"] = COMM_DETECT_SCENE;
93  (*tmp)["blankscene"] = COMM_DETECT_BLANK_SCENE;
94  (*tmp)["blank_scene"] = COMM_DETECT_BLANK_SCENE;
95  (*tmp)["logo"] = COMM_DETECT_LOGO;
96  (*tmp)["all"] = COMM_DETECT_ALL;
97  (*tmp)["d2"] = COMM_DETECT_2;
98  (*tmp)["d2_logo"] = COMM_DETECT_2_LOGO;
99  (*tmp)["d2_blank"] = COMM_DETECT_2_BLANK;
100  (*tmp)["d2_scene"] = COMM_DETECT_2_SCENE;
101  (*tmp)["d2_all"] = COMM_DETECT_2_ALL;
102  return tmp;
103 }
104 
105 typedef enum
106 {
109 } OutputMethod;
111 
112 static QMap<QString,OutputMethod> *init_output_types();
113 QMap<QString,OutputMethod> *outputTypes = init_output_types();
114 
115 static QMap<QString,OutputMethod> *init_output_types(void)
116 {
117  QMap<QString,OutputMethod> *tmp = new QMap<QString,OutputMethod>;
118  (*tmp)["essentials"] = kOutputMethodEssentials;
119  (*tmp)["full"] = kOutputMethodFull;
120  return tmp;
121 }
122 
123 static QString get_filename(ProgramInfo *program_info)
124 {
125  QString filename = program_info->GetPathname();
126  if (!QFile::exists(filename))
127  filename = program_info->GetPlaybackURL(true);
128  return filename;
129 }
130 
131 static int QueueCommFlagJob(uint chanid, QDateTime starttime, bool rebuild)
132 {
133  QString startstring = MythDate::toString(starttime, MythDate::kFilename);
134  const ProgramInfo pginfo(chanid, starttime);
135 
136  if (!pginfo.GetChanID())
137  {
138  if (progress)
139  {
140  QString tmp = QString(
141  "Unable to find program info for chanid %1 @ %2")
142  .arg(chanid).arg(startstring);
143  cerr << tmp.toLocal8Bit().constData() << endl;
144  }
146  }
147 
148  if (cmdline.toBool("dryrun"))
149  {
150  QString tmp = QString("Job have been queued for chanid %1 @ %2")
151  .arg(chanid).arg(startstring);
152  cerr << tmp.toLocal8Bit().constData() << endl;
153  return GENERIC_EXIT_OK;
154  }
155 
156  bool result = JobQueue::QueueJob(JOB_COMMFLAG,
157  pginfo.GetChanID(), pginfo.GetRecordingStartTime(), "", "", "",
158  rebuild ? JOB_REBUILD : 0, JOB_QUEUED, QDateTime());
159 
160  if (result)
161  {
162  if (progress)
163  {
164  QString tmp = QString("Job Queued for chanid %1 @ %2")
165  .arg(chanid).arg(startstring);
166  cerr << tmp.toLocal8Bit().constData() << endl;
167  }
168  return GENERIC_EXIT_OK;
169  }
170  else
171  {
172  if (progress)
173  {
174  QString tmp = QString("Error queueing job for chanid %1 @ %2")
175  .arg(chanid).arg(startstring);
176  cerr << tmp.toLocal8Bit().constData() << endl;
177  }
178  return GENERIC_EXIT_DB_ERROR;
179  }
180 
181  return GENERIC_EXIT_OK;
182 }
183 
184 static int CopySkipListToCutList(uint chanid, QDateTime starttime)
185 {
186  frm_dir_map_t cutlist;
187  frm_dir_map_t::const_iterator it;
188 
189  QString startstring = MythDate::toString(starttime, MythDate::kFilename);
190  const ProgramInfo pginfo(chanid, starttime);
191 
192  if (!pginfo.GetChanID())
193  {
194  LOG(VB_GENERAL, LOG_ERR,
195  QString("No program data exists for channel %1 at %2")
196  .arg(chanid).arg(startstring));
198  }
199 
200  pginfo.QueryCommBreakList(cutlist);
201  for (it = cutlist.begin(); it != cutlist.end(); ++it)
202  if (*it == MARK_COMM_START)
203  cutlist[it.key()] = MARK_CUT_START;
204  else
205  cutlist[it.key()] = MARK_CUT_END;
206  pginfo.SaveCutList(cutlist);
207 
208  return GENERIC_EXIT_OK;
209 }
210 
211 static int ClearSkipList(uint chanid, QDateTime starttime)
212 {
213  QString startstring = MythDate::toString(starttime, MythDate::kFilename);
214  const ProgramInfo pginfo(chanid, starttime);
215 
216  if (!pginfo.GetChanID())
217  {
218  LOG(VB_GENERAL, LOG_ERR,
219  QString("No program data exists for channel %1 at %2")
220  .arg(chanid).arg(startstring));
222  }
223 
224  frm_dir_map_t skiplist;
225  pginfo.SaveCommBreakList(skiplist);
226 
227  LOG(VB_GENERAL, LOG_NOTICE, "Commercial skip list cleared");
228 
229  return GENERIC_EXIT_OK;
230 }
231 
232 static int SetCutList(uint chanid, QDateTime starttime, QString newCutList)
233 {
234  frm_dir_map_t cutlist;
235 
236  newCutList.replace(QRegExp(" "), "");
237 
238  QStringList tokens = newCutList.split(",", QString::SkipEmptyParts);
239 
240  for (int i = 0; i < tokens.size(); i++)
241  {
242  QStringList cutpair = tokens[i].split("-", QString::SkipEmptyParts);
243  cutlist[cutpair[0].toInt()] = MARK_CUT_START;
244  cutlist[cutpair[1].toInt()] = MARK_CUT_END;
245  }
246 
247  QString startstring = MythDate::toString(starttime, MythDate::kFilename);
248  const ProgramInfo pginfo(chanid, starttime);
249 
250  if (!pginfo.GetChanID())
251  {
252  LOG(VB_GENERAL, LOG_ERR,
253  QString("No program data exists for channel %1 at %2")
254  .arg(chanid).arg(startstring));
256  }
257 
258  pginfo.SaveCutList(cutlist);
259 
260  LOG(VB_GENERAL, LOG_NOTICE, QString("Cutlist set to: %1").arg(newCutList));
261 
262  return GENERIC_EXIT_OK;
263 }
264 
265 static int GetMarkupList(QString list, uint chanid, QDateTime starttime)
266 {
267  frm_dir_map_t cutlist;
268  frm_dir_map_t::const_iterator it;
269  QString result;
270 
271  QString startstring = MythDate::toString(starttime, MythDate::kFilename);
272  const ProgramInfo pginfo(chanid, starttime);
273 
274  if (!pginfo.GetChanID())
275  {
276  LOG(VB_GENERAL, LOG_ERR,
277  QString("No program data exists for channel %1 at %2")
278  .arg(chanid).arg(startstring));
280  }
281 
282  if (list == "cutlist")
283  pginfo.QueryCutList(cutlist);
284  else
285  pginfo.QueryCommBreakList(cutlist);
286 
287  uint64_t lastStart = 0;
288  for (it = cutlist.begin(); it != cutlist.end(); ++it)
289  {
290  if ((*it == MARK_COMM_START) ||
291  (*it == MARK_CUT_START))
292  {
293  if (!result.isEmpty())
294  result += ",";
295  lastStart = it.key();
296  result += QString("%1-").arg(lastStart);
297  }
298  else
299  {
300  if (result.isEmpty())
301  result += "0-";
302  result += QString("%1").arg(it.key());
303  }
304  }
305 
306  if (result.endsWith('-'))
307  {
308  uint64_t lastFrame = pginfo.QueryLastFrameInPosMap() + 60;
309  if (lastFrame > lastStart)
310  result += QString("%1").arg(lastFrame);
311  }
312 
313  if (list == "cutlist")
314  cout << QString("Cutlist: %1\n").arg(result).toLocal8Bit().constData();
315  else
316  {
317  cout << QString("Commercial Skip List: %1\n")
318  .arg(result).toLocal8Bit().constData();
319  }
320 
321  return GENERIC_EXIT_OK;
322 }
323 
325  ostream &output, const frm_dir_map_t &commercialBreakList)
326 {
327  if (progress)
328  output << "----------------------------" << endl;
329 
330  if (commercialBreakList.empty())
331  {
332  if (progress)
333  output << "No breaks" << endl;
334  }
335  else
336  {
337  frm_dir_map_t::const_iterator it = commercialBreakList.begin();
338  for (; it != commercialBreakList.end(); ++it)
339  {
340  output << "framenum: " << it.key() << "\tmarktype: " << *it
341  << endl;
342  }
343  }
344 
345  if (progress)
346  output << "----------------------------" << endl;
347 }
348 
350  const ProgramInfo *program_info,
351  const frm_dir_map_t &commBreakList,
352  uint64_t frame_count,
353  const CommDetectorBase *commDetect,
354  const QString &output_filename)
355 {
356  if (output_filename.isEmpty())
357  return;
358 
359  ostream *out = &cout;
360  if (output_filename != "-")
361  {
362  QByteArray tmp = output_filename.toLocal8Bit();
363  out = new fstream(tmp.constData(), ios::app | ios::out );
364  }
365 
366  if (progress)
367  {
368  QString tmp = "";
369  if (program_info->GetChanID())
370  {
371  tmp = QString("commercialBreakListFor: %1 on %2 @ %3")
372  .arg(program_info->GetTitle())
373  .arg(program_info->GetChanID())
374  .arg(program_info->GetRecordingStartTime(MythDate::ISODate));
375  }
376  else
377  {
378  tmp = QString("commercialBreakListFor: %1")
379  .arg(program_info->GetPathname());
380  }
381 
382  const QByteArray tmp2 = tmp.toLocal8Bit();
383  *out << tmp2.constData() << endl;
384 
385  if (frame_count)
386  *out << "totalframecount: " << frame_count << endl;
387  }
388 
389  if (commDetect)
390  commDetect->PrintFullMap(*out, &commBreakList, progress);
391  else
392  streamOutCommercialBreakList(*out, commBreakList);
393 
394  if (output_filename != "-")
395  delete out;
396 }
397 
398 static void commDetectorBreathe()
399 {
400  //this is connected to the commdetectors breathe signal so we get a chance
401  //while its busy to see if the user already told us to stop.
402  qApp->processEvents();
403 
404  if (jobID != -1)
405  {
406  int curCmd = JobQueue::GetJobCmd(jobID);
407  if (curCmd == lastCmd)
408  return;
409 
410  switch (curCmd)
411  {
412  case JOB_STOP:
413  {
414  commDetector->stop();
415  break;
416  }
417  case JOB_PAUSE:
418  {
419  JobQueue::ChangeJobStatus(jobID, JOB_PAUSED,
420  QCoreApplication::translate("(mythcommflag)",
421  "Paused", "Job status"));
422  commDetector->pause();
423  break;
424  }
425  case JOB_RESUME:
426  {
427  JobQueue::ChangeJobStatus(jobID, JOB_RUNNING,
428  QCoreApplication::translate("(mythcommflag)",
429  "Running", "Job status"));
430  commDetector->resume();
431  break;
432  }
433  }
434  }
435 }
436 
437 static void commDetectorStatusUpdate(const QString& status)
438 {
439  if (jobID != -1)
440  {
441  JobQueue::ChangeJobStatus(jobID, JOB_RUNNING, status);
443  }
444 }
445 
447 {
448  frm_dir_map_t newCommercialMap;
449  commDetector->GetCommercialBreakList(newCommercialMap);
450 
451  frm_dir_map_t::Iterator it = newCommercialMap.begin();
452  QString message = "COMMFLAG_UPDATE ";
453  message += global_program_info->MakeUniqueKey();
454 
455  for (it = newCommercialMap.begin();
456  it != newCommercialMap.end(); ++it)
457  {
458  if (it != newCommercialMap.begin())
459  message += ",";
460  else
461  message += " ";
462  message += QString("%1:%2").arg(it.key())
463  .arg(*it);
464  }
465 
466  LOG(VB_COMMFLAG, LOG_INFO,
467  QString("mythcommflag sending update: %1").arg(message));
468 
469  gCoreContext->SendMessage(message);
470 }
471 
472 static void incomingCustomEvent(QEvent* e)
473 {
474  if (e->type() == MythEvent::MythEventMessage)
475  {
476  MythEvent *me = static_cast<MythEvent *>(e);
477  QString message = me->Message();
478 
479  message = message.simplified();
480  QStringList tokens = message.split(" ", QString::SkipEmptyParts);
481 
482  LOG(VB_COMMFLAG, LOG_INFO,
483  QString("mythcommflag: Received Event: '%1'") .arg(message));
484 
485  if ((watchingRecording) && (tokens.size() >= 3) &&
486  (tokens[0] == "DONE_RECORDING"))
487  {
488  int cardnum = tokens[1].toInt();
489  int filelen = tokens[2].toInt();
490 
491  message = QString("mythcommflag: Received a "
492  "DONE_RECORDING event for card %1. ")
493  .arg(cardnum);
494 
495  if (recorderNum != -1 && cardnum == recorderNum)
496  {
498  watchingRecording = false;
499  message += "Informed CommDetector that recording has finished.";
500  LOG(VB_COMMFLAG, LOG_INFO, message);
501  }
502  }
503 
504  if ((tokens.size() >= 2) && (tokens[0] == "COMMFLAG_REQUEST"))
505  {
506  uint chanid = 0;
507  QDateTime recstartts;
508  ProgramInfo::ExtractKey(tokens[1], chanid, recstartts);
509 
510  message = QString("mythcommflag: Received a "
511  "COMMFLAG_REQUEST event for chanid %1 @ %2. ")
512  .arg(chanid).arg(recstartts.toString(Qt::ISODate));
513 
514  if ((global_program_info->GetChanID() == chanid) &&
515  (global_program_info->GetRecordingStartTime() == recstartts))
516  {
518  message += "Requested CommDetector to generate new break list.";
519  LOG(VB_COMMFLAG, LOG_INFO, message);
520  }
521  }
522  }
523 }
524 
525 static int DoFlagCommercials(
526  ProgramInfo *program_info,
527  bool showPercentage, bool fullSpeed, int jobid,
528  MythCommFlagPlayer* cfp, enum SkipTypes commDetectMethod,
529  const QString &outputfilename, bool useDB)
530 {
531  CommDetectorFactory factory;
532  commDetector = factory.makeCommDetector(
533  commDetectMethod, showPercentage,
534  fullSpeed, cfp,
535  program_info->GetChanID(),
536  program_info->GetScheduledStartTime(),
537  program_info->GetScheduledEndTime(),
538  program_info->GetRecordingStartTime(),
539  program_info->GetRecordingEndTime(), useDB);
540 
541  if (jobid > 0)
542  LOG(VB_COMMFLAG, LOG_INFO,
543  QString("mythcommflag processing JobID %1").arg(jobid));
544 
545  if (useDB)
546  program_info->SaveCommFlagged(COMM_FLAG_PROCESSING);
547 
552  QObject::connect(commDetector, SIGNAL(breathe()),
553  a, SLOT(relay()));
554  QObject::connect(commDetector, SIGNAL(statusUpdate(const QString&)),
555  b, SLOT(relay(const QString&)));
556  QObject::connect(commDetector, SIGNAL(gotNewCommercialBreakList()),
557  c, SLOT(relay()));
558 
559  if (useDB)
560  {
561  LOG(VB_COMMFLAG, LOG_INFO,
562  "mythcommflag sending COMMFLAG_START notification");
563  QString message = "COMMFLAG_START ";
564  message += program_info->MakeUniqueKey();
565  gCoreContext->SendMessage(message);
566  }
567 
568  bool result = commDetector->go();
569  int comms_found = 0;
570 
571  if (result)
572  {
573  cfp->SaveTotalDuration();
574 
575  frm_dir_map_t commBreakList;
576  commDetector->GetCommercialBreakList(commBreakList);
577  comms_found = commBreakList.size() / 2;
578 
579  if (useDB)
580  {
581  program_info->SaveMarkupFlag(MARK_UPDATED_CUT);
582  program_info->SaveCommBreakList(commBreakList);
583  program_info->SaveCommFlagged(COMM_FLAG_DONE);
584  }
585 
587  program_info, commBreakList, cfp->GetTotalFrameCount(),
589  outputfilename);
590  }
591  else
592  {
593  if (useDB)
594  program_info->SaveCommFlagged(COMM_FLAG_NOT_FLAGGED);
595  }
596 
598  commDetector = nullptr;
599  sleep(1);
600  tmp->deleteLater();
601 
602  cer->deleteLater();
603  c->deleteLater();
604  b->deleteLater();
605  a->deleteLater();
606 
607  return comms_found;
608 }
609 
610 static qint64 GetFileSize(ProgramInfo *program_info)
611 {
612  QString filename = get_filename(program_info);
613  qint64 size = -1;
614 
615  if (filename.startsWith("myth://"))
616  {
617  RemoteFile remotefile(filename, false, false, 0);
618  size = remotefile.GetFileSize();
619  }
620  else
621  {
622  QFile file(filename);
623  if (file.exists())
624  {
625  size = file.size();
626  }
627  }
628 
629  return size;
630 }
631 
632 static bool DoesFileExist(ProgramInfo *program_info)
633 {
634  QString filename = get_filename(program_info);
635  qint64 size = GetFileSize(program_info);
636 
637  if (size < 0)
638  {
639  LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find file %1, aborting.")
640  .arg(filename));
641  return false;
642  }
643 
644  if (size == 0)
645  {
646  LOG(VB_GENERAL, LOG_ERR, QString("File %1 is zero-byte, aborting.")
647  .arg(filename));
648  return false;
649  }
650 
651  return true;
652 }
653 
654 static void UpdateFileSize(ProgramInfo *program_info)
655 {
656  qint64 size = GetFileSize(program_info);
657 
658  if (size != (qint64)program_info->GetFilesize())
659  program_info->SaveFilesize(size);
660 }
661 
662 static bool IsMarked(uint chanid, QDateTime starttime)
663 {
664  MSqlQuery mark_query(MSqlQuery::InitCon());
665  mark_query.prepare("SELECT commflagged, count(rm.type) "
666  "FROM recorded r "
667  "LEFT JOIN recordedmarkup rm ON "
668  "( r.chanid = rm.chanid AND "
669  "r.starttime = rm.starttime AND "
670  "type in (:MARK_START,:MARK_END)) "
671  "WHERE r.chanid = :CHANID AND "
672  "r.starttime = :STARTTIME "
673  "GROUP BY COMMFLAGGED;");
674  mark_query.bindValue(":MARK_START", MARK_COMM_START);
675  mark_query.bindValue(":MARK_END", MARK_COMM_END);
676  mark_query.bindValue(":CHANID", chanid);
677  mark_query.bindValue(":STARTTIME", starttime);
678 
679  if (mark_query.exec() && mark_query.isActive() &&
680  mark_query.size() > 0)
681  {
682  if (mark_query.next())
683  {
684  int flagStatus = mark_query.value(0).toInt();
685  int marksFound = mark_query.value(1).toInt();
686 
687  QString flagStatusStr = "UNKNOWN";
688  switch (flagStatus) {
690  flagStatusStr = "Not Flagged";
691  break;
692  case COMM_FLAG_DONE:
693  flagStatusStr = QString("Flagged with %1 breaks")
694  .arg(marksFound / 2);
695  break;
697  flagStatusStr = "Flagging";
698  break;
699  case COMM_FLAG_COMMFREE:
700  flagStatusStr = "Commercial Free";
701  break;
702  }
703 
704  LOG(VB_COMMFLAG, LOG_INFO,
705  QString("Status for chanid %1 @ %2 is '%3'")
706  .arg(chanid).arg(starttime.toString(Qt::ISODate))
707  .arg(flagStatusStr));
708 
709  if ((flagStatus == COMM_FLAG_NOT_FLAGGED) && (marksFound == 0))
710  return false;
711  }
712  }
713  return true;
714 }
715 
716 static int FlagCommercials(ProgramInfo *program_info, int jobid,
717  const QString &outputfilename, bool useDB, bool fullSpeed)
718 {
719  global_program_info = program_info;
720 
721  int breaksFound = 0;
722 
723  // configure commercial detection method
724  SkipTypes commDetectMethod = (SkipTypes)gCoreContext->GetNumSetting(
725  "CommercialSkipMethod", COMM_DETECT_ALL);
726 
727  if (cmdline.toBool("commmethod"))
728  {
729  // pull commercial detection method from command line
730  QString commmethod = cmdline.toString("commmethod");
731 
732  // assume definition as integer value
733  bool ok = true;
734  commDetectMethod = (SkipTypes) commmethod.toInt(&ok);
735  if (!ok)
736  {
737  // not an integer, attempt comma separated list
738  commDetectMethod = COMM_DETECT_UNINIT;
739 
740  QStringList list = commmethod.split(",", QString::SkipEmptyParts);
741  QStringList::const_iterator it = list.begin();
742  for (; it != list.end(); ++it)
743  {
744  QString val = (*it).toLower();
745  if (val == "off")
746  {
747  commDetectMethod = COMM_DETECT_OFF;
748  break;
749  }
750 
751  if (!skipTypes->contains(val))
752  {
753  cerr << "Failed to decode --method option '"
754  << val.toLatin1().constData()
755  << "'" << endl;
757  }
758 
759  if (commDetectMethod == COMM_DETECT_UNINIT) {
760  commDetectMethod = skipTypes->value(val);
761  } else {
762  commDetectMethod = (SkipTypes) ((int)commDetectMethod
763  | (int)skipTypes->value(val));
764  }
765  }
766 
767  }
768  if (commDetectMethod == COMM_DETECT_UNINIT)
770  }
771  else if (useDB)
772  {
773  // if not manually specified, and we have a database to access
774  // pull the commflag type from the channel
775  MSqlQuery query(MSqlQuery::InitCon());
776  query.prepare("SELECT commmethod FROM channel "
777  "WHERE chanid = :CHANID;");
778  query.bindValue(":CHANID", program_info->GetChanID());
779 
780  if (!query.exec())
781  {
782  // if the query fails, return with an error
783  commDetectMethod = COMM_DETECT_UNINIT;
784  MythDB::DBError("FlagCommercials", query);
785  }
786  else if (query.next())
787  {
788  commDetectMethod = (enum SkipTypes)query.value(0).toInt();
789  if (commDetectMethod == COMM_DETECT_COMMFREE)
790  {
791  // if the channel is commercial free, drop to the default instead
792  commDetectMethod =
794  "CommercialSkipMethod", COMM_DETECT_ALL);
795  LOG(VB_COMMFLAG, LOG_INFO,
796  QString("Chanid %1 is marked as being Commercial Free, "
797  "we will use the default commercial detection "
798  "method").arg(program_info->GetChanID()));
799  }
800  else if (commDetectMethod == COMM_DETECT_UNINIT)
801  // no value set, so use the database default
802  commDetectMethod =
804  "CommercialSkipMethod", COMM_DETECT_ALL);
805  LOG(VB_COMMFLAG, LOG_INFO,
806  QString("Using method: %1 from channel %2")
807  .arg(commDetectMethod).arg(program_info->GetChanID()));
808  }
809 
810  }
811  else if (!useDB)
812  {
813  // default to a cheaper method for debugging purposes
814  commDetectMethod = COMM_DETECT_BLANK;
815  }
816 
817  // if selection has failed, or intentionally disabled, drop out
818  if (commDetectMethod == COMM_DETECT_UNINIT)
819  return GENERIC_EXIT_NOT_OK;
820  else if (commDetectMethod == COMM_DETECT_OFF)
821  return GENERIC_EXIT_OK;
822 
823  frm_dir_map_t blanks;
824  recorder = nullptr;
825 
826 /*
827  * is there a purpose to this not fulfilled by --getskiplist?
828  if (onlyDumpDBCommercialBreakList)
829  {
830  frm_dir_map_t commBreakList;
831  program_info->QueryCommBreakList(commBreakList);
832 
833  print_comm_flag_output(program_info, commBreakList,
834  0, nullptr, outputfilename);
835 
836  global_program_info = nullptr;
837  return GENERIC_EXIT_OK;
838  }
839 */
840 
841  if (!DoesFileExist(program_info))
842  {
843  LOG(VB_GENERAL, LOG_ERR,
844  "Unable to find file in defined storage paths.");
846  }
847 
848  QString filename = get_filename(program_info);
849 
850  RingBuffer *tmprbuf = RingBuffer::Create(filename, false);
851  if (!tmprbuf)
852  {
853  LOG(VB_GENERAL, LOG_ERR,
854  QString("Unable to create RingBuffer for %1").arg(filename));
855  global_program_info = nullptr;
857  }
858 
859  if (useDB)
860  {
862  {
863  LOG(VB_GENERAL, LOG_ERR, "Unable to open commflag DB connection");
864  delete tmprbuf;
865  global_program_info = nullptr;
866  return GENERIC_EXIT_DB_ERROR;
867  }
868  }
869 
871  kVideoIsNull |
872  kDecodeLowRes |
875  kNoITV);
876  /* blank detector needs to be only sample center for this optimization. */
877  if ((COMM_DETECT_BLANKS == commDetectMethod) ||
878  (COMM_DETECT_2_BLANK == commDetectMethod))
879  {
880  flags = (PlayerFlags) (flags | kDecodeFewBlocks);
881  }
882 
883  MythCommFlagPlayer *cfp = new MythCommFlagPlayer(flags);
885  ctx->SetPlayingInfo(program_info);
886  ctx->SetRingBuffer(tmprbuf);
887  ctx->SetPlayer(cfp);
888  cfp->SetPlayerInfo(nullptr, nullptr, ctx);
889 
890  if (useDB)
891  {
892  if (program_info->GetRecordingEndTime() > MythDate::current())
893  {
895 
896  recorder = RemoteGetExistingRecorder(program_info);
897  if (recorder && (recorder->GetRecorderNumber() != -1))
898  {
900  watchingRecording = true;
901  ctx->SetRecorder(recorder);
902 
903  LOG(VB_COMMFLAG, LOG_INFO,
904  QString("mythcommflag will flag recording "
905  "currently in progress on cardid %1")
906  .arg(recorderNum));
907  }
908  else
909  {
910  recorderNum = -1;
911  watchingRecording = false;
912 
913  LOG(VB_GENERAL, LOG_ERR,
914  "Unable to find active recorder for this "
915  "recording, realtime flagging will not be enabled.");
916  }
918  }
919  }
920 
921  // TODO: Add back insertion of job if not in jobqueue
922 
923  breaksFound = DoFlagCommercials(
924  program_info, progress, fullSpeed, jobid,
925  cfp, commDetectMethod, outputfilename, useDB);
926 
927  if (progress)
928  cerr << breaksFound << "\n";
929 
930  LOG(VB_GENERAL, LOG_NOTICE, QString("Finished, %1 break(s) found.")
931  .arg(breaksFound));
932 
933  delete ctx;
934  global_program_info = nullptr;
935 
936  return breaksFound;
937 }
938 
939 static int FlagCommercials( uint chanid, const QDateTime &starttime,
940  int jobid, const QString &outputfilename,
941  bool fullSpeed )
942 {
943  QString startstring = MythDate::toString(starttime, MythDate::kFilename);
944  ProgramInfo pginfo(chanid, starttime);
945 
946  if (!pginfo.GetChanID())
947  {
948  LOG(VB_GENERAL, LOG_ERR,
949  QString("No program data exists for channel %1 at %2")
950  .arg(chanid).arg(startstring));
952  }
953 
954  if (!force && JobQueue::IsJobRunning(JOB_COMMFLAG, pginfo))
955  {
956  if (progress)
957  {
958  cerr << "IN USE\n";
959  cerr << " "
960  "(the program is already being flagged elsewhere)\n";
961  }
962  LOG(VB_GENERAL, LOG_ERR, "Program is already being flagged elsewhere");
963  return GENERIC_EXIT_IN_USE;
964  }
965 
966 
967  if (progress)
968  {
969  cerr << "MythTV Commercial Flagger, flagging commercials for:" << endl;
970  if (pginfo.GetSubtitle().isEmpty())
971  cerr << " " << pginfo.GetTitle().toLocal8Bit().constData() << endl;
972  else
973  cerr << " " << pginfo.GetTitle().toLocal8Bit().constData() << " - "
974  << pginfo.GetSubtitle().toLocal8Bit().constData() << endl;
975  }
976 
977  return FlagCommercials(&pginfo, jobid, outputfilename, true, fullSpeed);
978 }
979 
980 static int FlagCommercials(QString filename, int jobid,
981  const QString &outputfilename, bool useDB,
982  bool fullSpeed)
983 {
984 
985  if (progress)
986  {
987  cerr << "MythTV Commercial Flagger, flagging commercials for:" << endl
988  << " " << filename.toLatin1().constData() << endl;
989  }
990 
991  ProgramInfo pginfo(filename);
992  return FlagCommercials(&pginfo, jobid, outputfilename, useDB, fullSpeed);
993 }
994 
995 static int RebuildSeekTable(ProgramInfo *pginfo, int jobid, bool writefile = false)
996 {
997  QString filename = get_filename(pginfo);
998 
999  if (!DoesFileExist(pginfo))
1000  {
1001  // file not found on local filesystem
1002  // assume file is in Video storage group on local backend
1003  // and try again
1004 
1005  filename = QString("myth://Videos@%1/%2")
1006  .arg(gCoreContext->GetHostName()).arg(filename);
1007  pginfo->SetPathname(filename);
1008  if (!DoesFileExist(pginfo))
1009  {
1010  LOG(VB_GENERAL, LOG_ERR,
1011  QString("Unable to find file in defined storage "
1012  "paths for JobQueue ID# %1.").arg(jobid));
1014  }
1015  }
1016 
1017  // Update the file size since mythcommflag --rebuild is often used in user
1018  // scripts after transcoding or other size-changing operations
1019  UpdateFileSize(pginfo);
1020 
1021  RingBuffer *tmprbuf = RingBuffer::Create(filename, false);
1022  if (!tmprbuf)
1023  {
1024  LOG(VB_GENERAL, LOG_ERR,
1025  QString("Unable to create RingBuffer for %1").arg(filename));
1027  }
1028 
1031  kDecodeNoDecode | kNoITV));
1033  ctx->SetPlayingInfo(pginfo);
1034  ctx->SetRingBuffer(tmprbuf);
1035  ctx->SetPlayer(cfp);
1036  cfp->SetPlayerInfo(nullptr, nullptr, ctx);
1037 
1038  if (progress)
1039  {
1040  QString time = QDateTime::currentDateTime().toString(Qt::TextDate);
1041  cerr << "Rebuild started at " << qPrintable(time) << endl;
1042  }
1043 
1044  if (writefile)
1046  cfp->RebuildSeekTable(progress);
1047  if (writefile)
1049 
1050  if (progress)
1051  {
1052  QString time = QDateTime::currentDateTime().toString(Qt::TextDate);
1053  cerr << "Rebuild completed at " << qPrintable(time) << endl;
1054  }
1055 
1056  delete ctx;
1057 
1058  return GENERIC_EXIT_OK;
1059 }
1060 
1061 static int RebuildSeekTable(QString filename, int jobid, bool writefile = false)
1062 {
1063  if (progress)
1064  {
1065  cerr << "MythTV Commercial Flagger, building seek table for:" << endl
1066  << " " << filename.toLatin1().constData() << endl;
1067  }
1068  ProgramInfo pginfo(filename);
1069  return RebuildSeekTable(&pginfo, jobid, writefile);
1070 }
1071 
1072 static int RebuildSeekTable(uint chanid, QDateTime starttime, int jobid, bool writefile = false)
1073 {
1074  ProgramInfo pginfo(chanid, starttime);
1075  if (progress)
1076  {
1077  cerr << "MythTV Commercial Flagger, building seek table for:" << endl;
1078  if (pginfo.GetSubtitle().isEmpty())
1079  cerr << " " << pginfo.GetTitle().toLocal8Bit().constData() << endl;
1080  else
1081  cerr << " " << pginfo.GetTitle().toLocal8Bit().constData() << " - "
1082  << pginfo.GetSubtitle().toLocal8Bit().constData() << endl;
1083  }
1084  return RebuildSeekTable(&pginfo, jobid, writefile);
1085 }
1086 
1087 int main(int argc, char *argv[])
1088 {
1089  int result = GENERIC_EXIT_OK;
1090 
1091 // QString allStart = "19700101000000";
1092 // QString allEnd = MythDate::current().toString("yyyyMMddhhmmss");
1093  int jobType = JOB_NONE;
1094 
1095  if (!cmdline.Parse(argc, argv))
1096  {
1097  cmdline.PrintHelp();
1099  }
1100 
1101  if (cmdline.toBool("showhelp"))
1102  {
1103  cmdline.PrintHelp();
1104  return GENERIC_EXIT_OK;
1105  }
1106 
1107  if (cmdline.toBool("showversion"))
1108  {
1110  return GENERIC_EXIT_OK;
1111  }
1112 
1113  QCoreApplication a(argc, argv);
1114  QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHCOMMFLAG);
1115  int retval = cmdline.ConfigureLogging("general",
1116  !cmdline.toBool("noprogress"));
1117  if (retval != GENERIC_EXIT_OK)
1118  return retval;
1119 
1120  CleanupGuard callCleanup(cleanup);
1121 
1122 #ifndef _WIN32
1123  QList<int> signallist;
1124  signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
1125  << SIGILL;
1126 #if ! CONFIG_DARWIN
1127  signallist << SIGRTMIN;
1128 #endif
1129  SignalHandler::Init(signallist);
1130  SignalHandler::SetHandler(SIGHUP, logSigHup);
1131 #endif
1132 
1134  if (!gContext->Init( false, /*use gui*/
1135  false, /*prompt for backend*/
1136  false, /*bypass auto discovery*/
1137  cmdline.toBool("skipdb"))) /*ignoreDB*/
1138  {
1139  LOG(VB_GENERAL, LOG_EMERG, "Failed to init MythContext, exiting.");
1141  }
1143 
1144  MythTranslation::load("mythfrontend");
1145 
1146  if (cmdline.toBool("outputmethod"))
1147  {
1148  QString om = cmdline.toString("outputmethod");
1149  if (outputTypes->contains(om))
1150  outputMethod = outputTypes->value(om);
1151  }
1152 
1153  if (cmdline.toBool("chanid") && cmdline.toBool("starttime"))
1154  {
1155  // operate on a recording in the database
1156  uint chanid = cmdline.toUInt("chanid");
1157  QDateTime starttime = cmdline.toDateTime("starttime");
1158 
1159  if (cmdline.toBool("clearskiplist"))
1160  return ClearSkipList(chanid, starttime);
1161  if (cmdline.toBool("gencutlist"))
1162  return CopySkipListToCutList(chanid, starttime);
1163  if (cmdline.toBool("clearcutlist"))
1164  return SetCutList(chanid, starttime, "");
1165  if (cmdline.toBool("setcutlist"))
1166  return SetCutList(chanid, starttime, cmdline.toString("setcutlist"));
1167  if (cmdline.toBool("getcutlist"))
1168  return GetMarkupList("cutlist", chanid, starttime);
1169  if (cmdline.toBool("getskiplist"))
1170  return GetMarkupList("commflag", chanid, starttime);
1171 
1172  // TODO: check for matching jobid
1173  // create temporary id to operate off of if not
1174 
1175  if (cmdline.toBool("queue"))
1176  QueueCommFlagJob(chanid, starttime, cmdline.toBool("rebuild"));
1177  else if (cmdline.toBool("rebuild"))
1178  result = RebuildSeekTable(chanid, starttime, -1);
1179  else
1180  result = FlagCommercials(chanid, starttime, -1,
1181  cmdline.toString("outputfile"), true);
1182  }
1183  else if (cmdline.toBool("jobid"))
1184  {
1185  jobID = cmdline.toInt("jobid");
1186  uint chanid;
1187  QDateTime starttime;
1188 
1189  if (!JobQueue::GetJobInfoFromID(jobID, jobType, chanid, starttime))
1190  {
1191  cerr << "mythcommflag: ERROR: Unable to find DB info for "
1192  << "JobQueue ID# " << jobID << endl;
1194  }
1195  force = true;
1196  int jobQueueCPU = gCoreContext->GetNumSetting("JobQueueCPU", 0);
1197 
1198  if (jobQueueCPU < 2)
1199  {
1200  myth_nice(17);
1201  myth_ioprio((0 == jobQueueCPU) ? 8 : 7);
1202  }
1203 
1204  progress = false;
1205 
1206  int ret = 0;
1207 
1209  RebuildSeekTable(chanid, starttime, jobID);
1210  else
1211  ret = FlagCommercials(chanid, starttime, jobID, "", jobQueueCPU != 0);
1212 
1213  if (ret > GENERIC_EXIT_NOT_OK)
1214  JobQueue::ChangeJobStatus(jobID, JOB_ERRORED,
1215  QCoreApplication::translate("(mythcommflag)",
1216  "Failed with exit status %1",
1217  "Job status").arg(ret));
1218  else
1219  JobQueue::ChangeJobStatus(jobID, JOB_FINISHED,
1220  QCoreApplication::translate("(mythcommflag)",
1221  "%n commercial break(s)",
1222  "Job status",
1223  ret));
1224  }
1225  else if (cmdline.toBool("video"))
1226  {
1227  // build skiplist for video file
1228  return RebuildSeekTable(cmdline.toString("video"), -1);
1229  }
1230  else if (cmdline.toBool("file"))
1231  {
1232  if (cmdline.toBool("skipdb"))
1233  {
1234  if (cmdline.toBool("rebuild"))
1235  {
1236  cerr << "The --rebuild parameter builds the seektable for "
1237  "internal MythTV use only. It cannot be used in "
1238  "combination with --skipdb." << endl;
1240  }
1241 
1242  if (!cmdline.toBool("outputfile"))
1243  cmdline.SetValue("outputfile", "-");
1244 
1245  // perform commercial flagging on file outside the database
1246  FlagCommercials(cmdline.toString("file"), -1,
1247  cmdline.toString("outputfile"),
1248  !cmdline.toBool("skipdb"),
1249  true);
1250  }
1251  else
1252  {
1253  ProgramInfo pginfo(cmdline.toString("file"));
1254  // pass chanid and starttime
1255  // inefficient, but it lets the other function
1256  // handle sanity checking
1257  if (cmdline.toBool("rebuild"))
1258  result = RebuildSeekTable(pginfo.GetChanID(),
1259  pginfo.GetRecordingStartTime(),
1260  -1, cmdline.toBool("writefile"));
1261  else
1262  result = FlagCommercials(pginfo.GetChanID(),
1263  pginfo.GetRecordingStartTime(),
1264  -1, cmdline.toString("outputfile"),
1265  true);
1266  }
1267  }
1268  else if (cmdline.toBool("queue"))
1269  {
1270  // run flagging for all recordings with no skiplist
1271  MSqlQuery query(MSqlQuery::InitCon());
1272  query.prepare("SELECT r.chanid, r.starttime, c.commmethod "
1273  "FROM recorded AS r "
1274  "LEFT JOIN channel AS c ON r.chanid=c.chanid "
1275 // "WHERE startime >= :STARTTIME AND endtime <= :ENDTIME "
1276  "ORDER BY starttime;");
1277  //query.bindValue(":STARTTIME", allStart);
1278  //query.bindValue(":ENDTIME", allEnd);
1279 
1280  if (query.exec() && query.isActive() && query.size() > 0)
1281  {
1282  QDateTime starttime;
1283 
1284  while (query.next())
1285  {
1286  starttime = MythDate::fromString(query.value(1).toString());
1287  uint chanid = query.value(0).toUInt();
1288 
1289  if (!cmdline.toBool("force") && !cmdline.toBool("rebuild"))
1290  {
1291  // recording is already flagged
1292  if (IsMarked(chanid, starttime))
1293  continue;
1294 
1295  // channel is marked as commercial free
1296  if (query.value(2).toInt() == COMM_DETECT_COMMFREE)
1297  continue;
1298 
1299  // recording rule did not enable commflagging
1300 #if 0
1301  RecordingInfo recinfo(chanid, starttime);
1302  if (!(recinfo.GetAutoRunJobs() & JOB_COMMFLAG))
1303  continue;
1304 #endif
1305  }
1306 
1307  QueueCommFlagJob(chanid, starttime, cmdline.toBool("rebuild"));
1308  }
1309  }
1310 
1311  }
1312  else
1313  {
1314  LOG(VB_GENERAL, LOG_ERR,
1315  "No valid combination of command inputs received.");
1316  cmdline.PrintHelp();
1318  }
1319 
1320  return result;
1321 }
1322 
1323 
1324 /* vim: set expandtab tabstop=4 shiftwidth=4: */
#define GENERIC_EXIT_DB_ERROR
Database error.
Definition: exitcodes.h:17
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:794
SkipTypes
This is used as a bitmask.
Definition: programtypes.h:91
Startup context for MythTV.
Definition: mythcontext.h:42
static int SetCutList(uint chanid, QDateTime starttime, QString newCutList)
static int GetMarkupList(QString list, uint chanid, QDateTime starttime)
void bindValue(const QString &placeholder, const QVariant &val)
Definition: mythdbcon.cpp:875
static int FlagCommercials(ProgramInfo *program_info, int jobid, const QString &outputfilename, bool useDB, bool fullSpeed)
static void commDetectorGotNewCommercialBreakList(void)
PlayerFlags
Definition: mythplayer.h:88
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
virtual uint64_t GetFilesize(void) const
void RegisterFileForWrite(const QString &file, uint64_t size=0LL)
#define GENERIC_EXIT_PERMISSIONS_ERROR
File permissions error.
Definition: exitcodes.h:19
void SetPathname(const QString &) const
static void incomingCustomEvent(QEvent *e)
static Type MythEventMessage
Definition: mythevent.h:65
void SaveCommFlagged(CommFlagStatus flag)
Set "commflagged" field in "recorded" table to "flag".
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
bool myth_ioprio(int)
Allows setting the I/O priority of the current process/thread.
void PrintHelp(void) const
Print command line option help.
void SaveMarkupFlag(MarkTypes type) const
Clears the specified flag, then if sets it.
bool QueryCutList(frm_dir_map_t &, bool loadAutosave=false) const
QString GetTitle(void) const
Definition: programinfo.h:355
Default UTC, "yyyyMMddhhmmss".
Definition: mythdate.h:15
bool ConnectToMasterServer(bool blockingClient=true, bool openEventSocket=true)
int size(void) const
Definition: mythdbcon.h:187
static void Init(QList< int > &signallist, QObject *parent=nullptr)
static bool ChangeJobStatus(int jobID, int newStatus, QString comment="")
Definition: jobqueue.cpp:1006
void SetPlayer(MythPlayer *new_player)
static enum JobCmds GetJobCmd(int jobID)
Definition: jobqueue.cpp:1488
Holds information on a TV Program one might wish to record.
Definition: recordinginfo.h:34
void SetRingBuffer(RingBuffer *buf)
const char * kFlaggerInUseID
virtual void GetCommercialBreakList(frm_dir_map_t &comms)=0
static void UpdateFileSize(ProgramInfo *program_info)
void QueryCommBreakList(frm_dir_map_t &) const
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:81
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static RingBuffer * Create(const QString &xfilename, bool write, bool usereadahead=true, int timeout_ms=kDefaultOpenTimeout, bool stream_only=false)
Creates a RingBuffer instance.
Definition: ringbuffer.cpp:112
virtual void requestCommBreakMapUpdate(void)
void SaveCommBreakList(frm_dir_map_t &) const
static void streamOutCommercialBreakList(ostream &output, const frm_dir_map_t &commercialBreakList)
void SetRecorder(RemoteEncoder *rec)
bool toBool(QString key) const
Returns stored QVariant as a boolean.
MythContext * gContext
This global variable contains the MythContext instance for the application.
Definition: mythcontext.cpp:63
uint64_t QueryLastFrameInPosMap(void) const
Returns last frame in position map or 0.
bool SetValue(const QString &key, QVariant value)
Set a new stored value for an existing argument definition, or spawn a new definition store value in.
static guint32 * tmp
Definition: goom_core.c:35
#define GENERIC_EXIT_IN_USE
Recording in use, can't flag.
Definition: exitcodes.h:34
static bool IsMarked(uint chanid, QDateTime starttime)
int main(int argc, char *argv[])
unsigned sleep(unsigned int x)
Definition: compat.h:152
QMap< QString, OutputMethod > * outputTypes
void SendMessage(const QString &message)
unsigned char b
Definition: ParseText.cpp:340
int GetAutoRunJobs(void) const
Returns a bitmap of which jobs are attached to this RecordingInfo.
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:384
QVariant value(int i) const
Definition: mythdbcon.h:182
static QString get_filename(ProgramInfo *program_info)
QString MakeUniqueKey(void) const
Creates a unique string that can be used to identify an existing recording.
Definition: programinfo.h:333
void ApplySettingsOverride(void)
Apply all overrides to the global context.
Holds information on recordings and videos.
Definition: programinfo.h:66
static void commDetectorBreathe()
void SetPlayingInfo(const ProgramInfo *info)
assign programinfo to the context
bool Init(const bool gui=true, const bool promptForBackend=false, const bool bypassAutoDiscovery=false, const bool ignoreDB=false)
virtual void SaveFilesize(uint64_t fsize)
Sets recording file size in database, and sets "filesize" field.
This class is used as a container for messages.
Definition: mythevent.h:15
bool RebuildSeekTable(bool showPercentage=true, StatusCallback cb=nullptr, void *cbData=nullptr)
static bool QueueJob(int jobType, uint chanid, const QDateTime &recstartts, QString args="", QString comment="", QString host="", int flags=0, int status=JOB_QUEUED, QDateTime schedruntime=QDateTime())
Definition: jobqueue.cpp:525
static bool GetJobInfoFromID(int jobID, int &jobType, uint &chanid, QDateTime &recstartts)
Definition: jobqueue.cpp:683
#define GENERIC_EXIT_NO_RECORDING_DATA
No program/recording data.
Definition: exitcodes.h:29
static int DoFlagCommercials(ProgramInfo *program_info, bool showPercentage, bool fullSpeed, int jobid, MythCommFlagPlayer *cfp, enum SkipTypes commDetectMethod, const QString &outputfilename, bool useDB)
static bool ExtractKey(const QString &uniquekey, uint &chanid, QDateTime &recstartts)
Extracts chanid and recstartts from a unique key generated by MakeUniqueKey().
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QString GetSubtitle(void) const
Definition: programinfo.h:357
bool isActive(void) const
Definition: mythdbcon.h:188
CommDetectorBase * commDetector
static void load(const QString &module_name)
Load a QTranslator for the user's preferred language.
Abstract base class for all CommDetectors.
static bool ChangeJobComment(int jobID, QString comment="")
Definition: jobqueue.cpp:1033
static bool testDBConnection()
Checks DB connection + login (login info via Mythcontext)
Definition: mythdbcon.cpp:863
static int RebuildSeekTable(ProgramInfo *pginfo, int jobid, bool writefile=false)
static void Done(void)
static QMap< QString, OutputMethod > * init_output_types()
QString toString(QString key) const
Returns stored QVariant as a QString, falling to default if not provided.
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:547
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:391
void SaveTotalDuration(void)
MythCommFlagCommandLineParser cmdline
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:101
QDateTime toDateTime(QString key) const
Returns stored QVariant as a QDateTime, falling to default if not provided.
static bool IsJobRunning(int jobType, uint chanid, const QDateTime &recstartts)
Definition: jobqueue.cpp:1112
long long GetFileSize(void) const
GetFileSize: returns the remote file's size at the time it was first opened Will query the server in ...
#define MYTH_APPNAME_MYTHCOMMFLAG
void UnregisterFileForWrite(const QString &file)
void SetPlayerInfo(TV *tv, QWidget *widget, PlayerContext *ctx)
void SaveCutList(frm_dir_map_t &, bool isAutoSave=false) const
int GetNumSetting(const QString &key, int defaultval=0)
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:819
bool myth_nice(int val)
ProgramInfo * global_program_info
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QMap< QString, SkipTypes > * skipTypes
virtual void recordingFinished(long long totalFileSize)
virtual void PrintFullMap(ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const =0
virtual bool go()=0
static void print_comm_flag_output(const ProgramInfo *program_info, const frm_dir_map_t &commBreakList, uint64_t frame_count, const CommDetectorBase *commDetect, const QString &output_filename)
static int QueueCommFlagJob(uint chanid, QDateTime starttime, bool rebuild)
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
static bool DoesFileExist(ProgramInfo *program_info)
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:366
OutputMethod outputMethod
static void cleanup(VideoFilter *filter)
int GetRecorderNumber(void) const
QString GetPlaybackURL(bool checkMaster=false, bool forceCheckLocal=false) const
Returns filename or URL to be used to play back this recording.
#define SIGHUP
Definition: compat.h:206
uint64_t GetTotalFrameCount(void) const
Definition: mythplayer.h:194
static void commDetectorStatusUpdate(const QString &status)
static int CopySkipListToCutList(uint chanid, QDateTime starttime)
#define MYTH_BINARY_VERSION
Update this whenever the plug-in ABI changes.
Definition: mythversion.h:16
static enum JobFlags GetJobFlags(int jobID)
Definition: jobqueue.cpp:1530
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:398
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:406
RemoteEncoder * recorder
int toInt(QString key) const
Returns stored QVariant as an integer, falling to default if not provided.
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:615
Implements a file/stream reader/writer.
int ConfigureLogging(QString mask="general", unsigned int progress=0)
Read in logging options and initialize the logging interface.
#define GENERIC_EXIT_NO_MYTHCONTEXT
No MythContext available.
Definition: exitcodes.h:13
static void SetHandler(int signal, SigHandlerFunc handler)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
#define GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:15
static qint64 GetFileSize(ProgramInfo *program_info)
const QString & Message() const
Definition: mythevent.h:57
#define GENERIC_EXIT_NOT_OK
Exited with error.
Definition: exitcodes.h:11
QString GetHostName(void)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
QString GetPathname(void) const
Definition: programinfo.h:337
CommDetectorBase * makeCommDetector(SkipType commDetectMethod, bool showProgress, bool fullSpeed, MythPlayer *player, int chanid, const QDateTime &startedAt, const QDateTime &stopsAt, const QDateTime &recordingStartedAt, const QDateTime &recordingStopsAt, bool useDB)
void SetWatchingRecording(bool mode)
Definition: mythplayer.cpp:341
virtual void deleteLater(void)
static QMap< QString, SkipTypes > * init_skip_types()
void PrintVersion(void) const
Print application version information.
Default UTC.
Definition: mythdate.h:14
uint toUInt(QString key) const
Returns stored QVariant as an unsigned integer, falling to default if not provided.
RemoteEncoder * RemoteGetExistingRecorder(const ProgramInfo *pginfo)
static int ClearSkipList(uint chanid, QDateTime starttime)
#define output