Ticket #11914: programdata.cpp.diff.v10

File programdata.cpp.diff.v10, 14.0 KB (added by klaas.de.waal@…, 12 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;