2#if defined ANDROID && __ANDROID_API__ < 24
21#include <QCoreApplication>
37#include "libmythbase/mythversion.h"
54#define LOC QString("MythCommFlag: ")
55#define LOC_WARN QString("MythCommFlag, Warning: ")
56#define LOC_ERR QString("MythCommFlag, Error: ")
82 auto *tmp =
new QMap<QString,SkipType>;
113 auto *tmp =
new QMap<QString,OutputMethod>;
136 QString tmp = QString(
137 "Unable to find program info for chanid %1 @ %2")
138 .arg(chanid).arg(startstring);
139 std::cerr << tmp.toLocal8Bit().constData() <<
'\n';
146 QString tmp = QString(
"Job have been queued for chanid %1 @ %2")
147 .arg(chanid).arg(startstring);
148 std::cerr << tmp.toLocal8Bit().constData() <<
'\n';
154 rebuild ?
JOB_REBUILD : 0, JOB_QUEUED, QDateTime());
160 QString tmp = QString(
"Job Queued for chanid %1 @ %2")
161 .arg(chanid).arg(startstring);
162 std::cerr << tmp.toLocal8Bit().constData() <<
'\n';
169 QString tmp = QString(
"Error queueing job for chanid %1 @ %2")
170 .arg(chanid).arg(startstring);
171 std::cerr << tmp.toLocal8Bit().constData() <<
'\n';
180 output <<
"----------------------------\n";
182 if (commercialBreakList.empty())
189 frm_dir_map_t::const_iterator it = commercialBreakList.begin();
190 for (; it != commercialBreakList.end(); ++it)
192 output <<
"framenum: " << it.key() <<
"\tmarktype: " << *it
198 output <<
"----------------------------\n";
204 uint64_t frame_count,
206 const QString &output_filename)
208 if (output_filename.isEmpty())
211 std::ostream *out = &std::cout;
212 if (output_filename !=
"-")
214 QByteArray tmp = output_filename.toLocal8Bit();
215 out =
new std::fstream(tmp.constData(), std::ios::app | std::ios::out );
223 tmp = QString(
"commercialBreakListFor: %1 on %2 @ %3")
230 tmp = QString(
"commercialBreakListFor: %1")
234 const QByteArray tmp2 = tmp.toLocal8Bit();
235 *out << tmp2.constData() <<
'\n';
238 *out <<
"totalframecount: " << frame_count <<
'\n';
246 if (out != &std::cout)
254 qApp->processEvents();
272 QCoreApplication::translate(
"(mythcommflag)",
273 "Paused",
"Job status"));
280 QCoreApplication::translate(
"(mythcommflag)",
281 "Running",
"Job status"));
303 QString message =
"COMMFLAG_UPDATE ";
306 for (
auto it = newCommercialMap.begin();
307 it != newCommercialMap.end(); ++it)
309 if (it != newCommercialMap.begin())
313 message += QString(
"%1:%2").arg(it.key())
317 LOG(VB_COMMFLAG, LOG_INFO,
318 QString(
"mythcommflag sending update: %1").arg(message));
331 QString message = me->
Message();
333 message = message.simplified();
334 QStringList tokens = message.split(
" ", Qt::SkipEmptyParts);
336 LOG(VB_COMMFLAG, LOG_INFO,
337 QString(
"mythcommflag: Received Event: '%1'") .arg(message));
340 (tokens[0] ==
"DONE_RECORDING"))
342 int cardnum = tokens[1].toInt();
343 int filelen = tokens[2].toInt();
345 message = QString(
"mythcommflag: Received a "
346 "DONE_RECORDING event for card %1. ")
353 message +=
"Informed CommDetector that recording has finished.";
354 LOG(VB_COMMFLAG, LOG_INFO, message);
358 if ((tokens.size() >= 2) && (tokens[0] ==
"COMMFLAG_REQUEST"))
361 QDateTime recstartts;
364 message = QString(
"mythcommflag: Received a "
365 "COMMFLAG_REQUEST event for chanid %1 @ %2. ")
366 .arg(chanid).arg(recstartts.toString(
Qt::ISODate));
372 message +=
"Requested CommDetector to generate new break list.";
373 LOG(VB_COMMFLAG, LOG_INFO, message);
381 bool showPercentage,
bool fullSpeed,
int jobid,
383 const QString &outputfilename,
bool useDB)
386 commDetectMethod, showPercentage,
395 LOG(VB_COMMFLAG, LOG_INFO,
396 QString(
"mythcommflag processing JobID %1").arg(jobid));
414 LOG(VB_COMMFLAG, LOG_INFO,
415 "mythcommflag sending COMMFLAG_START notification");
416 QString message =
"COMMFLAG_START ";
430 comms_found = commBreakList.size() / 2;
452 std::this_thread::sleep_for(1s);
492 LOG(VB_GENERAL, LOG_ERR, QString(
"Couldn't find file %1, aborting.")
499 LOG(VB_GENERAL, LOG_ERR, QString(
"File %1 is zero-byte, aborting.")
518 mark_query.
prepare(
"SELECT commflagged, count(rm.type) "
520 "LEFT JOIN recordedmarkup rm ON "
521 "( r.chanid = rm.chanid AND "
522 "r.starttime = rm.starttime AND "
523 "type in (:MARK_START,:MARK_END)) "
524 "WHERE r.chanid = :CHANID AND "
525 "r.starttime = :STARTTIME "
526 "GROUP BY COMMFLAGGED;");
530 mark_query.
bindValue(
":STARTTIME", starttime);
533 mark_query.
size() > 0)
535 if (mark_query.
next())
537 int flagStatus = mark_query.
value(0).toInt();
538 int marksFound = mark_query.
value(1).toInt();
540 QString flagStatusStr =
"UNKNOWN";
541 switch (flagStatus) {
543 flagStatusStr =
"Not Flagged";
546 flagStatusStr = QString(
"Flagged with %1 breaks")
547 .arg(marksFound / 2);
550 flagStatusStr =
"Flagging";
553 flagStatusStr =
"Commercial Free";
557 LOG(VB_COMMFLAG, LOG_INFO,
558 QString(
"Status for chanid %1 @ %2 is '%3'")
559 .arg(QString::number(chanid),
571 const QString &outputfilename,
bool useDB,
bool fullSpeed)
588 commDetectMethod = (
SkipType) commmethod.toInt(&ok);
594 QStringList list = commmethod.split(
",", Qt::SkipEmptyParts);
595 for (
const auto & it : std::as_const(list))
597 QString val = it.toLower();
606 std::cerr <<
"Failed to decode --method option '"
607 << val.toLatin1().constData()
613 commDetectMethod =
skipTypes->value(val);
615 commDetectMethod = (
SkipType) ((
int)commDetectMethod
629 query.
prepare(
"SELECT commmethod FROM channel "
630 "WHERE chanid = :CHANID;");
639 else if (query.
next())
647 LOG(VB_COMMFLAG, LOG_INFO,
648 QString(
"Chanid %1 is marked as being Commercial Free, "
649 "we will use the default commercial detection "
650 "method").arg(program_info->
GetChanID()));
658 LOG(VB_COMMFLAG, LOG_INFO,
659 QString(
"Using method: %1 from channel %2")
660 .arg(commDetectMethod).arg(program_info->
GetChanID()));
695 LOG(VB_GENERAL, LOG_ERR,
696 "Unable to find file in defined storage paths.");
705 LOG(VB_GENERAL, LOG_ERR,
706 QString(
"Unable to create RingBuffer for %1").arg(
filename));
715 LOG(VB_GENERAL, LOG_ERR,
"Unable to open commflag DB connection");
731 LOG(VB_GENERAL, LOG_INFO,
"Enabling experimental flagging speedup (low resolution)");
744 ctx->SetPlayingInfo(program_info);
745 ctx->SetRingBuffer(tmprbuf);
761 LOG(VB_COMMFLAG, LOG_INFO,
762 QString(
"mythcommflag will flag recording "
763 "currently in progress on cardid %1")
771 LOG(VB_GENERAL, LOG_ERR,
772 "Unable to find active recorder for this "
773 "recording, realtime flagging will not be enabled.");
782 program_info,
progress, fullSpeed, jobid,
783 cfp, commDetectMethod, outputfilename, useDB);
786 std::cerr << breaksFound <<
"\n";
788 LOG(VB_GENERAL, LOG_NOTICE, QString(
"Finished, %1 break(s) found.")
798 int jobid,
const QString &outputfilename,
806 LOG(VB_GENERAL, LOG_ERR,
807 QString(
"No program data exists for channel %1 at %2")
808 .arg(chanid).arg(startstring));
816 std::cerr <<
"IN USE\n";
818 "(the program is already being flagged elsewhere)\n";
820 LOG(VB_GENERAL, LOG_ERR,
"Program is already being flagged elsewhere");
827 std::cerr <<
"MythTV Commercial Flagger, flagging commercials for:\n";
829 std::cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() <<
'\n';
831 std::cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() <<
" - "
832 << pginfo.
GetSubtitle().toLocal8Bit().constData() <<
'\n';
835 return FlagCommercials(&pginfo, jobid, outputfilename,
true, fullSpeed);
839 const QString &outputfilename,
bool useDB,
845 std::cerr <<
"MythTV Commercial Flagger, flagging commercials for:\n"
846 <<
" " <<
filename.toLatin1().constData() <<
'\n';
850 return FlagCommercials(&pginfo, jobid, outputfilename, useDB, fullSpeed);
863 filename = QString(
"myth://Videos@%1/%2")
868 LOG(VB_GENERAL, LOG_ERR,
869 QString(
"Unable to find file in defined storage "
870 "paths for JobQueue ID# %1.").arg(jobid));
882 LOG(VB_GENERAL, LOG_ERR,
883 QString(
"Unable to create RingBuffer for %1").arg(
filename));
891 ctx->SetPlayingInfo(pginfo);
892 ctx->SetRingBuffer(tmprbuf);
897 QString time = QDateTime::currentDateTime().toString(Qt::TextDate);
898 std::cerr <<
"Rebuild started at " << qPrintable(time) <<
'\n';
909 QString time = QDateTime::currentDateTime().toString(Qt::TextDate);
910 std::cerr <<
"Rebuild completed at " << qPrintable(time) <<
'\n';
922 std::cerr <<
"MythTV Commercial Flagger, building seek table for:\n"
923 <<
" " <<
filename.toLatin1().constData() <<
'\n';
934 std::cerr <<
"MythTV Commercial Flagger, building seek table for:\n";
936 std::cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() <<
'\n';
938 std::cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() <<
" - "
939 << pginfo.
GetSubtitle().toLocal8Bit().constData() <<
'\n';
944int main(
int argc,
char *argv[])
972 QCoreApplication a(argc, argv);
979 if (!context.Init(
false,
984 LOG(VB_GENERAL, LOG_EMERG,
"Failed to init MythContext, exiting.");
1019 QDateTime starttime;
1023 std::cerr <<
"mythcommflag: ERROR: Unable to find DB info for "
1024 <<
"JobQueue ID# " <<
jobID <<
'\n';
1030 if (jobQueueCPU < 2)
1048 QCoreApplication::translate(
"(mythcommflag)",
1049 "Failed with exit status %1",
1050 "Job status").arg(ret));
1055 QCoreApplication::translate(
"(mythcommflag)",
1056 "%n commercial break(s)",
1072 std::cerr <<
"The --rebuild parameter builds the seektable for "
1073 "internal MythTV use only. It cannot be used in "
1074 "combination with --skipdb.\n";
1112 query.
prepare(
"SELECT r.chanid, r.starttime, c.commmethod "
1113 "FROM recorded AS r "
1114 "LEFT JOIN channel AS c ON r.chanid=c.chanid "
1116 "ORDER BY starttime;");
1122 QDateTime starttime;
1124 while (query.
next())
1154 LOG(VB_GENERAL, LOG_ERR,
1155 "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)
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()
QMap< QString, OutputMethod > * outputTypes
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.
MythCommFlagCommandLineParser cmdline
ProgramInfo * global_program_info
CommDetectorBase * commDetector
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)