2#if defined ANDROID && __ANDROID_API__ < 24
20#include <QCoreApplication>
36#include "libmythbase/mythversion.h"
53#define LOC QString("MythCommFlag: ")
54#define LOC_WARN QString("MythCommFlag, Warning: ")
55#define LOC_ERR QString("MythCommFlag, Error: ")
81 auto *
tmp =
new QMap<QString,SkipType>;
112 auto *
tmp =
new QMap<QString,OutputMethod>;
135 QString
tmp = QString(
136 "Unable to find program info for chanid %1 @ %2")
137 .arg(chanid).arg(startstring);
138 std::cerr <<
tmp.toLocal8Bit().constData() << std::endl;
145 QString
tmp = QString(
"Job have been queued for chanid %1 @ %2")
146 .arg(chanid).arg(startstring);
147 std::cerr <<
tmp.toLocal8Bit().constData() << std::endl;
153 rebuild ?
JOB_REBUILD : 0, JOB_QUEUED, QDateTime());
159 QString
tmp = QString(
"Job Queued for chanid %1 @ %2")
160 .arg(chanid).arg(startstring);
161 std::cerr <<
tmp.toLocal8Bit().constData() << std::endl;
168 QString
tmp = QString(
"Error queueing job for chanid %1 @ %2")
169 .arg(chanid).arg(startstring);
170 std::cerr <<
tmp.toLocal8Bit().constData() << std::endl;
179 output <<
"----------------------------" << std::endl;
181 if (commercialBreakList.empty())
184 output <<
"No breaks" << std::endl;
188 frm_dir_map_t::const_iterator it = commercialBreakList.begin();
189 for (; it != commercialBreakList.end(); ++it)
191 output <<
"framenum: " << it.key() <<
"\tmarktype: " << *it
197 output <<
"----------------------------" << std::endl;
203 uint64_t frame_count,
205 const QString &output_filename)
207 if (output_filename.isEmpty())
210 std::ostream *out = &std::cout;
211 if (output_filename !=
"-")
213 QByteArray
tmp = output_filename.toLocal8Bit();
214 out =
new std::fstream(
tmp.constData(), std::ios::app | std::ios::out );
222 tmp = QString(
"commercialBreakListFor: %1 on %2 @ %3")
229 tmp = QString(
"commercialBreakListFor: %1")
233 const QByteArray tmp2 =
tmp.toLocal8Bit();
234 *out << tmp2.constData() << std::endl;
237 *out <<
"totalframecount: " << frame_count << std::endl;
245 if (out != &std::cout)
253 qApp->processEvents();
271 QCoreApplication::translate(
"(mythcommflag)",
272 "Paused",
"Job status"));
279 QCoreApplication::translate(
"(mythcommflag)",
280 "Running",
"Job status"));
302 QString message =
"COMMFLAG_UPDATE ";
305 for (
auto it = newCommercialMap.begin();
306 it != newCommercialMap.end(); ++it)
308 if (it != newCommercialMap.begin())
312 message += QString(
"%1:%2").arg(it.key())
316 LOG(VB_COMMFLAG, LOG_INFO,
317 QString(
"mythcommflag sending update: %1").arg(message));
330 QString message = me->
Message();
332 message = message.simplified();
333 QStringList tokens = message.split(
" ", Qt::SkipEmptyParts);
335 LOG(VB_COMMFLAG, LOG_INFO,
336 QString(
"mythcommflag: Received Event: '%1'") .arg(message));
339 (tokens[0] ==
"DONE_RECORDING"))
341 int cardnum = tokens[1].toInt();
342 int filelen = tokens[2].toInt();
344 message = QString(
"mythcommflag: Received a "
345 "DONE_RECORDING event for card %1. ")
352 message +=
"Informed CommDetector that recording has finished.";
353 LOG(VB_COMMFLAG, LOG_INFO, message);
357 if ((tokens.size() >= 2) && (tokens[0] ==
"COMMFLAG_REQUEST"))
360 QDateTime recstartts;
363 message = QString(
"mythcommflag: Received a "
364 "COMMFLAG_REQUEST event for chanid %1 @ %2. ")
365 .arg(chanid).arg(recstartts.toString(
Qt::ISODate));
371 message +=
"Requested CommDetector to generate new break list.";
372 LOG(VB_COMMFLAG, LOG_INFO, message);
380 bool showPercentage,
bool fullSpeed,
int jobid,
382 const QString &outputfilename,
bool useDB)
385 commDetectMethod, showPercentage,
394 LOG(VB_COMMFLAG, LOG_INFO,
395 QString(
"mythcommflag processing JobID %1").arg(jobid));
413 LOG(VB_COMMFLAG, LOG_INFO,
414 "mythcommflag sending COMMFLAG_START notification");
415 QString message =
"COMMFLAG_START ";
429 comms_found = commBreakList.size() / 2;
491 LOG(VB_GENERAL, LOG_ERR, QString(
"Couldn't find file %1, aborting.")
498 LOG(VB_GENERAL, LOG_ERR, QString(
"File %1 is zero-byte, aborting.")
517 mark_query.
prepare(
"SELECT commflagged, count(rm.type) "
519 "LEFT JOIN recordedmarkup rm ON "
520 "( r.chanid = rm.chanid AND "
521 "r.starttime = rm.starttime AND "
522 "type in (:MARK_START,:MARK_END)) "
523 "WHERE r.chanid = :CHANID AND "
524 "r.starttime = :STARTTIME "
525 "GROUP BY COMMFLAGGED;");
529 mark_query.
bindValue(
":STARTTIME", starttime);
532 mark_query.
size() > 0)
534 if (mark_query.
next())
536 int flagStatus = mark_query.
value(0).toInt();
537 int marksFound = mark_query.
value(1).toInt();
539 QString flagStatusStr =
"UNKNOWN";
540 switch (flagStatus) {
542 flagStatusStr =
"Not Flagged";
545 flagStatusStr = QString(
"Flagged with %1 breaks")
546 .arg(marksFound / 2);
549 flagStatusStr =
"Flagging";
552 flagStatusStr =
"Commercial Free";
556 LOG(VB_COMMFLAG, LOG_INFO,
557 QString(
"Status for chanid %1 @ %2 is '%3'")
558 .arg(QString::number(chanid),
570 const QString &outputfilename,
bool useDB,
bool fullSpeed)
587 commDetectMethod = (
SkipType) commmethod.toInt(&ok);
593 QStringList list = commmethod.split(
",", Qt::SkipEmptyParts);
594 for (
const auto & it : std::as_const(list))
596 QString val = it.toLower();
605 std::cerr <<
"Failed to decode --method option '"
606 << val.toLatin1().constData()
612 commDetectMethod =
skipTypes->value(val);
614 commDetectMethod = (
SkipType) ((
int)commDetectMethod
628 query.
prepare(
"SELECT commmethod FROM channel "
629 "WHERE chanid = :CHANID;");
638 else if (query.
next())
646 LOG(VB_COMMFLAG, LOG_INFO,
647 QString(
"Chanid %1 is marked as being Commercial Free, "
648 "we will use the default commercial detection "
649 "method").arg(program_info->
GetChanID()));
657 LOG(VB_COMMFLAG, LOG_INFO,
658 QString(
"Using method: %1 from channel %2")
659 .arg(commDetectMethod).arg(program_info->
GetChanID()));
694 LOG(VB_GENERAL, LOG_ERR,
695 "Unable to find file in defined storage paths.");
704 LOG(VB_GENERAL, LOG_ERR,
705 QString(
"Unable to create RingBuffer for %1").arg(
filename));
714 LOG(VB_GENERAL, LOG_ERR,
"Unable to open commflag DB connection");
730 LOG(VB_GENERAL, LOG_INFO,
"Enabling experimental flagging speedup (low resolution)");
743 ctx->SetPlayingInfo(program_info);
744 ctx->SetRingBuffer(tmprbuf);
760 LOG(VB_COMMFLAG, LOG_INFO,
761 QString(
"mythcommflag will flag recording "
762 "currently in progress on cardid %1")
770 LOG(VB_GENERAL, LOG_ERR,
771 "Unable to find active recorder for this "
772 "recording, realtime flagging will not be enabled.");
781 program_info,
progress, fullSpeed, jobid,
782 cfp, commDetectMethod, outputfilename, useDB);
785 std::cerr << breaksFound <<
"\n";
787 LOG(VB_GENERAL, LOG_NOTICE, QString(
"Finished, %1 break(s) found.")
797 int jobid,
const QString &outputfilename,
805 LOG(VB_GENERAL, LOG_ERR,
806 QString(
"No program data exists for channel %1 at %2")
807 .arg(chanid).arg(startstring));
815 std::cerr <<
"IN USE\n";
817 "(the program is already being flagged elsewhere)\n";
819 LOG(VB_GENERAL, LOG_ERR,
"Program is already being flagged elsewhere");
826 std::cerr <<
"MythTV Commercial Flagger, flagging commercials for:" << std::endl;
828 std::cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() << std::endl;
830 std::cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() <<
" - "
831 << pginfo.
GetSubtitle().toLocal8Bit().constData() << std::endl;
834 return FlagCommercials(&pginfo, jobid, outputfilename,
true, fullSpeed);
838 const QString &outputfilename,
bool useDB,
844 std::cerr <<
"MythTV Commercial Flagger, flagging commercials for:" << std::endl
845 <<
" " <<
filename.toLatin1().constData() << std::endl;
849 return FlagCommercials(&pginfo, jobid, outputfilename, useDB, fullSpeed);
862 filename = QString(
"myth://Videos@%1/%2")
867 LOG(VB_GENERAL, LOG_ERR,
868 QString(
"Unable to find file in defined storage "
869 "paths for JobQueue ID# %1.").arg(jobid));
881 LOG(VB_GENERAL, LOG_ERR,
882 QString(
"Unable to create RingBuffer for %1").arg(
filename));
890 ctx->SetPlayingInfo(pginfo);
891 ctx->SetRingBuffer(tmprbuf);
896 QString time = QDateTime::currentDateTime().toString(Qt::TextDate);
897 std::cerr <<
"Rebuild started at " << qPrintable(time) << std::endl;
908 QString time = QDateTime::currentDateTime().toString(Qt::TextDate);
909 std::cerr <<
"Rebuild completed at " << qPrintable(time) << std::endl;
921 std::cerr <<
"MythTV Commercial Flagger, building seek table for:" << std::endl
922 <<
" " <<
filename.toLatin1().constData() << std::endl;
933 std::cerr <<
"MythTV Commercial Flagger, building seek table for:" << std::endl;
935 std::cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() << std::endl;
937 std::cerr <<
" " << pginfo.
GetTitle().toLocal8Bit().constData() <<
" - "
938 << pginfo.
GetSubtitle().toLocal8Bit().constData() << std::endl;
943int main(
int argc,
char *argv[])
971 QCoreApplication a(argc, argv);
978 if (!context.Init(
false,
983 LOG(VB_GENERAL, LOG_EMERG,
"Failed to init MythContext, exiting.");
1018 QDateTime starttime;
1022 std::cerr <<
"mythcommflag: ERROR: Unable to find DB info for "
1023 <<
"JobQueue ID# " <<
jobID << std::endl;
1029 if (jobQueueCPU < 2)
1047 QCoreApplication::translate(
"(mythcommflag)",
1048 "Failed with exit status %1",
1049 "Job status").arg(ret));
1054 QCoreApplication::translate(
"(mythcommflag)",
1055 "%n commercial break(s)",
1071 std::cerr <<
"The --rebuild parameter builds the seektable for "
1072 "internal MythTV use only. It cannot be used in "
1073 "combination with --skipdb." << std::endl;
1111 query.
prepare(
"SELECT r.chanid, r.starttime, c.commmethod "
1112 "FROM recorded AS r "
1113 "LEFT JOIN channel AS c ON r.chanid=c.chanid "
1115 "ORDER BY starttime;");
1121 QDateTime starttime;
1123 while (query.
next())
1153 LOG(VB_GENERAL, LOG_ERR,
1154 "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)