2#if defined ANDROID && __ANDROID_API__ < 24
20#include <QCoreApplication>
36#include "libmythbase/mythversion.h"
54#define LOC QString("MythCommFlag: ")
55#define LOC_WARN QString("MythCommFlag, Warning: ")
56#define LOC_ERR QString("MythCommFlag, Error: ")
78 auto *
tmp =
new QMap<QString,SkipType>;
109 auto *
tmp =
new QMap<QString,OutputMethod>;
132 QString
tmp = QString(
133 "Unable to find program info for chanid %1 @ %2")
134 .arg(chanid).arg(startstring);
135 std::cerr <<
tmp.toLocal8Bit().constData() << std::endl;
142 QString
tmp = QString(
"Job have been queued for chanid %1 @ %2")
143 .arg(chanid).arg(startstring);
144 std::cerr <<
tmp.toLocal8Bit().constData() << std::endl;
150 rebuild ?
JOB_REBUILD : 0, JOB_QUEUED, QDateTime());
156 QString
tmp = QString(
"Job Queued for chanid %1 @ %2")
157 .arg(chanid).arg(startstring);
158 std::cerr <<
tmp.toLocal8Bit().constData() << std::endl;
165 QString
tmp = QString(
"Error queueing job for chanid %1 @ %2")
166 .arg(chanid).arg(startstring);
167 std::cerr <<
tmp.toLocal8Bit().constData() << std::endl;
176 output <<
"----------------------------" << std::endl;
178 if (commercialBreakList.empty())
181 output <<
"No breaks" << std::endl;
185 frm_dir_map_t::const_iterator it = commercialBreakList.begin();
186 for (; it != commercialBreakList.end(); ++it)
188 output <<
"framenum: " << it.key() <<
"\tmarktype: " << *it
194 output <<
"----------------------------" << std::endl;
200 uint64_t frame_count,
202 const QString &output_filename)
204 if (output_filename.isEmpty())
207 std::ostream *out = &std::cout;
208 if (output_filename !=
"-")
210 QByteArray
tmp = output_filename.toLocal8Bit();
211 out =
new std::fstream(
tmp.constData(), std::ios::app | std::ios::out );
219 tmp = QString(
"commercialBreakListFor: %1 on %2 @ %3")
226 tmp = QString(
"commercialBreakListFor: %1")
230 const QByteArray tmp2 =
tmp.toLocal8Bit();
231 *out << tmp2.constData() << std::endl;
234 *out <<
"totalframecount: " << frame_count << std::endl;
242 if (out != &std::cout)
250 qApp->processEvents();
268 QCoreApplication::translate(
"(mythcommflag)",
269 "Paused",
"Job status"));
276 QCoreApplication::translate(
"(mythcommflag)",
277 "Running",
"Job status"));
299 QString message =
"COMMFLAG_UPDATE ";
302 for (
auto it = newCommercialMap.begin();
303 it != newCommercialMap.end(); ++it)
305 if (it != newCommercialMap.begin())
309 message += QString(
"%1:%2").arg(it.key())
313 LOG(VB_COMMFLAG, LOG_INFO,
314 QString(
"mythcommflag sending update: %1").arg(message));
327 QString message = me->
Message();
329 message = message.simplified();
330 QStringList tokens = message.split(
" ", Qt::SkipEmptyParts);
332 LOG(VB_COMMFLAG, LOG_INFO,
333 QString(
"mythcommflag: Received Event: '%1'") .arg(message));
336 (tokens[0] ==
"DONE_RECORDING"))
338 int cardnum = tokens[1].toInt();
339 int filelen = tokens[2].toInt();
341 message = QString(
"mythcommflag: Received a "
342 "DONE_RECORDING event for card %1. ")
349 message +=
"Informed CommDetector that recording has finished.";
350 LOG(VB_COMMFLAG, LOG_INFO, message);
354 if ((tokens.size() >= 2) && (tokens[0] ==
"COMMFLAG_REQUEST"))
357 QDateTime recstartts;
360 message = QString(
"mythcommflag: Received a "
361 "COMMFLAG_REQUEST event for chanid %1 @ %2. ")
362 .arg(chanid).arg(recstartts.toString(
Qt::ISODate));
368 message +=
"Requested CommDetector to generate new break list.";
369 LOG(VB_COMMFLAG, LOG_INFO, message);
377 bool showPercentage,
bool fullSpeed,
int jobid,
379 const QString &outputfilename,
bool useDB)
382 commDetectMethod, showPercentage,
391 LOG(VB_COMMFLAG, LOG_INFO,
392 QString(
"mythcommflag processing JobID %1").arg(jobid));
410 LOG(VB_COMMFLAG, LOG_INFO,
411 "mythcommflag sending COMMFLAG_START notification");
412 QString message =
"COMMFLAG_START ";
426 comms_found = commBreakList.size() / 2;
488 LOG(VB_GENERAL, LOG_ERR, QString(
"Couldn't find file %1, aborting.")
495 LOG(VB_GENERAL, LOG_ERR, QString(
"File %1 is zero-byte, aborting.")
514 mark_query.
prepare(
"SELECT commflagged, count(rm.type) "
516 "LEFT JOIN recordedmarkup rm ON "
517 "( r.chanid = rm.chanid AND "
518 "r.starttime = rm.starttime AND "
519 "type in (:MARK_START,:MARK_END)) "
520 "WHERE r.chanid = :CHANID AND "
521 "r.starttime = :STARTTIME "
522 "GROUP BY COMMFLAGGED;");
526 mark_query.
bindValue(
":STARTTIME", starttime);
529 mark_query.
size() > 0)
531 if (mark_query.
next())
533 int flagStatus = mark_query.
value(0).toInt();
534 int marksFound = mark_query.
value(1).toInt();
536 QString flagStatusStr =
"UNKNOWN";
537 switch (flagStatus) {
539 flagStatusStr =
"Not Flagged";
542 flagStatusStr = QString(
"Flagged with %1 breaks")
543 .arg(marksFound / 2);
546 flagStatusStr =
"Flagging";
549 flagStatusStr =
"Commercial Free";
553 LOG(VB_COMMFLAG, LOG_INFO,
554 QString(
"Status for chanid %1 @ %2 is '%3'")
555 .arg(QString::number(chanid),
567 const QString &outputfilename,
bool useDB,
bool fullSpeed)
584 commDetectMethod = (
SkipType) commmethod.toInt(&ok);
590 QStringList list = commmethod.split(
",", Qt::SkipEmptyParts);
591 for (
const auto & it : std::as_const(list))
593 QString val = it.toLower();
602 std::cerr <<
"Failed to decode --method option '"
603 << val.toLatin1().constData()
609 commDetectMethod =
skipTypes->value(val);
611 commDetectMethod = (
SkipType) ((
int)commDetectMethod
625 query.
prepare(
"SELECT commmethod FROM channel "
626 "WHERE chanid = :CHANID;");
635 else if (query.
next())
643 LOG(VB_COMMFLAG, LOG_INFO,
644 QString(
"Chanid %1 is marked as being Commercial Free, "
645 "we will use the default commercial detection "
646 "method").arg(program_info->
GetChanID()));
654 LOG(VB_COMMFLAG, LOG_INFO,
655 QString(
"Using method: %1 from channel %2")
656 .arg(commDetectMethod).arg(program_info->
GetChanID()));
691 LOG(VB_GENERAL, LOG_ERR,
692 "Unable to find file in defined storage paths.");
701 LOG(VB_GENERAL, LOG_ERR,
702 QString(
"Unable to create RingBuffer for %1").arg(
filename));
711 LOG(VB_GENERAL, LOG_ERR,
"Unable to open commflag DB connection");
727 LOG(VB_GENERAL, LOG_INFO,
"Enabling experimental flagging speedup (low resolution)");
740 ctx->SetPlayingInfo(program_info);
741 ctx->SetRingBuffer(tmprbuf);
757 LOG(VB_COMMFLAG, LOG_INFO,
758 QString(
"mythcommflag will flag recording "
759 "currently in progress on cardid %1")
767 LOG(VB_GENERAL, LOG_ERR,
768 "Unable to find active recorder for this "
769 "recording, realtime flagging will not be enabled.");
778 program_info,
progress, fullSpeed, jobid,
779 cfp, commDetectMethod, outputfilename, useDB);
782 std::cerr << breaksFound <<
"\n";
784 LOG(VB_GENERAL, LOG_NOTICE, QString(
"Finished, %1 break(s) found.")
794 int jobid,
const QString &outputfilename,
802 LOG(VB_GENERAL, LOG_ERR,
803 QString(
"No program data exists for channel %1 at %2")
804 .arg(chanid).arg(startstring));
812 std::cerr <<
"IN USE\n";
814 "(the program is already being flagged elsewhere)\n";
816 LOG(VB_GENERAL, LOG_ERR,
"Program is already being flagged elsewhere");
823 std::cerr <<
"MythTV Commercial Flagger, flagging commercials for:" << std::endl;
825 std::cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() << std::endl;
827 std::cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() <<
" - "
828 << pginfo.
GetSubtitle().toLocal8Bit().constData() << std::endl;
831 return FlagCommercials(&pginfo, jobid, outputfilename,
true, fullSpeed);
835 const QString &outputfilename,
bool useDB,
841 std::cerr <<
"MythTV Commercial Flagger, flagging commercials for:" << std::endl
842 <<
" " <<
filename.toLatin1().constData() << std::endl;
846 return FlagCommercials(&pginfo, jobid, outputfilename, useDB, fullSpeed);
859 filename = QString(
"myth://Videos@%1/%2")
864 LOG(VB_GENERAL, LOG_ERR,
865 QString(
"Unable to find file in defined storage "
866 "paths for JobQueue ID# %1.").arg(jobid));
878 LOG(VB_GENERAL, LOG_ERR,
879 QString(
"Unable to create RingBuffer for %1").arg(
filename));
887 ctx->SetPlayingInfo(pginfo);
888 ctx->SetRingBuffer(tmprbuf);
893 QString time = QDateTime::currentDateTime().toString(Qt::TextDate);
894 std::cerr <<
"Rebuild started at " << qPrintable(time) << std::endl;
905 QString time = QDateTime::currentDateTime().toString(Qt::TextDate);
906 std::cerr <<
"Rebuild completed at " << qPrintable(time) << std::endl;
918 std::cerr <<
"MythTV Commercial Flagger, building seek table for:" << std::endl
919 <<
" " <<
filename.toLatin1().constData() << std::endl;
930 std::cerr <<
"MythTV Commercial Flagger, building seek table for:" << std::endl;
932 std::cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() << std::endl;
934 std::cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() <<
" - "
935 << pginfo.
GetSubtitle().toLocal8Bit().constData() << std::endl;
940int main(
int argc,
char *argv[])
966 QCoreApplication a(argc, argv);
974 if (!context.Init(
false,
979 LOG(VB_GENERAL, LOG_EMERG,
"Failed to init MythContext, exiting.");
1014 QDateTime starttime;
1018 std::cerr <<
"mythcommflag: ERROR: Unable to find DB info for "
1019 <<
"JobQueue ID# " <<
jobID << std::endl;
1025 if (jobQueueCPU < 2)
1043 QCoreApplication::translate(
"(mythcommflag)",
1044 "Failed with exit status %1",
1045 "Job status").arg(ret));
1050 QCoreApplication::translate(
"(mythcommflag)",
1051 "%n commercial break(s)",
1067 std::cerr <<
"The --rebuild parameter builds the seektable for "
1068 "internal MythTV use only. It cannot be used in "
1069 "combination with --skipdb." << std::endl;
1107 query.
prepare(
"SELECT r.chanid, r.starttime, c.commmethod "
1108 "FROM recorded AS r "
1109 "LEFT JOIN channel AS c ON r.chanid=c.chanid "
1111 "ORDER BY starttime;");
1117 QDateTime starttime;
1119 while (query.
next())
1149 LOG(VB_GENERAL, LOG_ERR,
1150 "No valid combination of command inputs received.");
Abstract base class for all CommDetectors.
virtual void PrintFullMap(std::ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const =0
virtual void recordingFinished(long long totalFileSize)
virtual void GetCommercialBreakList(frm_dir_map_t &comms)=0
void statusUpdate(const QString &a)
void gotNewCommercialBreakList()
virtual void requestCommBreakMapUpdate(void)
static CommDetectorBase * makeCommDetector(SkipType commDetectMethod, bool showProgress, bool fullSpeed, MythCommFlagPlayer *player, int chanid, const QDateTime &startedAt, const QDateTime &stopsAt, const QDateTime &recordingStartedAt, const QDateTime &recordingStopsAt, bool useDB)
static bool GetJobInfoFromID(int jobID, int &jobType, uint &chanid, QDateTime &recstartts)
static enum JobFlags GetJobFlags(int jobID)
static enum JobCmds GetJobCmd(int jobID)
static bool QueueJob(int jobType, uint chanid, const QDateTime &recstartts, const QString &args="", const QString &comment="", QString host="", int flags=0, int status=JOB_QUEUED, QDateTime schedruntime=QDateTime())
static bool ChangeJobComment(int jobID, const QString &comment="")
static bool IsJobRunning(int jobType, uint chanid, const QDateTime &recstartts)
static bool ChangeJobStatus(int jobID, int newStatus, const QString &comment="")
QSqlQuery wrapper that fetches a DB connection from the connection pool.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
QVariant value(int i) const
static bool testDBConnection()
Checks DB connection + login (login info via Mythcontext)
bool isActive(void) const
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
int toInt(const QString &key) const
Returns stored QVariant as an integer, falling to default if not provided.
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
void ApplySettingsOverride(void)
Apply all overrides to the global context.
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
static void PrintVersion(void)
Print application version information.
bool SetValue(const QString &key, const QVariant &value)
Set a new stored value for an existing argument definition, or spawn a new definition store value in.
QDateTime toDateTime(const QString &key) const
Returns stored QVariant as a QDateTime, falling to default if not provided.
uint toUInt(const QString &key) const
Returns stored QVariant as an unsigned integer, falling to default if not provided.
void PrintHelp(void) const
Print command line option help.
Startup context for MythTV.
QString GetHostName(void)
void RegisterFileForWrite(const QString &file, uint64_t size=0LL)
bool ConnectToMasterServer(bool blockingClient=true, bool openEventSocket=true)
void SendMessage(const QString &message)
int GetNumSetting(const QString &key, int defaultval=0)
void UnregisterFileForWrite(const QString &file)
static void DBError(const QString &where, const MSqlQuery &query)
This class is used as a container for messages.
const QString & Message() const
static const Type kMythEventMessage
void SaveTotalDuration(void)
uint64_t GetTotalFrameCount(void) const
static void load(const QString &module_name)
Load a QTranslator for the user's preferred language.
Holds information on recordings and videos.
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
static bool ExtractKey(const QString &uniquekey, uint &chanid, QDateTime &recstartts)
Extracts chanid and recstartts from a unique key generated by MakeUniqueKey().
virtual void SaveFilesize(uint64_t fsize)
Sets recording file size in database, and sets "filesize" field.
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
QString GetTitle(void) const
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
void SaveCommBreakList(frm_dir_map_t &frames) const
QString MakeUniqueKey(void) const
Creates a unique string that can be used to identify an existing recording.
void SaveMarkupFlag(MarkTypes type) const
Clears the specified flag, then if sets it.
QString GetPathname(void) const
virtual uint64_t GetFilesize(void) const
QString GetPlaybackURL(bool checkMaster=false, bool forceCheckLocal=false)
Returns filename or URL to be used to play back this recording.
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
void SaveCommFlagged(CommFlagStatus flag)
Set "commflagged" field in "recorded" table to "flag".
QString GetSubtitle(void) const
void SetPathname(const QString &pn)
Holds information on a TV Program one might wish to record.
int GetAutoRunJobs(void) const
Returns a bitmap of which jobs are attached to this RecordingInfo.
int GetRecorderNumber(void) const
long long GetFileSize(void) const
GetFileSize: returns the remote file's size at the time it was first opened Will query the server in ...
@ GENERIC_EXIT_PERMISSIONS_ERROR
File permissions error.
@ GENERIC_EXIT_NO_MYTHCONTEXT
No MythContext available.
@ GENERIC_EXIT_OK
Exited with no error.
@ GENERIC_EXIT_NO_RECORDING_DATA
No program/recording data.
@ GENERIC_EXIT_IN_USE
Recording in use, can't flag.
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
@ GENERIC_EXIT_DB_ERROR
Database error.
@ GENERIC_EXIT_NOT_OK
Exited with error.
static constexpr const char * MYTH_APPNAME_MYTHCOMMFLAG
int main(int argc, char *argv[])
static int RebuildSeekTable(ProgramInfo *pginfo, int jobid, bool writefile=false)
ProgramInfo * global_program_info
static void UpdateFileSize(ProgramInfo *program_info)
static QString get_filename(ProgramInfo *program_info)
QMap< QString, SkipType > * skipTypes
static int FlagCommercials(ProgramInfo *program_info, int jobid, const QString &outputfilename, bool useDB, bool fullSpeed)
static bool IsMarked(uint chanid, const QDateTime &starttime)
static void incomingCustomEvent(QEvent *e)
static bool DoesFileExist(ProgramInfo *program_info)
static void commDetectorBreathe()
CommDetectorBase * commDetector
QMap< QString, OutputMethod > * outputTypes
MythCommFlagCommandLineParser cmdline
static void commDetectorGotNewCommercialBreakList(void)
static int QueueCommFlagJob(uint chanid, const QDateTime &starttime, bool rebuild)
static QMap< QString, SkipType > * init_skip_types()
@ kOutputMethodEssentials
static void commDetectorStatusUpdate(const QString &status)
static QMap< QString, OutputMethod > * init_output_types()
static int DoFlagCommercials(ProgramInfo *program_info, bool showPercentage, bool fullSpeed, int jobid, MythCommFlagPlayer *cfp, SkipType commDetectMethod, const QString &outputfilename, bool useDB)
static void streamOutCommercialBreakList(std::ostream &output, const frm_dir_map_t &commercialBreakList)
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 qint64 GetFileSize(ProgramInfo *program_info)
OutputMethod outputMethod
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
bool myth_ioprio(int)
Allows setting the I/O priority of the current process/thread.
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
@ kFilename
Default UTC, "yyyyMMddhhmmss".
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
const QString kFlaggerInUseID
SkipType
This is used as a bitmask.
@ COMM_DETECT_BLANK_SCENE
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
RemoteEncoder * RemoteGetExistingRecorder(const ProgramInfo *pginfo)