| 1 | diff --git a/mythtv/libs/libmythtv/programdata.cpp b/mythtv/libs/libmythtv/programdata.cpp
|
|---|
| 2 | index b182d1e..074c2be 100644
|
|---|
| 3 | --- a/mythtv/libs/libmythtv/programdata.cpp
|
|---|
| 4 | +++ b/mythtv/libs/libmythtv/programdata.cpp
|
|---|
| 5 | @@ -206,39 +206,111 @@ bool DBEvent::HasTimeConflict(const DBEvent &o) const
|
|---|
| 6 | (o.endtime <= endtime && starttime < o.endtime));
|
|---|
| 7 | }
|
|---|
| 8 |
|
|---|
| 9 | +// Processing new EIT entry starts here
|
|---|
| 10 | uint DBEvent::UpdateDB(
|
|---|
| 11 | MSqlQuery &query, uint chanid, int match_threshold) const
|
|---|
| 12 | {
|
|---|
| 13 | + // List the program that we are going to add
|
|---|
| 14 | + LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 15 | + QString("EIT: new program: %1 %2 '%3' chanid %4")
|
|---|
| 16 | + .arg(starttime.toString(Qt::ISODate))
|
|---|
| 17 | + .arg(endtime.toString(Qt::ISODate))
|
|---|
| 18 | + .arg(title.left(35))
|
|---|
| 19 | + .arg(chanid));
|
|---|
| 20 | +
|
|---|
| 21 | + // Do not insert or update when the program is in the past
|
|---|
| 22 | + QDateTime now = QDateTime::currentDateTimeUtc();
|
|---|
| 23 | + if (endtime < now)
|
|---|
| 24 | + {
|
|---|
| 25 | + LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 26 | + QString("EIT: skip '%1' endtime is in the past")
|
|---|
| 27 | + .arg(title.left(35)));
|
|---|
| 28 | + return 0;
|
|---|
| 29 | + }
|
|---|
| 30 | +
|
|---|
| 31 | + // Get all programs already in the database that overlap
|
|---|
| 32 | + // with our new program.
|
|---|
| 33 | vector<DBEvent> programs;
|
|---|
| 34 | uint count = GetOverlappingPrograms(query, chanid, programs);
|
|---|
| 35 | int match = INT_MIN;
|
|---|
| 36 | int i = -1;
|
|---|
| 37 |
|
|---|
| 38 | + // If there are no programs already in the database that overlap
|
|---|
| 39 | + // with our new program then we can simply insert it in the database.
|
|---|
| 40 | if (!count)
|
|---|
| 41 | return InsertDB(query, chanid);
|
|---|
| 42 |
|
|---|
| 43 | - // move overlapping programs out of the way and update existing if possible
|
|---|
| 44 | + // List all overlapping programs with start- and endtime.
|
|---|
| 45 | + for (uint j=0; j<count; j++)
|
|---|
| 46 | + {
|
|---|
| 47 | + LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 48 | + QString("EIT: overlap[%1] : %2 %3 '%4'")
|
|---|
| 49 | + .arg(j)
|
|---|
| 50 | + .arg(programs[j].starttime.toString(Qt::ISODate))
|
|---|
| 51 | + .arg(programs[j].endtime.toString(Qt::ISODate))
|
|---|
| 52 | + .arg(programs[j].title.left(35)));
|
|---|
| 53 | + }
|
|---|
| 54 | +
|
|---|
| 55 | + // Determine which of the overlapping programs is a match with
|
|---|
| 56 | + // our new program; if we have a match then our new program is considered
|
|---|
| 57 | + // to be an update of the matching program.
|
|---|
| 58 | + // The 2nd parameter "i" is the index of the best matching program.
|
|---|
| 59 | match = GetMatch(programs, i);
|
|---|
| 60 |
|
|---|
| 61 | + // Update an existing program or insert a new program.
|
|---|
| 62 | if (match >= match_threshold)
|
|---|
| 63 | {
|
|---|
| 64 | + // We have a good match; update program[i] in the database
|
|---|
| 65 | + // with the new program data and move the overlapping programs
|
|---|
| 66 | + // out of the way.
|
|---|
| 67 | LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 68 | QString("EIT: accept match[%1]: %2 '%3' vs. '%4'")
|
|---|
| 69 | - .arg(i).arg(match).arg(title).arg(programs[i].title));
|
|---|
| 70 | + .arg(i).arg(match).arg(title.left(35))
|
|---|
| 71 | + .arg(programs[i].title.left(35)));
|
|---|
| 72 | return UpdateDB(query, chanid, programs, i);
|
|---|
| 73 | }
|
|---|
| 74 | else
|
|---|
| 75 | {
|
|---|
| 76 | + // If we are here then either we have a match but the match is
|
|---|
| 77 | + // not good enough (the "i >= 0" case) or we did not find
|
|---|
| 78 | + // a match at all.
|
|---|
| 79 | if (i >= 0)
|
|---|
| 80 | {
|
|---|
| 81 | LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 82 | QString("EIT: reject match[%1]: %2 '%3' vs. '%4'")
|
|---|
| 83 | - .arg(i).arg(match).arg(title).arg(programs[i].title));
|
|---|
| 84 | + .arg(i).arg(match).arg(title.left(35))
|
|---|
| 85 | + .arg(programs[i].title.left(35)));
|
|---|
| 86 | }
|
|---|
| 87 | +
|
|---|
| 88 | + // Move the overlapping programs out of the way and
|
|---|
| 89 | + // insert the new program.
|
|---|
| 90 | return UpdateDB(query, chanid, programs, -1);
|
|---|
| 91 | }
|
|---|
| 92 | }
|
|---|
| 93 |
|
|---|
| 94 | +// Get all programs in the database that overlap with our new program.
|
|---|
| 95 | +// We check for three ways in which we can have an overlap:
|
|---|
| 96 | +// (1) Start of old program is inside our new program:
|
|---|
| 97 | +// old program starts at or after our program AND
|
|---|
| 98 | +// old program starts before end of our program;
|
|---|
| 99 | +// e.g. new program s-------------e
|
|---|
| 100 | +// old program s-------------e
|
|---|
| 101 | +// or old program s-----e
|
|---|
| 102 | +// This is the STIME1/ETIME1 comparison.
|
|---|
| 103 | +// (2) End of old program is inside our new program:
|
|---|
| 104 | +// old program ends after our program starts AND
|
|---|
| 105 | +// old program ends before end of our program
|
|---|
| 106 | +// e.g. new program s-------------e
|
|---|
| 107 | +// old program s-------------e
|
|---|
| 108 | +// or old program s-----e
|
|---|
| 109 | +// This is the STIME2/ETIME2 comparison.
|
|---|
| 110 | +// (3) We can have a new program is "inside" the old program:
|
|---|
| 111 | +// old program starts before our program AND
|
|---|
| 112 | +// old program ends after end of our program
|
|---|
| 113 | +// e.g. new program s---------e
|
|---|
| 114 | +// old program s-----------------e
|
|---|
| 115 | +// This is the STIME3/ETIME3 comparison.
|
|---|
| 116 | +//
|
|---|
| 117 | uint DBEvent::GetOverlappingPrograms(
|
|---|
| 118 | MSqlQuery &query, uint chanid, vector<DBEvent> &programs) const
|
|---|
| 119 | {
|
|---|
| 120 | @@ -258,12 +330,15 @@ uint DBEvent::GetOverlappingPrograms(
|
|---|
| 121 | "WHERE chanid = :CHANID AND "
|
|---|
| 122 | " manualid = 0 AND "
|
|---|
| 123 | " ( ( starttime >= :STIME1 AND starttime < :ETIME1 ) OR "
|
|---|
| 124 | - " ( endtime > :STIME2 AND endtime <= :ETIME2 ) )");
|
|---|
| 125 | + " ( endtime > :STIME2 AND endtime <= :ETIME2 ) OR "
|
|---|
| 126 | + " ( starttime < :STIME3 AND endtime > :ETIME3 ) )");
|
|---|
| 127 | query.bindValue(":CHANID", chanid);
|
|---|
| 128 | query.bindValue(":STIME1", starttime);
|
|---|
| 129 | query.bindValue(":ETIME1", endtime);
|
|---|
| 130 | query.bindValue(":STIME2", starttime);
|
|---|
| 131 | query.bindValue(":ETIME2", endtime);
|
|---|
| 132 | + query.bindValue(":STIME3", starttime);
|
|---|
| 133 | + query.bindValue(":ETIME3", endtime);
|
|---|
| 134 |
|
|---|
| 135 | if (!query.exec())
|
|---|
| 136 | {
|
|---|
| 137 | @@ -298,7 +373,6 @@ uint DBEvent::GetOverlappingPrograms(
|
|---|
| 138 | prog.airdate = query.value(15).toUInt();
|
|---|
| 139 | prog.originalairdate = query.value(16).toDate();
|
|---|
| 140 | prog.previouslyshown = query.value(17).toBool();
|
|---|
| 141 | - ;
|
|---|
| 142 |
|
|---|
| 143 | programs.push_back(prog);
|
|---|
| 144 | count++;
|
|---|
| 145 | @@ -408,7 +482,7 @@ int DBEvent::GetMatch(const vector<DBEvent> &programs, int &bestmatch) const
|
|---|
| 146 | {
|
|---|
| 147 | /* crappy providers apparently have events without duration
|
|---|
| 148 | * ensure that the minimal duration is 2 second to avoid
|
|---|
| 149 | - * muliplying and more importantly dividing by zero */
|
|---|
| 150 | + * multiplying and more importantly dividing by zero */
|
|---|
| 151 | int min_dur = max(2, min(duration, duration_loop));
|
|---|
| 152 | overlap = min(overlap, min_dur/2);
|
|---|
| 153 | mv *= overlap * 2;
|
|---|
| 154 | @@ -419,10 +493,10 @@ int DBEvent::GetMatch(const vector<DBEvent> &programs, int &bestmatch) const
|
|---|
| 155 | LOG(VB_GENERAL, LOG_ERR,
|
|---|
| 156 | QString("Unexpected result: shows don't "
|
|---|
| 157 | "overlap\n\t%1: %2 - %3\n\t%4: %5 - %6")
|
|---|
| 158 | - .arg(title.left(30), 30)
|
|---|
| 159 | + .arg(title.left(35))
|
|---|
| 160 | .arg(starttime.toString(Qt::ISODate))
|
|---|
| 161 | .arg(endtime.toString(Qt::ISODate))
|
|---|
| 162 | - .arg(programs[i].title.left(30), 30)
|
|---|
| 163 | + .arg(programs[i].title.left(35), 35)
|
|---|
| 164 | .arg(programs[i].starttime.toString(Qt::ISODate))
|
|---|
| 165 | .arg(programs[i].endtime.toString(Qt::ISODate))
|
|---|
| 166 | );
|
|---|
| 167 | @@ -431,9 +505,9 @@ int DBEvent::GetMatch(const vector<DBEvent> &programs, int &bestmatch) const
|
|---|
| 168 | if (mv > match_val)
|
|---|
| 169 | {
|
|---|
| 170 | LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 171 | - QString("GM : %1 new best match %2 with score %3")
|
|---|
| 172 | - .arg(title.left(25))
|
|---|
| 173 | - .arg(programs[i].title.left(25)).arg(mv));
|
|---|
| 174 | + QString("GM : '%1' new best match '%2' with score %3")
|
|---|
| 175 | + .arg(title.left(35))
|
|---|
| 176 | + .arg(programs[i].title.left(35)).arg(mv));
|
|---|
| 177 | bestmatch = i;
|
|---|
| 178 | match_val = mv;
|
|---|
| 179 | }
|
|---|
| 180 | @@ -445,7 +519,7 @@ int DBEvent::GetMatch(const vector<DBEvent> &programs, int &bestmatch) const
|
|---|
| 181 | uint DBEvent::UpdateDB(
|
|---|
| 182 | MSqlQuery &q, uint chanid, const vector<DBEvent> &p, int match) const
|
|---|
| 183 | {
|
|---|
| 184 | - // adjust/delete overlaps;
|
|---|
| 185 | + // Adjust/delete overlaps;
|
|---|
| 186 | bool ok = true;
|
|---|
| 187 | for (uint i = 0; i < p.size(); i++)
|
|---|
| 188 | {
|
|---|
| 189 | @@ -453,20 +527,52 @@ uint DBEvent::UpdateDB(
|
|---|
| 190 | ok &= MoveOutOfTheWayDB(q, chanid, p[i]);
|
|---|
| 191 | }
|
|---|
| 192 |
|
|---|
| 193 | - // if we failed to move programs out of the way, don't insert new ones..
|
|---|
| 194 | + // If we failed to move programs out of the way, don't insert new ones..
|
|---|
| 195 | if (!ok)
|
|---|
| 196 | + {
|
|---|
| 197 | + LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 198 | + QString("EIT: cannot insert '%1' MoveOutOfTheWayDB failed")
|
|---|
| 199 | + .arg(title.left(35)));
|
|---|
| 200 | return 0;
|
|---|
| 201 | + }
|
|---|
| 202 |
|
|---|
| 203 | - // if no match, insert current item
|
|---|
| 204 | + // No match, insert current item
|
|---|
| 205 | if ((match < 0) || ((uint)match >= p.size()))
|
|---|
| 206 | + {
|
|---|
| 207 | + LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 208 | + QString("EIT: insert '%1'")
|
|---|
| 209 | + .arg(title.left(35)));
|
|---|
| 210 | return InsertDB(q, chanid);
|
|---|
| 211 | + }
|
|---|
| 212 | +
|
|---|
| 213 | + // Changing a starttime of a program that is being recorded can
|
|---|
| 214 | + // start another recording of the same program.
|
|---|
| 215 | + // Therefore we skip updates that change a starttime in the past
|
|---|
| 216 | + // unless the endtime is later.
|
|---|
| 217 | + if (starttime != p[match].starttime)
|
|---|
| 218 | + {
|
|---|
| 219 | + QDateTime now = QDateTime::currentDateTimeUtc();
|
|---|
| 220 | + if (starttime < now && endtime <= p[match].endtime)
|
|---|
| 221 | + {
|
|---|
| 222 | + LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 223 | + QString("EIT: skip '%1' starttime is in the past")
|
|---|
| 224 | + .arg(title.left(35)));
|
|---|
| 225 | + return 0;
|
|---|
| 226 | + }
|
|---|
| 227 | + }
|
|---|
| 228 |
|
|---|
| 229 | - // update matched item with current data
|
|---|
| 230 | + // Update matched item with current data
|
|---|
| 231 | + LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 232 | + QString("EIT: update '%1' with '%2'")
|
|---|
| 233 | + .arg(p[match].title.left(35))
|
|---|
| 234 | + .arg(title.left(35)));
|
|---|
| 235 | return UpdateDB(q, chanid, p[match]);
|
|---|
| 236 | }
|
|---|
| 237 |
|
|---|
| 238 | +// Update matched item with current data.
|
|---|
| 239 | +//
|
|---|
| 240 | uint DBEvent::UpdateDB(
|
|---|
| 241 | - MSqlQuery &query, uint chanid, const DBEvent &match) const
|
|---|
| 242 | + MSqlQuery &query, uint chanid, const DBEvent &match) const
|
|---|
| 243 | {
|
|---|
| 244 | QString ltitle = title;
|
|---|
| 245 | QString lsubtitle = subtitle;
|
|---|
| 246 | @@ -477,7 +583,7 @@ uint DBEvent::UpdateDB(
|
|---|
| 247 | QString lseriesId = seriesId;
|
|---|
| 248 | QDate loriginalairdate = originalairdate;
|
|---|
| 249 |
|
|---|
| 250 | - if (match.title.length() >= ltitle.length())
|
|---|
| 251 | + if (match.title.length() >= ltitle.length())
|
|---|
| 252 | ltitle = match.title;
|
|---|
| 253 |
|
|---|
| 254 | if (match.subtitle.length() >= lsubtitle.length())
|
|---|
| 255 | @@ -634,6 +740,25 @@ static bool delete_program(MSqlQuery &query, uint chanid, const QDateTime &st)
|
|---|
| 256 | return true;
|
|---|
| 257 | }
|
|---|
| 258 |
|
|---|
| 259 | +static bool program_exists(MSqlQuery &query, uint chanid, const QDateTime &st)
|
|---|
| 260 | +{
|
|---|
| 261 | + query.prepare(
|
|---|
| 262 | + "SELECT title FROM program "
|
|---|
| 263 | + "WHERE chanid = :CHANID AND "
|
|---|
| 264 | + " starttime = :OLDSTART");
|
|---|
| 265 | + query.bindValue(":CHANID", chanid);
|
|---|
| 266 | + query.bindValue(":OLDSTART", st);
|
|---|
| 267 | + if (!query.exec())
|
|---|
| 268 | + {
|
|---|
| 269 | + MythDB::DBError("program_exists", query);
|
|---|
| 270 | + }
|
|---|
| 271 | + if (query.next())
|
|---|
| 272 | + {
|
|---|
| 273 | + return true;
|
|---|
| 274 | + }
|
|---|
| 275 | + return false;
|
|---|
| 276 | +}
|
|---|
| 277 | +
|
|---|
| 278 | static bool change_program(MSqlQuery &query, uint chanid, const QDateTime &st,
|
|---|
| 279 | const QDateTime &new_st, const QDateTime &new_end)
|
|---|
| 280 | {
|
|---|
| 281 | @@ -674,25 +799,62 @@ static bool change_program(MSqlQuery &query, uint chanid, const QDateTime &st,
|
|---|
| 282 | return true;
|
|---|
| 283 | }
|
|---|
| 284 |
|
|---|
| 285 | +// Move the program "prog" (3rd parameter) out of the way
|
|---|
| 286 | +// because it overlaps with our new program.
|
|---|
| 287 | bool DBEvent::MoveOutOfTheWayDB(
|
|---|
| 288 | MSqlQuery &query, uint chanid, const DBEvent &prog) const
|
|---|
| 289 | {
|
|---|
| 290 | if (prog.starttime >= starttime && prog.endtime <= endtime)
|
|---|
| 291 | {
|
|---|
| 292 | - // inside current program
|
|---|
| 293 | + // Old program completely inside our new program.
|
|---|
| 294 | + // Delete the old program completely.
|
|---|
| 295 | + LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 296 | + QString("EIT: delete '%1' %2 - %3")
|
|---|
| 297 | + .arg(prog.title.left(35))
|
|---|
| 298 | + .arg(prog.starttime.toString(Qt::ISODate))
|
|---|
| 299 | + .arg(prog.endtime.toString(Qt::ISODate)));
|
|---|
| 300 | return delete_program(query, chanid, prog.starttime);
|
|---|
| 301 | }
|
|---|
| 302 | else if (prog.starttime < starttime && prog.endtime > starttime)
|
|---|
| 303 | {
|
|---|
| 304 | - // starts before, but ends during our program
|
|---|
| 305 | + // Old program starts before, but ends during or after our new program.
|
|---|
| 306 | + // Adjust the end time of the old program to the start time
|
|---|
| 307 | + // of our new program.
|
|---|
| 308 | + // This will leave a hole after our new program when the end time of
|
|---|
| 309 | + // the old program was after the end time of the new program!!
|
|---|
| 310 | + LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 311 | + QString("EIT: change '%1' endtime to %2")
|
|---|
| 312 | + .arg(prog.title.left(35))
|
|---|
| 313 | + .arg(starttime.toString(Qt::ISODate)));
|
|---|
| 314 | return change_program(query, chanid, prog.starttime,
|
|---|
| 315 | - prog.starttime, starttime);
|
|---|
| 316 | + prog.starttime, // Keep the start time
|
|---|
| 317 | + starttime); // New end time is our start time
|
|---|
| 318 | }
|
|---|
| 319 | else if (prog.starttime < endtime && prog.endtime > endtime)
|
|---|
| 320 | {
|
|---|
| 321 | - // starts during, but ends after our program
|
|---|
| 322 | + // Old program starts during, but ends after our new program.
|
|---|
| 323 | + // Adjust the starttime of the old program to the end time
|
|---|
| 324 | + // of our new program.
|
|---|
| 325 | + // If there is already a program starting just when our
|
|---|
| 326 | + // new program ends we cannot move the old program
|
|---|
| 327 | + // so then we have to delete the old program.
|
|---|
| 328 | + if (program_exists(query, chanid, endtime))
|
|---|
| 329 | + {
|
|---|
| 330 | + LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 331 | + QString("EIT: delete '%1' %2 - %3")
|
|---|
| 332 | + .arg(prog.title.left(35))
|
|---|
| 333 | + .arg(prog.starttime.toString(Qt::ISODate))
|
|---|
| 334 | + .arg(prog.endtime.toString(Qt::ISODate)));
|
|---|
| 335 | + return delete_program(query, chanid, prog.starttime);
|
|---|
| 336 | + }
|
|---|
| 337 | + LOG(VB_EIT, LOG_DEBUG,
|
|---|
| 338 | + QString("EIT: change '%1' starttime to %2")
|
|---|
| 339 | + .arg(prog.title.left(35))
|
|---|
| 340 | + .arg(endtime.toString(Qt::ISODate)));
|
|---|
| 341 | +
|
|---|
| 342 | return change_program(query, chanid, prog.starttime,
|
|---|
| 343 | - endtime, prog.endtime);
|
|---|
| 344 | + endtime, // New start time is our endtime
|
|---|
| 345 | + prog.endtime); // Keep the end time
|
|---|
| 346 | }
|
|---|
| 347 | // must be non-conflicting...
|
|---|
| 348 | return true;
|
|---|