Permalink
Browse files

Improve scheduler handling of seriesids and programid authorities.

Programs in the same series occasionally have different titles.
Previously, the scheduler would not match programs with titles
different from that of the recording rule.  The scheduler now uses
seriesid in addition to title to find matching programs.  The various
screens such as the EPG which offer to list "Other showings" now also
match on seriesid as well as title.

There is now a "This series" filter to aid in scheduling when two
series share the same title.  If this filter is enabled for a
recording rule, the scheduler only matches programs for that series
and does not match programs from other series even if they have the
same title.  This change also corrects the description of a couple of
other filters.

Some users have video sources with programids generated from different
authorities.  Previously, if two programs had non-empty programids,
the scheduler considered them different programs even if the programid
authorities were different.  The scheduler now falls back to
title/subtitle/description checking if two programs have non-empty
programids from different authorities.

The additional, programid authority checking is less efficient than
the previous, simple, programid checking and results in longer
scheduling times.  To remedy this for users who don't need it, the
scheduler checks the database at initialization and only performs the
authority checking if two or more distinct authorities are detected.
  • Loading branch information...
1 parent a76823a commit 02f646ac989f3045bd4395a0e07148b7458371f6 @gigem gigem committed Feb 4, 2012
View
2 mythtv/bindings/perl/MythTV.pm
@@ -114,7 +114,7 @@ package MythTV;
# schema version supported in the main code. We need to check that the schema
# version in the database is as expected by the bindings, which are expected
# to be kept in sync with the main code.
- our $SCHEMA_VERSION = "1293";
+ our $SCHEMA_VERSION = "1294";
# NUMPROGRAMLINES is defined in mythtv/libs/libmythtv/programinfo.h and is
# the number of items in a ProgramInfo QStringList group used by
View
2 mythtv/bindings/python/MythTV/static.py
@@ -5,7 +5,7 @@
"""
OWN_VERSION = (0,25,-1,3)
-SCHEMA_VERSION = 1293
+SCHEMA_VERSION = 1294
NVSCHEMA_VERSION = 1007
MUSICSCHEMA_VERSION = 1018
PROTO_VERSION = '72'
View
56 mythtv/libs/libmyth/programinfo.cpp
@@ -44,6 +44,7 @@ int pginfo_init_statics() { return ProgramInfo::InitStatics(); }
QMutex ProgramInfo::staticDataLock;
ProgramInfoUpdater *ProgramInfo::updater;
int dummy = pginfo_init_statics();
+int ProgramInfo::usingProgIDAuth = -1;
const QString ProgramInfo::kFromRecordedQuery =
@@ -1896,7 +1897,24 @@ bool ProgramInfo::IsSameProgram(const ProgramInfo& other) const
}
if (!programid.isEmpty() && !other.programid.isEmpty())
- return programid == other.programid;
+ {
+ // Read from database if not known yet
+ if (usingProgIDAuth < 0)
+ UsingProgramIDAuthority();
+
+ if (usingProgIDAuth)
+ {
+ int index = programid.indexOf('/');
+ int oindex = other.programid.indexOf('/');
+ if (index == oindex && (index < 0 ||
+ programid.leftRef(index) == other.programid.leftRef(oindex)))
+ return programid == other.programid;
+ }
+ else
+ {
+ return programid == other.programid;
+ }
+ }
if ((dupmethod & kDupCheckSub) &&
((subtitle.isEmpty()) ||
@@ -1960,6 +1978,42 @@ bool ProgramInfo::IsSameProgramTimeslot(const ProgramInfo &other) const
return false;
}
+int ProgramInfo::UsingProgramIDAuthority(void)
+{
+ if (usingProgIDAuth < 0)
+ usingProgIDAuth =
+ gCoreContext->GetNumSetting("UsingProgramIDAuthority", 0);
+ return usingProgIDAuth;
+}
+
+void ProgramInfo::CheckProgramIDAuthorities(void)
+{
+ QMap<QString, int> authMap;
+ char *tables[] = { "program", "recorded", "oldrecorded", NULL };
+ MSqlQuery query(MSqlQuery::InitCon());
+
+ for (char **table = tables; *table; ++table)
+ {
+ query.prepare(QString(
+ "SELECT DISTINCT LEFT(programid, LOCATE('/', programid)) "
+ "FROM %1 WHERE programid <> ''").arg(*table));
+ if (!query.exec())
+ MythDB::DBError("CheckProgramIDAuthorities", query);
+ else
+ {
+ while (query.next())
+ authMap[query.value(0).toString()] = 1;
+ }
+ }
+
+ int numAuths = authMap.count();
+ LOG(VB_GENERAL, LOG_INFO,
+ QString("Found %1 distinct programid authorities").arg(numAuths));
+
+ usingProgIDAuth = (numAuths > 1);
+ gCoreContext->SaveSetting("UsingProgramIDAuthority", usingProgIDAuth);
+}
+
/** \fn ProgramInfo::CreateRecordBasename(const QString &ext) const
* \brief Returns a filename for a recording based on the
* recording channel and date.
View
3 mythtv/libs/libmyth/programinfo.h
@@ -282,6 +282,8 @@ class MPUBLIC ProgramInfo
bool IsSameTimeslot(const ProgramInfo &other) const;
bool IsSameProgramTimeslot(const ProgramInfo &other) const;//sched only
static int GetRecordingTypeRecPriority(RecordingType type);//sched only
+ static int UsingProgramIDAuthority(void);//sched only
+ static void CheckProgramIDAuthorities(void);//sched only
// Used for extending scheduled recordings
bool IsSameProgramWeakCheck(const ProgramInfo &other) const;
@@ -713,6 +715,7 @@ class MPUBLIC ProgramInfo
static QMutex staticDataLock;
static ProgramInfoUpdater *updater;
+ static int usingProgIDAuth;
};
Q_DECLARE_METATYPE(ProgramInfo*)
View
4 mythtv/libs/libmythbase/mythversion.h
@@ -12,7 +12,7 @@
/// Update this whenever the plug-in API changes.
/// Including changes in the libmythbase, libmyth, libmythtv, libmythav* and
/// libmythui class methods used by plug-ins.
-#define MYTH_BINARY_VERSION "0.25.20120201-1"
+#define MYTH_BINARY_VERSION "0.25.20120204-1"
/** \brief Increment this whenever the MythTV network protocol changes.
*
@@ -54,7 +54,7 @@
* MythTV PHP Bindings
* mythtv/bindings/php/MythBackend.php
*/
-#define MYTH_DATABASE_VERSION "1293"
+#define MYTH_DATABASE_VERSION "1294"
MBASE_PUBLIC const char *GetMythSourceVersion();
View
17 mythtv/libs/libmythtv/dbcheck.cpp
@@ -6107,6 +6107,23 @@ NULL
return false;
}
+ if (dbver == "1293")
+ {
+ const char *updates[] = {
+"TRUNCATE TABLE recordmatch",
+"ALTER TABLE recordmatch DROP INDEX recordid",
+"ALTER TABLE recordmatch ADD UNIQUE INDEX (recordid, chanid, starttime)",
+"UPDATE recordfilter SET description='Prime time' WHERE filterid=3",
+"UPDATE recordfilter SET description='This episode' WHERE filterid=6",
+"REPLACE INTO recordfilter (filterid, description, clause, newruledefault) "
+" VALUES (7, 'This series', '(RECTABLE.seriesid <> '''' AND program.seriesid = RECTABLE.seriesid)', 0);",
+NULL
+};
+
+ if (!performActualUpdate(updates, "1294", dbver))
+ return false;
+ }
+
return true;
}
View
53 mythtv/programs/mythbackend/scheduler.cpp
@@ -97,6 +97,7 @@ Scheduler::Scheduler(bool runthread, QMap<int, EncoderLink *> *tvList,
if (doRun)
{
+ ProgramInfo::CheckProgramIDAuthorities();
{
QMutexLocker locker(&schedLock);
start(QThread::LowPriority);
@@ -424,7 +425,17 @@ void Scheduler::FillRecordListFromDB(int recordid)
return;
}
- thequery = "ALTER TABLE recordmatch ADD INDEX (recordid);";
+ thequery = "ALTER TABLE recordmatch "
+ " ADD UNIQUE INDEX (recordid, chanid, starttime); ";
+ query.prepare(thequery);
+ if (!query.exec())
+ {
+ MythDB::DBError("FillRecordListFromDB", query);
+ return;
+ }
+
+ thequery = "ALTER TABLE recordmatch "
+ " ADD INDEX (chanid, starttime, manualid); ";
query.prepare(thequery);
if (!query.exec())
{
@@ -3207,20 +3218,22 @@ void Scheduler::BuildNewRecordsQueries(int recordid, QStringList &from,
QString recidmatch = "";
if (recordid != -1)
recidmatch = "RECTABLE.recordid = :NRRECORDID AND ";
- QString s = recidmatch +
+ QString s1 = recidmatch +
"RECTABLE.search = :NRST AND "
"program.manualid = 0 AND "
"program.title = RECTABLE.title ";
+ s1.replace("RECTABLE", recordTable);
+ QString s2 = recidmatch +
+ "RECTABLE.search = :NRST AND "
+ "program.manualid = 0 AND "
+ "program.seriesid <> '' AND "
+ "program.seriesid = RECTABLE.seriesid ";
+ s2.replace("RECTABLE", recordTable);
- while (1)
- {
- int i = s.indexOf("RECTABLE");
- if (i == -1) break;
- s = s.replace(i, strlen("RECTABLE"), recordTable);
- }
-
from << "";
- where << s;
+ where << s1;
+ from << "";
+ where << s2;
bindings[":NRST"] = kNoSearch;
if (recordid != -1)
bindings[":NRRECORDID"] = recordid;
@@ -3318,7 +3331,7 @@ void Scheduler::UpdateMatches(int recordid) {
for (clause = 0; clause < fromclauses.count(); ++clause)
{
QString query = QString(
-"INSERT INTO recordmatch (recordid, chanid, starttime, manualid) "
+"REPLACE INTO recordmatch (recordid, chanid, starttime, manualid) "
"SELECT RECTABLE.recordid, program.chanid, program.starttime, "
" IF(search = %1, RECTABLE.recordid, 0) ").arg(kManualSearch) + QString(
"FROM (RECTABLE, program INNER JOIN channel "
@@ -3636,8 +3649,13 @@ void Scheduler::AddNewRecords(void)
" (program.programid <> '' "
" AND program.programid = oldrecorded.programid) "
" OR "
-" ( "
-" (program.programid = '' OR oldrecorded.programid = '') "
+" ( ") +
+ (ProgramInfo::UsingProgramIDAuthority() ?
+" (program.programid = '' OR oldrecorded.programid = '' OR "
+" LEFT(program.programid, LOCATE('/', program.programid)) <> "
+" LEFT(oldrecorded.programid, LOCATE('/', oldrecorded.programid))) " :
+" (program.programid = '' OR oldrecorded.programid = '') " )
+ + QString(
" AND "
" (((RECTABLE.dupmethod & 0x02) = 0) OR (program.subtitle <> '' "
" AND program.subtitle = oldrecorded.subtitle)) "
@@ -3669,8 +3687,13 @@ void Scheduler::AddNewRecords(void)
" (program.programid <> '' "
" AND program.programid = recorded.programid) "
" OR "
-" ( "
-" (program.programid = '' OR recorded.programid = '') "
+" ( ") +
+ (ProgramInfo::UsingProgramIDAuthority() ?
+" (program.programid = '' OR recorded.programid = '' OR "
+" LEFT(program.programid, LOCATE('/', program.programid)) <> "
+" LEFT(recorded.programid, LOCATE('/', recorded.programid))) " :
+" (program.programid = '' OR recorded.programid = '') ")
+ + QString(
" AND "
" (((RECTABLE.dupmethod & 0x02) = 0) OR (program.subtitle <> '' "
" AND program.subtitle = recorded.subtitle)) "
View
15 mythtv/programs/mythfrontend/proglist.cpp
@@ -25,12 +25,12 @@ using namespace std;
#define LOC_ERR QString("ProgLister, Error: ")
ProgLister::ProgLister(MythScreenStack *parent, ProgListType pltype,
- const QString &view, const QString &from) :
+ const QString &view, const QString &extraArg) :
ScheduleCommon(parent, "ProgLister"),
m_type(pltype),
m_recid(0),
m_title(),
- m_addTables(from),
+ m_extraArg(extraArg),
m_startTime(QDateTime::currentDateTime()),
m_searchTime(m_startTime),
m_channelOrdering(gCoreContext->GetSetting("ChannelOrdering", "channum")),
@@ -79,7 +79,7 @@ ProgLister::ProgLister(
m_type(plPreviouslyRecorded),
m_recid(recid),
m_title(title),
- m_addTables(),
+ m_extraArg(),
m_startTime(QDateTime::currentDateTime()),
m_searchTime(m_startTime),
m_channelOrdering(gCoreContext->GetSetting("ChannelOrdering", "channum")),
@@ -1119,8 +1119,11 @@ void ProgLister::FillItemList(bool restorePosition, bool updateDisp)
{
where = "WHERE channel.visible = 1 "
" AND program.endtime > :PGILSTART "
- " AND program.title = :PGILPHRASE0 ";
+ " AND (program.title = :PGILPHRASE0 OR "
+ " (program.seriesid <> '' AND "
+ " program.seriesid = :PGILPHRASE1)) ";
bindings[":PGILPHRASE0"] = qphrase;
+ bindings[":PGILPHRASE1"] = m_extraArg;
}
else if (m_type == plNewListings) // what's new list
{
@@ -1214,8 +1217,8 @@ void ProgLister::FillItemList(bool restorePosition, bool updateDisp)
where = QString("WHERE channel.visible = 1 "
" AND program.endtime > :PGILSTART "
" AND ( %1 ) ").arg(qphrase);
- if (!m_addTables.isEmpty())
- where = m_addTables + ' ' + where;
+ if (!m_extraArg.isEmpty())
+ where = m_extraArg + ' ' + where;
}
else if (m_type == plChannel) // list by channel
{
View
4 mythtv/programs/mythfrontend/proglist.h
@@ -39,7 +39,7 @@ class ProgLister : public ScheduleCommon
public:
ProgLister(MythScreenStack *parent, ProgListType pltype,
- const QString &view, const QString &from);
+ const QString &view, const QString &extraArg);
explicit ProgLister(MythScreenStack *parent, uint recid = 0,
const QString &title = QString());
~ProgLister();
@@ -102,7 +102,7 @@ class ProgLister : public ScheduleCommon
ProgListType m_type;
uint m_recid;
QString m_title;
- QString m_addTables;
+ QString m_extraArg;
QDateTime m_startTime;
QDateTime m_searchTime;
QString m_channelOrdering;
View
3 mythtv/programs/mythfrontend/programrecpriority.cpp
@@ -1067,7 +1067,8 @@ void ProgramRecPriority::upcoming(void)
QString trimTitle = pgRecInfo->title;
trimTitle.remove(QRegExp(" \\(.*\\)$"));
MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
- pl = new ProgLister(mainStack, plTitle, trimTitle, "");
+ pl = new ProgLister(mainStack, plTitle, trimTitle,
+ pgRecInfo->GetSeriesID());
if (pl->Create())
mainStack->AddScreen(pl);
else
View
9 mythtv/programs/mythfrontend/schedulecommon.cpp
@@ -47,13 +47,14 @@ void ScheduleCommon::ShowDetails(ProgramInfo *pginfo) const
/**
* \brief Show the upcoming recordings for this title
*/
-void ScheduleCommon::ShowUpcoming(const QString &title) const
+void ScheduleCommon::ShowUpcoming(const QString &title,
+ const QString &seriesid) const
{
if (title.isEmpty())
return;
MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
- ProgLister *pl = new ProgLister(mainStack, plTitle, title, "");
+ ProgLister *pl = new ProgLister(mainStack, plTitle, title, seriesid);
if (pl->Create())
{
mainStack->AddScreen(pl);
@@ -70,7 +71,7 @@ void ScheduleCommon::ShowUpcoming(ProgramInfo *pginfo) const
if (!pginfo)
return;
- ShowUpcoming(pginfo->GetTitle());
+ ShowUpcoming(pginfo->GetTitle(), pginfo->GetSeriesID());
}
/**
@@ -85,7 +86,7 @@ void ScheduleCommon::ShowUpcomingScheduled(ProgramInfo *pginfo) const
uint id;
if ((id = ri.GetRecordingRuleID()) <= 0)
- return ShowUpcoming(pginfo->GetTitle());
+ return ShowUpcoming(pginfo->GetTitle(), pginfo->GetSeriesID());
MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
ProgLister *pl = new ProgLister(mainStack, plRecordid,
View
2 mythtv/programs/mythfrontend/schedulecommon.h
@@ -22,7 +22,7 @@ class ScheduleCommon : public MythScreenType
~ScheduleCommon() {};
void ShowDetails(ProgramInfo *pginfo) const;
- void ShowUpcoming(const QString &title) const;
+ void ShowUpcoming(const QString &title, const QString &seriesid) const;
void ShowUpcoming(ProgramInfo *pginfo) const;
void ShowUpcomingScheduled(ProgramInfo *pginfo) const;
void EditRecording(ProgramInfo *pginfo);
View
7 mythtv/programs/mythfrontend/scheduleeditor.cpp
@@ -46,10 +46,11 @@
static QString fs0(QT_TRANSLATE_NOOP("SchedFilterEditor", "New episode"));
static QString fs1(QT_TRANSLATE_NOOP("SchedFilterEditor", "Identifiable episode"));
static QString fs2(QT_TRANSLATE_NOOP("SchedFilterEditor", "First showing"));
-static QString fs3(QT_TRANSLATE_NOOP("SchedFilterEditor", "Primetime"));
+static QString fs3(QT_TRANSLATE_NOOP("SchedFilterEditor", "Prime time"));
static QString fs4(QT_TRANSLATE_NOOP("SchedFilterEditor", "Commercial free"));
static QString fs5(QT_TRANSLATE_NOOP("SchedFilterEditor", "High definition"));
-static QString fs6(QT_TRANSLATE_NOOP("SchedFilterEditor", "This Episode"));
+static QString fs6(QT_TRANSLATE_NOOP("SchedFilterEditor", "This episode"));
+static QString fs7(QT_TRANSLATE_NOOP("SchedFilterEditor", "This series"));
void *ScheduleEditor::RunScheduleEditor(ProgramInfo *proginfo, void *player)
{
@@ -443,7 +444,7 @@ void ScheduleEditor::showUpcomingByTitle(void)
if (m_recordingRule->m_searchType != kNoSearch)
title.remove(QRegExp(" \\(.*\\)$"));
- ShowUpcoming(title);
+ ShowUpcoming(title, m_recordingRule->m_seriesid);
}
void ScheduleEditor::ShowPreview(void)

0 comments on commit 02f646a

Please sign in to comment.