Ticket #11914: programdata.cpp.diff.v10

File programdata.cpp.diff.v10, 14.0 KB (added by klaas.de.waal@…, 6 years ago)
Line 
1diff --git a/mythtv/libs/libmythtv/programdata.cpp b/mythtv/libs/libmythtv/programdata.cpp
2index 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;