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; |
---|