18 #include <QCoreApplication>
38 #include "ringbuffer.h"
39 #include "commandlineparser.h"
50 #define LOC QString("MythCommFlag: ")
51 #define LOC_WARN QString("MythCommFlag, Warning: ")
52 #define LOC_ERR QString("MythCommFlag, Error: ")
66 typedef void (*CleanupFunc)();
69 CleanupGuard(CleanupFunc cleanFunction) :
70 m_cleanFunction(cleanFunction) {}
78 CleanupFunc m_cleanFunction;
102 QMap<QString,SkipTypes> *
tmp =
new QMap<QString,SkipTypes>;
133 QMap<QString,OutputMethod> *
tmp =
new QMap<QString,OutputMethod>;
156 QString
tmp = QString(
157 "Unable to find program info for chanid %1 @ %2")
158 .arg(chanid).arg(startstring);
159 cerr << tmp.toLocal8Bit().constData() << endl;
161 return GENERIC_EXIT_NO_RECORDING_DATA;
166 QString
tmp = QString(
"Job have been queued for chanid %1 @ %2")
167 .arg(chanid).arg(startstring);
168 cerr << tmp.toLocal8Bit().constData() << endl;
169 return GENERIC_EXIT_OK;
174 rebuild ?
JOB_REBUILD : 0, JOB_QUEUED, QDateTime());
180 QString
tmp = QString(
"Job Queued for chanid %1 @ %2")
181 .arg(chanid).arg(startstring);
182 cerr << tmp.toLocal8Bit().constData() << endl;
184 return GENERIC_EXIT_OK;
190 QString
tmp = QString(
"Error queueing job for chanid %1 @ %2")
191 .arg(chanid).arg(startstring);
192 cerr << tmp.toLocal8Bit().constData() << endl;
194 return GENERIC_EXIT_DB_ERROR;
197 return GENERIC_EXIT_OK;
203 frm_dir_map_t::const_iterator it;
210 LOG(VB_GENERAL, LOG_ERR,
211 QString(
"No program data exists for channel %1 at %2")
212 .arg(chanid).arg(startstring));
213 return GENERIC_EXIT_NO_RECORDING_DATA;
217 for (it = cutlist.begin(); it != cutlist.end(); ++it)
224 return GENERIC_EXIT_OK;
234 LOG(VB_GENERAL, LOG_ERR,
235 QString(
"No program data exists for channel %1 at %2")
236 .arg(chanid).arg(startstring));
237 return GENERIC_EXIT_NO_RECORDING_DATA;
243 LOG(VB_GENERAL, LOG_NOTICE,
"Commercial skip list cleared");
245 return GENERIC_EXIT_OK;
252 newCutList.replace(QRegExp(
" "),
"");
254 QStringList tokens = newCutList.split(
",", QString::SkipEmptyParts);
256 for (
int i = 0; i < tokens.size(); i++)
258 QStringList cutpair = tokens[i].split(
"-", QString::SkipEmptyParts);
268 LOG(VB_GENERAL, LOG_ERR,
269 QString(
"No program data exists for channel %1 at %2")
270 .arg(chanid).arg(startstring));
271 return GENERIC_EXIT_NO_RECORDING_DATA;
276 LOG(VB_GENERAL, LOG_NOTICE, QString(
"Cutlist set to: %1").arg(newCutList));
278 return GENERIC_EXIT_OK;
284 frm_dir_map_t::const_iterator it;
292 LOG(VB_GENERAL, LOG_ERR,
293 QString(
"No program data exists for channel %1 at %2")
294 .arg(chanid).arg(startstring));
295 return GENERIC_EXIT_NO_RECORDING_DATA;
298 if (list ==
"cutlist")
303 uint64_t lastStart = 0;
304 for (it = cutlist.begin(); it != cutlist.end(); ++it)
309 if (!result.isEmpty())
311 lastStart = it.key();
312 result += QString(
"%1-").arg(lastStart);
316 if (result.isEmpty())
318 result += QString(
"%1").arg(it.key());
322 if (result.endsWith(
'-'))
325 if (lastFrame > lastStart)
326 result += QString(
"%1").arg(lastFrame);
329 if (list ==
"cutlist")
330 cout << QString(
"Cutlist: %1\n").arg(result).toLocal8Bit().constData();
333 cout << QString(
"Commercial Skip List: %1\n")
334 .arg(result).toLocal8Bit().constData();
337 return GENERIC_EXIT_OK;
344 output <<
"----------------------------" << endl;
346 if (commercialBreakList.empty())
349 output <<
"No breaks" << endl;
353 frm_dir_map_t::const_iterator it = commercialBreakList.begin();
354 for (; it != commercialBreakList.end(); ++it)
356 output <<
"framenum: " << it.key() <<
"\tmarktype: " << *it
362 output <<
"----------------------------" << endl;
368 uint64_t frame_count,
370 const QString &output_filename)
372 if (output_filename.isEmpty())
375 ostream *out = &cout;
376 if (output_filename !=
"-")
378 QByteArray
tmp = output_filename.toLocal8Bit();
379 out =
new fstream(tmp.constData(), ios::app | ios::out );
387 tmp = QString(
"commercialBreakListFor: %1 on %2 @ %3")
394 tmp = QString(
"commercialBreakListFor: %1")
398 const QByteArray tmp2 = tmp.toLocal8Bit();
399 *out << tmp2.constData() << endl;
402 *out <<
"totalframecount: " << frame_count << endl;
410 if (output_filename !=
"-")
418 qApp->processEvents();
436 QCoreApplication::translate(
"(mythcommflag)",
437 "Paused",
"Job status"));
444 QCoreApplication::translate(
"(mythcommflag)",
445 "Running",
"Job status"));
467 frm_dir_map_t::Iterator it = newCommercialMap.begin();
468 QString message =
"COMMFLAG_UPDATE ";
471 for (it = newCommercialMap.begin();
472 it != newCommercialMap.end(); ++it)
474 if (it != newCommercialMap.begin())
478 message += QString(
"%1:%2").arg(it.key())
482 LOG(VB_COMMFLAG, LOG_INFO,
483 QString(
"mythcommflag sending update: %1").arg(message));
493 QString message = me->
Message();
495 message = message.simplified();
496 QStringList tokens = message.split(
" ", QString::SkipEmptyParts);
498 LOG(VB_COMMFLAG, LOG_INFO,
499 QString(
"mythcommflag: Received Event: '%1'") .arg(message));
502 (tokens[0] ==
"DONE_RECORDING"))
504 int cardnum = tokens[1].toInt();
505 int filelen = tokens[2].toInt();
507 message = QString(
"mythcommflag: Received a "
508 "DONE_RECORDING event for card %1. ")
515 message +=
"Informed CommDetector that recording has finished.";
516 LOG(VB_COMMFLAG, LOG_INFO, message);
520 if ((tokens.size() >= 2) && (tokens[0] ==
"COMMFLAG_REQUEST"))
523 QDateTime recstartts;
526 message = QString(
"mythcommflag: Received a "
527 "COMMFLAG_REQUEST event for chanid %1 @ %2. ")
528 .arg(chanid).arg(recstartts.toString(
Qt::ISODate));
534 message +=
"Requested CommDetector to generate new break list.";
535 LOG(VB_COMMFLAG, LOG_INFO, message);
543 bool showPercentage,
bool fullSpeed,
int jobid,
545 const QString &outputfilename,
bool useDB)
549 commDetectMethod, showPercentage,
558 LOG(VB_COMMFLAG, LOG_INFO,
559 QString(
"mythcommflag processing JobID %1").arg(jobid));
570 QObject::connect(
commDetector, SIGNAL(statusUpdate(
const QString&)),
571 b, SLOT(relay(
const QString&)));
572 QObject::connect(
commDetector, SIGNAL(gotNewCommercialBreakList()),
577 LOG(VB_COMMFLAG, LOG_INFO,
578 "mythcommflag sending COMMFLAG_START notification");
579 QString message =
"COMMFLAG_START ";
593 comms_found = commBreakList.size() / 2;
631 if (filename.startsWith(
"myth://"))
633 RemoteFile remotefile(filename,
false,
false, 0);
638 QFile file(filename);
655 LOG(VB_GENERAL, LOG_ERR, QString(
"Couldn't find file %1, aborting.")
662 LOG(VB_GENERAL, LOG_ERR, QString(
"File %1 is zero-byte, aborting.")
681 mark_query.
prepare(
"SELECT commflagged, count(rm.type) "
683 "LEFT JOIN recordedmarkup rm ON "
684 "( r.chanid = rm.chanid AND "
685 "r.starttime = rm.starttime AND "
686 "type in (:MARK_START,:MARK_END)) "
687 "WHERE r.chanid = :CHANID AND "
688 "r.starttime = :STARTTIME "
689 "GROUP BY COMMFLAGGED;");
693 mark_query.
bindValue(
":STARTTIME", starttime);
696 mark_query.
size() > 0)
698 if (mark_query.
next())
700 int flagStatus = mark_query.
value(0).toInt();
701 int marksFound = mark_query.
value(1).toInt();
703 QString flagStatusStr =
"UNKNOWN";
704 switch (flagStatus) {
706 flagStatusStr =
"Not Flagged";
709 flagStatusStr = QString(
"Flagged with %1 breaks")
710 .arg(marksFound / 2);
713 flagStatusStr =
"Flagging";
716 flagStatusStr =
"Commercial Free";
720 LOG(VB_COMMFLAG, LOG_INFO,
721 QString(
"Status for chanid %1 @ %2 is '%3'")
723 .arg(flagStatusStr));
733 const QString &outputfilename,
bool useDB,
bool fullSpeed)
751 commDetectMethod = (
SkipTypes) commmethod.toInt(&ok);
756 QMap<QString, SkipTypes>::const_iterator sit;
758 QStringList list = commmethod.split(
",", QString::SkipEmptyParts);
759 QStringList::const_iterator it = list.begin();
760 for (; it != list.end(); ++it)
762 QString val = (*it).toLower();
771 cerr <<
"Failed to decode --method option '"
772 << val.toLatin1().constData()
774 return GENERIC_EXIT_INVALID_CMDLINE;
778 commDetectMethod = (
SkipTypes) ((
int)commDetectMethod
784 return GENERIC_EXIT_INVALID_CMDLINE;
791 query.
prepare(
"SELECT commmethod FROM channel "
792 "WHERE chanid = :CHANID;");
801 else if (query.
next())
810 LOG(VB_COMMFLAG, LOG_INFO,
811 QString(
"Chanid %1 is marked as being Commercial Free, "
812 "we will use the default commercial detection "
813 "method").arg(program_info->
GetChanID()));
820 LOG(VB_COMMFLAG, LOG_INFO,
821 QString(
"Using method: %1 from channel %2")
822 .arg(commDetectMethod).arg(program_info->
GetChanID()));
832 return GENERIC_EXIT_NOT_OK;
834 return GENERIC_EXIT_OK;
856 LOG(VB_GENERAL, LOG_ERR,
857 "Unable to find file in defined storage paths.");
858 return GENERIC_EXIT_PERMISSIONS_ERROR;
866 LOG(VB_GENERAL, LOG_ERR,
867 QString(
"Unable to create RingBuffer for %1").arg(filename));
869 return GENERIC_EXIT_PERMISSIONS_ERROR;
876 LOG(VB_GENERAL, LOG_ERR,
"Unable to open commflag DB connection");
879 return GENERIC_EXIT_DB_ERROR;
915 LOG(VB_COMMFLAG, LOG_INFO,
916 QString(
"mythcommflag will flag recording "
917 "currently in progress on cardid %1")
925 LOG(VB_GENERAL, LOG_ERR,
926 "Unable to find active recorder for this "
927 "recording, realtime flagging will not be enabled.");
936 program_info,
progress, fullSpeed, jobid,
937 cfp, commDetectMethod, outputfilename, useDB);
940 cerr << breaksFound <<
"\n";
942 LOG(VB_GENERAL, LOG_NOTICE, QString(
"Finished, %1 break(s) found.")
952 int jobid,
const QString &outputfilename,
960 LOG(VB_GENERAL, LOG_ERR,
961 QString(
"No program data exists for channel %1 at %2")
962 .arg(chanid).arg(startstring));
963 return GENERIC_EXIT_NO_RECORDING_DATA;
972 "(the program is already being flagged elsewhere)\n";
974 LOG(VB_GENERAL, LOG_ERR,
"Program is already being flagged elsewhere");
975 return GENERIC_EXIT_IN_USE;
981 cerr <<
"MythTV Commercial Flagger, flagging commercials for:" << endl;
983 cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() << endl;
985 cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() <<
" - "
986 << pginfo.
GetSubtitle().toLocal8Bit().constData() << endl;
989 return FlagCommercials(&pginfo, jobid, outputfilename,
true, fullSpeed);
993 const QString &outputfilename,
bool useDB,
999 cerr <<
"MythTV Commercial Flagger, flagging commercials for:" << endl
1000 <<
" " << filename.toLatin1().constData() << endl;
1004 return FlagCommercials(&pginfo, jobid, outputfilename, useDB, fullSpeed);
1017 filename = QString(
"myth://Videos@%1/%2")
1022 LOG(VB_GENERAL, LOG_ERR,
1023 "Unable to find file in defined storage paths.");
1024 return GENERIC_EXIT_PERMISSIONS_ERROR;
1035 LOG(VB_GENERAL, LOG_ERR,
1036 QString(
"Unable to create RingBuffer for %1").arg(filename));
1037 return GENERIC_EXIT_PERMISSIONS_ERROR;
1050 QString time = QDateTime::currentDateTime().toString(Qt::TextDate);
1051 cerr <<
"Rebuild started at " << qPrintable(time) << endl;
1058 QString time = QDateTime::currentDateTime().toString(Qt::TextDate);
1059 cerr <<
"Rebuild completed at " << qPrintable(time) << endl;
1064 return GENERIC_EXIT_OK;
1071 cerr <<
"MythTV Commercial Flagger, building seek table for:" << endl
1072 <<
" " << filename.toLatin1().constData() << endl;
1083 cerr <<
"MythTV Commercial Flagger, building seek table for:" << endl;
1085 cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() << endl;
1087 cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() <<
" - "
1088 << pginfo.
GetSubtitle().toLocal8Bit().constData() << endl;
1095 int result = GENERIC_EXIT_OK;
1104 return GENERIC_EXIT_INVALID_CMDLINE;
1110 return GENERIC_EXIT_OK;
1116 return GENERIC_EXIT_OK;
1119 QCoreApplication a(argc, argv);
1120 QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHCOMMFLAG);
1123 if (retval != GENERIC_EXIT_OK)
1126 CleanupGuard callCleanup(
cleanup);
1129 QList<int> signallist;
1130 signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
1133 signallist << SIGRTMIN;
1136 signal(SIGHUP, SIG_IGN);
1145 LOG(VB_GENERAL, LOG_EMERG,
"Failed to init MythContext, exiting.");
1146 return GENERIC_EXIT_NO_MYTHCONTEXT;
1186 QDateTime starttime;
1190 cerr <<
"mythcommflag: ERROR: Unable to find DB info for "
1191 <<
"JobQueue ID# " <<
jobID << endl;
1192 return GENERIC_EXIT_NO_RECORDING_DATA;
1197 if (jobQueueCPU < 2)
1212 if (ret > GENERIC_EXIT_NOT_OK)
1214 QCoreApplication::translate(
"(mythcommflag)",
1215 "Failed with exit status %1",
1216 "Job status").arg(ret));
1219 QCoreApplication::translate(
"(mythcommflag)",
1220 "%1 commercial break(s)",
1221 "Job status").arg(ret));
1234 cerr <<
"The --rebuild parameter builds the seektable for "
1235 "internal MythTV use only. It cannot be used in "
1236 "combination with --skipdb." << endl;
1237 return GENERIC_EXIT_INVALID_CMDLINE;
1257 pginfo.GetRecordingStartTime(),
1261 pginfo.GetRecordingStartTime(),
1270 query.
prepare(
"SELECT r.chanid, r.starttime, c.commmethod "
1271 "FROM recorded AS r "
1272 "LEFT JOIN channel AS c ON r.chanid=c.chanid "
1274 "ORDER BY starttime;");
1280 QDateTime starttime;
1283 while (query.
next())
1286 chanid = query.
value(0).toUInt();
1313 LOG(VB_GENERAL, LOG_ERR,
1314 "No valid combination of command inputs received.");
1316 return GENERIC_EXIT_INVALID_CMDLINE;