MythTV  0.27pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
eitfixup.cpp
Go to the documentation of this file.
1 // C++ headers
2 #include <algorithm>
3 
4 // MythTV headers
5 #include "eitfixup.h"
6 #include "programinfo.h" // for CategoryType
7 #include "channelutil.h" // for GetDefaultAuthority()
8 
9 #include "programinfo.h" // for subtitle types and audio and video properties
10 #include "dishdescriptors.h" // for dish_theme_type_to_string
11 
12 /*------------------------------------------------------------------------
13  * Event Fix Up Scripts - Turned on by entry in dtv_privatetype table
14  *------------------------------------------------------------------------*/
15 
17  : m_bellYear("[\\(]{1}[0-9]{4}[\\)]{1}"),
18  m_bellActors("\\set\\s|,"),
19  m_bellPPVTitleAllDayHD("\\s*\\(All Day\\, HD\\)\\s*$"),
20  m_bellPPVTitleAllDay("\\s*\\(All Day.*\\)\\s*$"),
21  m_bellPPVTitleHD("^HD\\s?-\\s?"),
22  m_bellPPVSubtitleAllDay("^All Day \\(.*\\sEastern\\)\\s*$"),
23  m_bellPPVDescriptionAllDay("^\\(.*\\sEastern\\)"),
24  m_bellPPVDescriptionAllDay2("^\\([0-9].*am-[0-9].*am\\sET\\)"),
25  m_bellPPVDescriptionEventId("\\([0-9]{5}\\)"),
26  m_dishPPVTitleHD("\\sHD\\s*$"),
27  m_dishPPVTitleColon("\\:\\s*$"),
28  m_dishPPVSpacePerenEnd("\\s\\)\\s*$"),
29  m_dishDescriptionNew("\\s*New\\.\\s*"),
30  m_dishDescriptionFinale("\\s*(Series|Season)\\sFinale\\.\\s*"),
31  m_dishDescriptionFinale2("\\s*Finale\\.\\s*"),
32  m_dishDescriptionPremiere("\\s*(Series|Season)\\s(Premier|Premiere)\\.\\s*"),
33  m_dishDescriptionPremiere2("\\s*(Premier|Premiere)\\.\\s*"),
34  m_dishPPVCode("\\s*\\(([A-Z]|[0-9]){5}\\)\\s*$"),
35  m_ukThen("\\s*(Then|Followed by) 60 Seconds\\.", Qt::CaseInsensitive),
36  m_ukNew("(New\\.|\\s*(Brand New|New)\\s*(Series|Episode)\\s*[:\\.\\-])",Qt::CaseInsensitive),
37  m_ukCEPQ("[:\\!\\.\\?]"),
38  m_ukColonPeriod("[:\\.]"),
39  m_ukDotSpaceStart("^\\. "),
40  m_ukDotEnd("\\.$"),
41  m_ukSpaceColonStart("^[ |:]*"),
42  m_ukSpaceStart("^ "),
43  m_ukSeries("\\s*\\(?\\s*(?:Episode|Part|Pt)?\\s*(\\d{1,2})\\s*(?:of|/)\\s*(\\d{1,2})\\s*\\)?\\s*(?:\\.|:)?", Qt::CaseInsensitive),
44  m_ukCC("\\[(?:(AD|SL|S|W),?)+\\]"),
45  m_ukYear("[\\[\\(]([\\d]{4})[\\)\\]]"),
46  m_uk24ep("^\\d{1,2}:00[ap]m to \\d{1,2}:00[ap]m: "),
47  m_ukStarring("(?:Western\\s)?[Ss]tarring ([\\w\\s\\-']+)[Aa]nd\\s([\\w\\s\\-']+)[\\.|,](?:\\s)*(\\d{4})?(?:\\.\\s)?"),
48  m_ukBBC7rpt("\\[Rptd?[^]]+\\d{1,2}\\.\\d{1,2}[ap]m\\]\\."),
49  m_ukDescriptionRemove("^(?:CBBC\\s*\\.|CBeebies\\s*\\.|Class TV\\s*:|BBC Switch\\.)"),
50  m_ukTitleRemove("^(?:[tT]4:|Schools\\s*:)"),
51  m_ukDoubleDotEnd("\\.\\.+$"),
52  m_ukDoubleDotStart("^\\.\\.+"),
53  m_ukTime("\\d{1,2}[\\.:]\\d{1,2}\\s*(am|pm|)"),
54  m_ukBBC34("BBC (?:THREE|FOUR) on BBC (?:ONE|TWO)\\.",Qt::CaseInsensitive),
55  m_ukYearColon("^[\\d]{4}:"),
56  m_ukExclusionFromSubtitle("(starring|stars\\s|drama|series|sitcom)",Qt::CaseInsensitive),
57  m_ukCompleteDots("^\\.\\.+$"),
58  m_ukQuotedSubtitle("(?:^')([\\w\\s\\-,]+)(?:\\.' )"),
59  m_ukAllNew("All New To 4Music!\\s?"),
60  m_comHemCountry("^(\\(.+\\))?\\s?([^ ]+)\\s([^\\.0-9]+)"
61  "(?:\\sfrån\\s([0-9]{4}))(?:\\smed\\s([^\\.]+))?\\.?"),
62  m_comHemDirector("[Rr]egi"),
63  m_comHemActor("[Ss]kådespelare|[Ii] rollerna"),
64  m_comHemHost("[Pp]rogramledare"),
65  m_comHemSub("[.\\?\\!] "),
66  m_comHemRerun1("[Rr]epris\\sfrån\\s([^\\.]+)(?:\\.|$)"),
67  m_comHemRerun2("([0-9]+)/([0-9]+)(?:\\s-\\s([0-9]{4}))?"),
68  m_comHemTT("[Tt]ext-[Tt][Vv]"),
69  m_comHemPersSeparator("(, |\\soch\\s)"),
70  m_comHemPersons("\\s?([Rr]egi|[Ss]kådespelare|[Pp]rogramledare|"
71  "[Ii] rollerna):\\s([^\\.]+)\\."),
72  m_comHemSubEnd("\\s?\\.\\s?$"),
73  m_comHemSeries1("\\s?(?:[dD]el|[eE]pisode)\\s([0-9]+)"
74  "(?:\\s?(?:/|:|av)\\s?([0-9]+))?\\."),
75  m_comHemSeries2("\\s?-?\\s?([Dd]el\\s+([0-9]+))"),
76  m_comHemTSub("\\s+-\\s+([^\\-]+)"),
77  m_mcaIncompleteTitle("(.*).\\.\\.\\.$"),
78  m_mcaCompleteTitlea("^'?("),
79  m_mcaCompleteTitleb("[^\\.\\?]+[^\\'])'?[\\.\\?]\\s+(.+)"),
80  m_mcaSubtitle("^'([^\\.]+)'\\.\\s+(.+)"),
81  m_mcaSeries("^S?(\\d+)\\/E?(\\d+)\\s-\\s(.*)$"),
82  m_mcaCredits("(.*)\\s\\((\\d{4})\\)\\s*([^\\.]+)\\.?\\s*$"),
83  m_mcaAvail("\\s(Only available on [^\\.]*bouquet|Not available in RSA [^\\.]*)\\.?"),
84  m_mcaActors("(.*\\.)\\s+([^\\.]+\\s[A-Z][^\\.]+)\\.\\s*"),
85  m_mcaActorsSeparator("(,\\s+)"),
86  m_mcaYear("(.*)\\s\\((\\d{4})\\)\\s*$"),
87  m_mcaCC(",?\\s(HI|English) Subtitles\\.?"),
88  m_mcaDD(",?\\sDD\\.?"),
89  m_RTLrepeat("(\\(|\\s)?Wiederholung.+vo[m|n].+((?:\\d{2}\\.\\d{2}\\.\\d{4})|(?:\\d{2}[:\\.]\\d{2}\\sUhr))\\)?"),
90  m_RTLSubtitle("^([^\\.]{3,})\\.\\s+(.+)"),
91  /* should be (?:\x{8a}|\\.\\s*|$) but 0x8A gets replaced with 0x20 */
92  m_RTLSubtitle1("^Folge\\s(\\d{1,4})\\s*:\\s+'(.*)'(?:\\s|\\.\\s*|$)"),
93  m_RTLSubtitle2("^Folge\\s(\\d{1,4})\\s+(.{,5}[^\\.]{,120})[\\?!\\.]\\s*"),
94  m_RTLSubtitle3("^(?:Folge\\s)?(\\d{1,4}(?:\\/[IVX]+)?)\\s+(.{,5}[^\\.]{,120})[\\?!\\.]\\s*"),
95  m_RTLSubtitle4("^Thema.{0,5}:\\s([^\\.]+)\\.\\s*"),
96  m_RTLSubtitle5("^'(.+)'\\.\\s*"),
97  m_RTLEpisodeNo1("^(Folge\\s\\d{1,4})\\.*\\s*"),
98  m_RTLEpisodeNo2("^(\\d{1,2}\\/[IVX]+)\\.*\\s*"),
99  m_fiRerun("\\ ?Uusinta[a-zA-Z\\ ]*\\.?"),
100  m_fiRerun2("\\([Uu]\\)"),
101  m_dePremiereInfos("([^.]+)?\\s?([0-9]{4})\\.\\s[0-9]+\\sMin\\.(?:\\sVon"
102  "\\s([^,]+)(?:,|\\su\\.\\sa\\.)\\smit\\s(.+)\\.)?"),
103  m_dePremiereOTitle("\\s*\\(([^\\)]*)\\)$"),
104  m_nlTxt("txt"),
105  m_nlWide("breedbeeld"),
106  m_nlRepeat("herh."),
107  m_nlHD("\\sHD$"),
108  m_nlSub("\\sAfl\\.:\\s([^\\.]+)\\."),
109  m_nlSub2("\\s\"([^\"]+)\""),
110  m_nlActors("\\sMet:\\s.+e\\.a\\."),
111  m_nlPres("\\sPresentatie:\\s([^\\.]+)\\."),
112  m_nlPersSeparator("(, |\\sen\\s)"),
113  m_nlRub("\\s?\\({1}\\W+\\){1}\\s?"),
114  m_nlYear1("(?=\\suit\\s)([1-2]{2}[0-9]{2})"),
115  m_nlYear2("([\\s]{1}[\\(]{1}[A-Z]{0,3}/?)([1-2]{2}[0-9]{2})([\\)]{1})"),
116  m_nlDirector("(?=\\svan\\s)(([A-Z]{1}[a-z]+\\s)|([A-Z]{1}\\.\\s))"),
117  m_nlCat("^(Amusement|Muziek|Informatief|Nieuws/actualiteiten|Jeugd|Animatie|Sport|Serie/soap|Kunst/Cultuur|Documentaire|Film|Natuur|Erotiek|Comedy|Misdaad|Religieus)\\.\\s"),
118  m_nlOmroep ("\\s\\(([A-Z]+/?)+\\)$"),
119  m_noRerun("\\(R\\)"),
120  m_noHD("[\\(\\[]HD[\\)\\]]"),
121  m_noColonSubtitle("^([^:]+): (.+)"),
122  m_noNRKCategories("^(Superstrek[ea]r|Supersomm[ea]r|Superjul|Barne-tv|Fantorangen|Kuraffen|Supermorg[eo]n|Julemorg[eo]n|Sommermorg[eo]n|"
123  "Kuraffen-TV|Sport i dag|NRKs sportsl.rdag|NRKs sportss.ndag|Dagens dokumentar|"
124  "NRK2s historiekveld|Detektimen|Nattkino|Filmklassiker|Film|Kortfilm|P.skemorg[eo]n|"
125  "Radioteatret|Opera|P2-Akademiet|Nyhetsmorg[eo]n i P2 og Alltid Nyheter:): (.+)"),
126  m_noPremiere("\\s+-\\s+(Sesongpremiere|Premiere|premiere)!?$"),
127  m_Stereo("\\b\\(?[sS]tereo\\)?\\b"),
128  m_dkEpisode("\\(([0-9]+)\\)"),
129  m_dkPart("\\(([0-9]+):([0-9]+)\\)"),
130  m_dkSubtitle1("^([^:]+): (.+)"),
131  m_dkSubtitle2("^([^:]+) - (.+)"),
132  m_dkSeason1("Sæson ([0-9]+)\\."),
133  m_dkSeason2("- år ([0-9]+)(?: :)"),
134  m_dkFeatures("Features:(.+)"),
135  m_dkWidescreen(" 16:9"),
136  m_dkDolby(" 5:1"),
137  m_dkSurround(" \\(\\(S\\)\\)"),
138  m_dkStereo(" S"),
139  m_dkReplay(" \\(G\\)"),
140  m_dkTxt(" TTV"),
141  m_dkHD(" HD"),
142  m_dkActors("(?:Medvirkende: |Medv\\.: )(.+)"),
143  m_dkPersonsSeparator("(, )|(og )"),
144  m_dkDirector("(?:Instr.: |Instrukt.r: )(.+)$"),
145  m_dkYear(" fra ([0-9]{4})[ \\.]"),
146  m_AUFreeviewSY("(.*) \\((.+)\\) \\(([12][0-9][0-9][0-9])\\)$"),
147  m_AUFreeviewY("(.*) \\(([12][0-9][0-9][0-9])\\)$"),
148  m_AUFreeviewYC("(.*) \\(([12][0-9][0-9][0-9])\\) \\((.+)\\)$"),
149  m_AUFreeviewSYC("(.*) \\((.+)\\) \\(([12][0-9][0-9][0-9])\\) \\((.+)\\)$")
150 {
151 }
152 
153 void EITFixUp::Fix(DBEventEIT &event) const
154 {
155  if (event.fixup)
156  {
157  if (event.subtitle == event.title)
158  event.subtitle = QString("");
159 
160  if (event.description.isEmpty() && !event.subtitle.isEmpty())
161  {
162  event.description = event.subtitle;
163  event.subtitle = QString("");
164  }
165  }
166 
167  if (kFixHDTV & event.fixup)
168  event.videoProps |= VID_HDTV;
169 
170  if (kFixBell & event.fixup)
171  FixBellExpressVu(event);
172 
173  if (kFixDish & event.fixup)
174  FixBellExpressVu(event);
175 
176  if (kFixUK & event.fixup)
177  FixUK(event);
178 
179  if (kFixPBS & event.fixup)
180  FixPBS(event);
181 
182  if (kFixComHem & event.fixup)
183  FixComHem(event, kFixSubtitle & event.fixup);
184 
185  if (kFixAUStar & event.fixup)
186  FixAUStar(event);
187 
188  if (kFixAUDescription & event.fixup)
189  FixAUDescription(event);
190 
191  if (kFixAUFreeview & event.fixup)
192  FixAUFreeview(event);
193 
194  if (kFixAUNine & event.fixup)
195  FixAUNine(event);
196 
197  if (kFixAUSeven & event.fixup)
198  FixAUSeven(event);
199 
200  if (kFixMCA & event.fixup)
201  FixMCA(event);
202 
203  if (kFixRTL & event.fixup)
204  FixRTL(event);
205 
206  if (kFixFI & event.fixup)
207  FixFI(event);
208 
209  if (kFixPremiere & event.fixup)
210  FixPremiere(event);
211 
212  if (kFixNL & event.fixup)
213  FixNL(event);
214 
215  if (kFixNO & event.fixup)
216  FixNO(event);
217 
218  if (kFixNRK_DVBT & event.fixup)
219  FixNRK_DVBT(event);
220 
221  if (kFixDK & event.fixup)
222  FixDK(event);
223 
224  if (kFixCategory & event.fixup)
225  FixCategory(event);
226 
227  if (event.fixup)
228  {
229  if (!event.title.isEmpty())
230  {
231  event.title = event.title.replace(QChar('\0'), "");
232  event.title = event.title.trimmed();
233  }
234 
235  if (!event.subtitle.isEmpty())
236  {
237  event.subtitle = event.subtitle.replace(QChar('\0'), "");
238  event.subtitle = event.subtitle.trimmed();
239  }
240 
241  if (!event.description.isEmpty())
242  {
243  event.description = event.description.replace(QChar('\0'), "");
244  event.description = event.description.trimmed();
245  }
246  }
247 
248  if (kFixGenericDVB & event.fixup)
249  {
250  event.programId = AddDVBEITAuthority(event.chanid, event.programId);
251  event.seriesId = AddDVBEITAuthority(event.chanid, event.seriesId);
252  }
253 }
254 
270 QString EITFixUp::AddDVBEITAuthority(uint chanid, const QString &id)
271 {
272  if (id.isEmpty())
273  return id;
274 
275  // CRIDs are not case sensitive, so change all to lower case
276  QString crid = id.toLower();
277 
278  // remove "crid://"
279  if (crid.startsWith("crid://"))
280  crid.remove(0,7);
281 
282  // if id is a CRID with authority, return it
283  if (crid.length() >= 1 && crid[0] != '/')
284  return crid;
285 
286  QString authority = ChannelUtil::GetDefaultAuthority(chanid);
287  if (authority.isEmpty())
288  return ""; // no authority, not a valid CRID, return empty
289 
290  return authority + crid;
291 }
292 
299 {
300  QString tmp;
301 
302  // A 0x0D character is present between the content
303  // and the subtitle if its present
304  int position = event.description.indexOf(0x0D);
305 
306  if (position != -1)
307  {
308  // Subtitle present in the title, so get
309  // it and adjust the description
310  event.subtitle = event.description.left(position);
311  event.description = event.description.right(
312  event.description.length() - position - 2);
313  }
314 
315  // Take out the content description which is
316  // always next with a period after it
317  position = event.description.indexOf(".");
318  // Make sure they didn't leave it out and
319  // you come up with an odd category
320  if (position < 10)
321  {
322  }
323  else
324  {
325  event.category = "Unknown";
326  }
327 
328  // If the content descriptor didn't come up with anything, try parsing the category
329  // out of the description.
330  if (event.category.isEmpty())
331  {
332  // Take out the content description which is
333  // always next with a period after it
334  position = event.description.indexOf(".");
335  if ((position + 1) < event.description.length())
336  position = event.description.indexOf(". ");
337  // Make sure they didn't leave it out and
338  // you come up with an odd category
339  if ((position > -1) && position < 20)
340  {
341  const QString stmp = event.description;
342  event.description = stmp.right(stmp.length() - position - 2);
343  event.category = stmp.left(position);
344 
345  int position_p = event.category.indexOf("(");
346  if (position_p == -1)
347  event.description = stmp.right(stmp.length() - position - 2);
348  else
349  event.category = "Unknown";
350  }
351  else
352  {
353  event.category = "Unknown";
354  }
355 
356  // When a channel is off air the category is "-"
357  // so leave the category as blank
358  if (event.category == "-")
359  event.category = "OffAir";
360 
361  if (event.category.length() > 20)
362  event.category = "Unknown";
363  }
364  else if (event.categoryType)
365  {
366  QString theme = dish_theme_type_to_string(event.categoryType);
367  event.description = event.description.replace(theme, "");
368  if (event.description.startsWith("."))
369  event.description = event.description.right(event.description.length() - 1);
370  if (event.description.startsWith(" "))
371  event.description = event.description.right(event.description.length() - 1);
372  }
373 
374  // See if a year is present as (xxxx)
375  position = event.description.indexOf(m_bellYear);
376  if (position != -1 && !event.category.isEmpty())
377  {
378  tmp = "";
379  // Parse out the year
380  bool ok;
381  uint y = event.description.mid(position + 1, 4).toUInt(&ok);
382  if (ok)
383  {
384  event.originalairdate = QDate(y, 1, 1);
385  event.airdate = y;
386  event.previouslyshown = true;
387  }
388 
389  // Get the actors if they exist
390  if (position > 3)
391  {
392  tmp = event.description.left(position-3);
393  QStringList actors =
394  tmp.split(m_bellActors, QString::SkipEmptyParts);
395  QStringList::const_iterator it = actors.begin();
396  for (; it != actors.end(); ++it)
397  event.AddPerson(DBPerson::kActor, *it);
398  }
399  // Remove the year and actors from the description
400  event.description = event.description.right(
401  event.description.length() - position - 7);
402  }
403 
404  // Check for (CC) in the decription and
405  // set the <subtitles type="teletext"> flag
406  position = event.description.indexOf("(CC)");
407  if (position != -1)
408  {
409  event.subtitleType |= SUB_HARDHEAR;
410  event.description = event.description.replace("(CC)", "");
411  }
412 
413  // Check for (Stereo) in the decription and set the <audio> tags
414  position = event.description.indexOf(m_Stereo);
415  if (position != -1)
416  {
417  event.audioProps |= AUD_STEREO;
418  event.description = event.description.replace(m_Stereo, "");
419  }
420 
421  // Check for "title (All Day, HD)" in the title
422  position = event.title.indexOf(m_bellPPVTitleAllDayHD);
423  if (position != -1)
424  {
425  event.title = event.title.replace(m_bellPPVTitleAllDayHD, "");
426  event.videoProps |= VID_HDTV;
427  }
428 
429  // Check for "title (All Day)" in the title
430  position = event.title.indexOf(m_bellPPVTitleAllDay);
431  if (position != -1)
432  {
433  event.title = event.title.replace(m_bellPPVTitleAllDay, "");
434  }
435 
436  // Check for "HD - title" in the title
437  position = event.title.indexOf(m_bellPPVTitleHD);
438  if (position != -1)
439  {
440  event.title = event.title.replace(m_bellPPVTitleHD, "");
441  event.videoProps |= VID_HDTV;
442  }
443 
444  // Check for (HD) in the decription
445  position = event.description.indexOf("(HD)");
446  if (position != -1)
447  {
448  event.description = event.description.replace("(HD)", "");
449  event.videoProps |= VID_HDTV;
450  }
451 
452  // Check for (HD) in the title
453  position = event.title.indexOf("(HD)");
454  if (position != -1)
455  {
456  event.description = event.title.replace("(HD)", "");
457  event.videoProps |= VID_HDTV;
458  }
459 
460  // Check for HD at the end of the title
461  position = event.title.indexOf(m_dishPPVTitleHD);
462  if (position != -1)
463  {
464  event.title = event.title.replace(m_dishPPVTitleHD, "");
465  event.videoProps |= VID_HDTV;
466  }
467 
468  // Check for (DD) at the end of the description
469  position = event.description.indexOf("(DD)");
470  if (position != -1)
471  {
472  event.description = event.description.replace("(DD)", "");
473  event.audioProps |= AUD_DOLBY;
474  event.audioProps |= AUD_STEREO;
475  }
476 
477  // Remove SAP from Dish descriptions
478  position = event.description.indexOf("(SAP)");
479  if (position != -1)
480  {
481  event.description = event.description.replace("(SAP", "");
482  event.subtitleType |= SUB_HARDHEAR;
483  }
484 
485  // Remove any trailing colon in title
486  position = event.title.indexOf(m_dishPPVTitleColon);
487  if (position != -1)
488  {
489  event.title = event.title.replace(m_dishPPVTitleColon, "");
490  }
491 
492  // Remove New at the end of the description
493  position = event.description.indexOf(m_dishDescriptionNew);
494  if (position != -1)
495  {
496  event.previouslyshown = false;
497  event.description = event.description.replace(m_dishDescriptionNew, "");
498  }
499 
500  // Remove Series Finale at the end of the desciption
501  position = event.description.indexOf(m_dishDescriptionFinale);
502  if (position != -1)
503  {
504  event.previouslyshown = false;
505  event.description = event.description.replace(m_dishDescriptionFinale, "");
506  }
507 
508  // Remove Series Finale at the end of the desciption
509  position = event.description.indexOf(m_dishDescriptionFinale2);
510  if (position != -1)
511  {
512  event.previouslyshown = false;
513  event.description = event.description.replace(m_dishDescriptionFinale2, "");
514  }
515 
516  // Remove Series Premiere at the end of the description
517  position = event.description.indexOf(m_dishDescriptionPremiere);
518  if (position != -1)
519  {
520  event.previouslyshown = false;
521  event.description = event.description.replace(m_dishDescriptionPremiere, "");
522  }
523 
524  // Remove Series Premiere at the end of the description
525  position = event.description.indexOf(m_dishDescriptionPremiere2);
526  if (position != -1)
527  {
528  event.previouslyshown = false;
529  event.description = event.description.replace(m_dishDescriptionPremiere2, "");
530  }
531 
532  // Remove Dish's PPV code at the end of the description
533  QRegExp ppvcode = m_dishPPVCode;
534  ppvcode.setCaseSensitivity(Qt::CaseInsensitive);
535  position = event.description.indexOf(ppvcode);
536  if (position != -1)
537  {
538  event.description = event.description.replace(ppvcode, "");
539  }
540 
541  // Remove trailing garbage
542  position = event.description.indexOf(m_dishPPVSpacePerenEnd);
543  if (position != -1)
544  {
545  event.description = event.description.replace(m_dishPPVSpacePerenEnd, "");
546  }
547 
548  // Check for subtitle "All Day (... Eastern)" in the subtitle
549  position = event.subtitle.indexOf(m_bellPPVSubtitleAllDay);
550  if (position != -1)
551  {
552  event.subtitle = event.subtitle.replace(m_bellPPVSubtitleAllDay, "");
553  }
554 
555  // Check for description "(... Eastern)" in the description
556  position = event.description.indexOf(m_bellPPVDescriptionAllDay);
557  if (position != -1)
558  {
559  event.description = event.description.replace(m_bellPPVDescriptionAllDay, "");
560  }
561 
562  // Check for description "(... ET)" in the description
563  position = event.description.indexOf(m_bellPPVDescriptionAllDay2);
564  if (position != -1)
565  {
566  event.description = event.description.replace(m_bellPPVDescriptionAllDay2, "");
567  }
568 
569  // Check for description "(nnnnn)" in the description
570  position = event.description.indexOf(m_bellPPVDescriptionEventId);
571  if (position != -1)
572  {
573  event.description = event.description.replace(m_bellPPVDescriptionEventId, "");
574  }
575 
576 }
577 
582 {
583  QStringList strListColon = event.description.split(":");
584  QStringList strListEnd;
585 
586  bool fColon = false, fQuotedSubtitle = false;
587  int nPosition1;
588  QString strEnd;
589  if (strListColon.count()>1)
590  {
591  bool fDoubleDot = false;
592  bool fSingleDot = true;
593  int nLength = strListColon[0].length();
594 
595  nPosition1 = event.description.indexOf("..");
596  if ((nPosition1 < nLength) && (nPosition1 >= 0))
597  fDoubleDot = true;
598  nPosition1 = event.description.indexOf(".");
599  if (nPosition1==-1)
600  fSingleDot = false;
601  if (nPosition1 > nLength)
602  fSingleDot = false;
603  else
604  {
605  QString strTmp = event.description.mid(nPosition1+1,
606  nLength-nPosition1);
607 
608  QStringList tmp = strTmp.split(" ");
609  if (((uint) tmp.size()) < kMaxDotToColon)
610  fSingleDot = false;
611  }
612 
613  if (fDoubleDot)
614  {
615  strListEnd = strListColon;
616  fColon = true;
617  }
618  else if (!fSingleDot)
619  {
620  QStringList strListTmp;
621  uint nTitle=0;
622  int nTitleMax=-1;
623  int i;
624  for (i =0; (i<(int)strListColon.count()) && (nTitleMax==-1);i++)
625  {
626  const QStringList tmp = strListColon[i].split(" ");
627 
628  nTitle += tmp.size();
629 
630  if (nTitle < kMaxToTitle)
631  strListTmp.push_back(strListColon[i]);
632  else
633  nTitleMax=i;
634  }
635  QString strPartial;
636  for (i=0;i<(nTitleMax-1);i++)
637  strPartial+=strListTmp[i]+":";
638  if (nTitleMax>0)
639  {
640  strPartial+=strListTmp[nTitleMax-1];
641  strListEnd.push_back(strPartial);
642  }
643  for (i=nTitleMax+1;i<(int)strListColon.count();i++)
644  strListEnd.push_back(strListColon[i]);
645  fColon = true;
646  }
647  }
648  QRegExp tmpQuotedSubtitle = m_ukQuotedSubtitle;
649  if (tmpQuotedSubtitle.indexIn(event.description) != -1)
650  {
651  event.subtitle = tmpQuotedSubtitle.cap(1);
652  event.description.remove(m_ukQuotedSubtitle);
653  fQuotedSubtitle = true;
654  }
655  QStringList strListPeriod;
656  QStringList strListQuestion;
657  QStringList strListExcl;
658  if (!(fColon || fQuotedSubtitle))
659  {
660  strListPeriod = event.description.split(".");
661  if (strListPeriod.count() >1)
662  {
663  nPosition1 = event.description.indexOf(".");
664  int nPosition2 = event.description.indexOf("..");
665  if ((nPosition1 < nPosition2) || (nPosition2==-1))
666  strListEnd = strListPeriod;
667  }
668 
669  strListQuestion = event.description.split("?");
670  strListExcl = event.description.split("!");
671  if ((strListQuestion.size() > 1) &&
672  ((uint)strListQuestion.size() <= kMaxQuestionExclamation))
673  {
674  strListEnd = strListQuestion;
675  strEnd = "?";
676  }
677  else if ((strListExcl.size() > 1) &&
678  ((uint)strListExcl.size() <= kMaxQuestionExclamation))
679  {
680  strListEnd = strListExcl;
681  strEnd = "!";
682  }
683  else
684  strEnd = QString::null;
685  }
686 
687  if (!strListEnd.empty())
688  {
689  QStringList strListSpace = strListEnd[0].split(
690  " ", QString::SkipEmptyParts);
691  if (fColon && ((uint)strListSpace.size() > kMaxToTitle))
692  return;
693  if ((uint)strListSpace.size() > kDotToTitle)
694  return;
695  if (strListSpace.filter(m_ukExclusionFromSubtitle).empty())
696  {
697  event.subtitle = strListEnd[0]+strEnd;
698  event.subtitle.remove(m_ukSpaceColonStart);
699  event.description=
700  event.description.mid(strListEnd[0].length()+1);
701  event.description.remove(m_ukSpaceColonStart);
702  }
703  }
704 }
705 
706 
710 void EITFixUp::FixUK(DBEventEIT &event) const
711 {
712  int position1;
713  int position2;
714  QString strFull;
715 
716  bool isMovie = event.category.startsWith("Movie",Qt::CaseInsensitive);
717  // BBC three case (could add another record here ?)
718  event.description = event.description.remove(m_ukThen);
719  event.description = event.description.remove(m_ukNew);
720 
721  // Removal of Class TV, CBBC and CBeebies etc..
722  event.title = event.title.remove(m_ukTitleRemove);
723  event.description = event.description.remove(m_ukDescriptionRemove);
724 
725  // Removal of BBC FOUR and BBC THREE
726  event.description = event.description.remove(m_ukBBC34);
727 
728  // BBC 7 [Rpt of ...] case.
729  event.description = event.description.remove(m_ukBBC7rpt);
730 
731  // "All New To 4Music!
732  event.description = event.description.remove(m_ukAllNew);
733 
734  // Remove [AD,S] etc.
735  QRegExp tmpCC = m_ukCC;
736  if ((position1 = tmpCC.indexIn(event.description)) != -1)
737  {
738  QStringList tmpCCitems = tmpCC.cap(0).remove("[").remove("]").split(",");
739  if (tmpCCitems.contains("AD"))
740  event.audioProps |= AUD_VISUALIMPAIR;
741  if (tmpCCitems.contains("S"))
742  event.subtitleType |= SUB_NORMAL;
743  if (tmpCCitems.contains("SL"))
744  event.subtitleType |= SUB_SIGNED;
745  if (tmpCCitems.contains("W"))
746  event.videoProps |= VID_WIDESCREEN;
747  event.description = event.description.remove(m_ukCC);
748  }
749 
750  event.title = event.title.trimmed();
751  event.description = event.description.trimmed();
752 
753  // Work out the episode numbers (if any)
754  bool series = false;
755  QRegExp tmpExp1 = m_ukSeries;
756  if ((position1 = tmpExp1.indexIn(event.title)) != -1)
757  {
758  if ((tmpExp1.cap(1).toUInt() <= tmpExp1.cap(2).toUInt())
759  && tmpExp1.cap(2).toUInt()<=50)
760  {
761  event.partnumber = tmpExp1.cap(1).toUInt();
762  event.parttotal = tmpExp1.cap(2).toUInt();
763  // Remove from the title
764  event.title = event.title.left(position1) +
765  event.title.mid(position1 + tmpExp1.cap(0).length());
766  series = true;
767  }
768  }
769  else if ((position1 = tmpExp1.indexIn(event.description)) != -1)
770  {
771  if ((tmpExp1.cap(1).toUInt() <= tmpExp1.cap(2).toUInt())
772  && tmpExp1.cap(2).toUInt()<=50)
773  {
774  event.partnumber = tmpExp1.cap(1).toUInt();
775  event.parttotal = tmpExp1.cap(2).toUInt();
776 #if 0 // Remove from the description
777  event.description = event.description.left(position1) +
778  event.description.mid(position1+tmpExp1.cap(0).length());
779 #endif
780  series = true;
781  }
782  }
783  if (series)
784  event.categoryType = ProgramInfo::kCategorySeries;
785 
786  QRegExp tmpStarring = m_ukStarring;
787  if (tmpStarring.indexIn(event.description) != -1)
788  {
789  // if we match this we've captured 2 actors and an (optional) airdate
790  event.AddPerson(DBPerson::kActor, tmpStarring.cap(1));
791  event.AddPerson(DBPerson::kActor, tmpStarring.cap(2));
792  if (tmpStarring.cap(3).length() > 0)
793  {
794  bool ok;
795  uint y = tmpStarring.cap(3).toUInt(&ok);
796  if (ok)
797  {
798  event.airdate = y;
799  event.originalairdate = QDate(y, 1, 1);
800  }
801  }
802  }
803 
804  QRegExp tmp24ep = m_uk24ep;
805  if (!event.title.startsWith("CSI:") && !event.title.startsWith("CD:"))
806  {
807  if (((position1=event.title.indexOf(m_ukDoubleDotEnd)) != -1) &&
808  ((position2=event.description.indexOf(m_ukDoubleDotStart)) != -1))
809  {
810  QString strPart=event.title.remove(m_ukDoubleDotEnd)+" ";
811  strFull = strPart + event.description.remove(m_ukDoubleDotStart);
812  if (isMovie &&
813  ((position1 = strFull.indexOf(m_ukCEPQ,strPart.length())) != -1))
814  {
815  if (strFull[position1] == '!' || strFull[position1] == '?')
816  position1++;
817  event.title = strFull.left(position1);
818  event.description = strFull.mid(position1 + 1);
819  event.description.remove(m_ukSpaceStart);
820  }
821  else if ((position1 = strFull.indexOf(m_ukCEPQ)) != -1)
822  {
823  if (strFull[position1] == '!' || strFull[position1] == '?')
824  position1++;
825  event.title = strFull.left(position1);
826  event.description = strFull.mid(position1 + 1);
827  event.description.remove(m_ukSpaceStart);
828  SetUKSubtitle(event);
829  }
830  if ((position1 = strFull.indexOf(m_ukYear)) != -1)
831  {
832  // Looks like they are using the airdate as a delimiter
833  if ((uint)position1 < SUBTITLE_MAX_LEN)
834  {
835  event.description = event.title.mid(position1);
836  event.title = event.title.left(position1);
837  }
838  }
839  }
840  else if ((position1 = tmp24ep.indexIn(event.description)) != -1)
841  {
842  // Special case for episodes of 24.
843  // -2 from the length cause we don't want ": " on the end
844  event.subtitle = event.description.mid(position1,
845  tmp24ep.cap(0).length() - 2);
846  event.description = event.description.remove(tmp24ep.cap(0));
847  }
848  else if ((position1 = event.description.indexOf(m_ukTime)) == -1)
849  {
850  if (!isMovie && (event.title.indexOf(m_ukYearColon) < 0))
851  {
852  if (((position1 = event.title.indexOf(":")) != -1) &&
853  (event.description.indexOf(":") < 0 ))
854  {
855  if (event.title.mid(position1+1).indexOf(m_ukCompleteDots)==0)
856  {
857  SetUKSubtitle(event);
858  QString strTmp = event.title.mid(position1+1);
859  event.title.resize(position1);
860  event.subtitle = strTmp+event.subtitle;
861  }
862  else if ((uint)position1 < SUBTITLE_MAX_LEN)
863  {
864  event.subtitle = event.title.mid(position1 + 1);
865  event.title = event.title.left(position1);
866  }
867  }
868  else
869  SetUKSubtitle(event);
870  }
871  }
872  }
873 
874  if (!isMovie && event.subtitle.isEmpty())
875  {
876  if ((position1=event.description.indexOf(m_ukTime)) != -1)
877  {
878  position2 = event.description.indexOf(m_ukColonPeriod);
879  if ((position2>=0) && (position2 < (position1-2)))
880  SetUKSubtitle(event);
881  }
882  else if ((position1=event.title.indexOf("-")) != -1)
883  {
884  if ((uint)position1 < SUBTITLE_MAX_LEN)
885  {
886  event.subtitle = event.title.mid(position1 + 1);
887  event.subtitle.remove(m_ukSpaceColonStart);
888  event.title = event.title.left(position1);
889  }
890  }
891  else
892  SetUKSubtitle(event);
893  }
894 
895  // Work out the year (if any)
896  QRegExp tmpUKYear = m_ukYear;
897  if ((position1 = tmpUKYear.indexIn(event.description)) != -1)
898  {
899  QString stmp = event.description;
900  int itmp = position1 + tmpUKYear.cap(0).length();
901  event.description = stmp.left(position1) + stmp.mid(itmp);
902  bool ok;
903  uint y = tmpUKYear.cap(1).toUInt(&ok);
904  if (ok)
905  {
906  event.airdate = y;
907  event.originalairdate = QDate(y, 1, 1);
908  }
909  }
910 
911  // Trim leading/trailing '.'
912  event.subtitle.remove(m_ukDotSpaceStart);
913  if (event.subtitle.lastIndexOf("..") != (((int)event.subtitle.length())-2))
914  event.subtitle.remove(m_ukDotEnd);
915 
916  // Reverse the subtitle and empty description
917  if (event.description.isEmpty() && !event.subtitle.isEmpty())
918  {
919  event.description=event.subtitle;
920  event.subtitle=QString::null;
921  }
922 }
923 
927 void EITFixUp::FixPBS(DBEventEIT &event) const
928 {
929  /* Used for PBS ATSC Subtitles are separated by a colon */
930  int position = event.description.indexOf(':');
931  if (position != -1)
932  {
933  const QString stmp = event.description;
934  event.subtitle = stmp.left(position);
935  event.description = stmp.right(stmp.length() - position - 2);
936  }
937 }
938 
942 void EITFixUp::FixComHem(DBEventEIT &event, bool process_subtitle) const
943 {
944  // Reverse what EITFixUp::Fix() did
945  if (event.subtitle.isEmpty() && !event.description.isEmpty())
946  {
947  event.subtitle = event.description;
948  event.description = "";
949  }
950 
951  // Remove subtitle, it contains the category and we already know that
952  event.subtitle = "";
953 
954  bool isSeries = false;
955  // Try to find episode numbers
956  int pos;
957  QRegExp tmpSeries1 = m_comHemSeries1;
958  QRegExp tmpSeries2 = m_comHemSeries2;
959  if ((pos = tmpSeries2.indexIn(event.title)) != -1)
960  {
961  QStringList list = tmpSeries2.capturedTexts();
962  event.partnumber = list[2].toUInt();
963  event.title = event.title.replace(list[0],"");
964  }
965  else if ((pos = tmpSeries1.indexIn(event.description)) != -1)
966  {
967  QStringList list = tmpSeries1.capturedTexts();
968  if (!list[1].isEmpty())
969  {
970  event.partnumber = list[1].toUInt();
971  }
972  if (!list[2].isEmpty())
973  {
974  event.parttotal = list[2].toUInt();
975  }
976 
977  // Remove the episode numbers, but only if it's not at the begining
978  // of the description (subtitle code might use it)
979  if(pos > 0)
980  event.description = event.description.replace(list[0],"");
981  isSeries = true;
982  }
983 
984  // Add partnumber/parttotal to subtitle
985  // This will be overwritten if we find a better subtitle
986  if (event.partnumber > 0)
987  {
988  event.subtitle = QString("Del %1").arg(event.partnumber);
989  if (event.parttotal > 0)
990  {
991  event.subtitle += QString(" av %1").arg(event.parttotal);
992  }
993  }
994 
995  // Move subtitle info from title to subtitle
996  QRegExp tmpTSub = m_comHemTSub;
997  if (tmpTSub.indexIn(event.title) != -1)
998  {
999  event.subtitle = tmpTSub.cap(1);
1000  event.title = event.title.replace(tmpTSub.cap(0),"");
1001  }
1002 
1003  // No need to continue without a description.
1004  if (event.description.length() <= 0)
1005  return;
1006 
1007  // Try to find country category, year and possibly other information
1008  // from the begining of the description
1009  QRegExp tmpCountry = m_comHemCountry;
1010  pos = tmpCountry.indexIn(event.description);
1011  if (pos != -1)
1012  {
1013  QStringList list = tmpCountry.capturedTexts();
1014  QString replacement;
1015 
1016  // Original title, usually english title
1017  // note: list[1] contains extra () around the text that needs removing
1018  if (list[1].length() > 0)
1019  {
1020  replacement = list[1] + " ";
1021  //store it somewhere?
1022  }
1023 
1024  // Countr(y|ies)
1025  if (list[2].length() > 0)
1026  {
1027  replacement += list[2] + " ";
1028  //store it somewhere?
1029  }
1030 
1031  // Category
1032  if (list[3].length() > 0)
1033  {
1034  replacement += list[3] + ".";
1035  if(event.category.isEmpty())
1036  {
1037  event.category = list[3];
1038  }
1039 
1040  if(list[3].indexOf("serie")!=-1)
1041  {
1042  isSeries = true;
1043  }
1044  }
1045 
1046  // Year
1047  if (list[4].length() > 0)
1048  {
1049  bool ok;
1050  uint y = list[4].trimmed().toUInt(&ok);
1051  if (ok)
1052  event.airdate = y;
1053  }
1054 
1055  // Actors
1056  if (list[5].length() > 0)
1057  {
1058  const QStringList actors =
1059  list[5].split(m_comHemPersSeparator, QString::SkipEmptyParts);
1060  QStringList::const_iterator it = actors.begin();
1061  for (; it != actors.end(); ++it)
1062  event.AddPerson(DBPerson::kActor, *it);
1063  }
1064 
1065  // Remove year and actors.
1066  // The reason category is left in the description is because otherwise
1067  // the country would look wierd like "Amerikansk. Rest of description."
1068  event.description = event.description.replace(list[0],replacement);
1069  }
1070 
1071  if (isSeries)
1072  event.categoryType = ProgramInfo::kCategorySeries;
1073 
1074  // Look for additional persons in the description
1075  QRegExp tmpPersons = m_comHemPersons;
1076  while(pos = tmpPersons.indexIn(event.description),pos!=-1)
1077  {
1078  DBPerson::Role role;
1079  QStringList list = tmpPersons.capturedTexts();
1080 
1081  QRegExp tmpDirector = m_comHemDirector;
1082  QRegExp tmpActor = m_comHemActor;
1083  QRegExp tmpHost = m_comHemHost;
1084  if (tmpDirector.indexIn(list[1])!=-1)
1085  {
1086  role = DBPerson::kDirector;
1087  }
1088  else if(tmpActor.indexIn(list[1])!=-1)
1089  {
1090  role = DBPerson::kActor;
1091  }
1092  else if(tmpHost.indexIn(list[1])!=-1)
1093  {
1094  role = DBPerson::kHost;
1095  }
1096  else
1097  {
1098  event.description=event.description.replace(list[0],"");
1099  continue;
1100  }
1101 
1102  const QStringList actors =
1103  list[2].split(m_comHemPersSeparator, QString::SkipEmptyParts);
1104  QStringList::const_iterator it = actors.begin();
1105  for (; it != actors.end(); ++it)
1106  event.AddPerson(role, *it);
1107 
1108  // Remove it
1109  event.description=event.description.replace(list[0],"");
1110  }
1111 
1112  // Is this event on a channel we shoud look for a subtitle?
1113  // The subtitle is the first sentence in the description, but the
1114  // subtitle can't be the only thing in the description and it must be
1115  // shorter than 55 characters or we risk picking up the wrong thing.
1116  if (process_subtitle)
1117  {
1118  int pos = event.description.indexOf(m_comHemSub);
1119  bool pvalid = pos != -1 && pos <= 55;
1120  if (pvalid && (event.description.length() - (pos + 2)) > 0)
1121  {
1122  event.subtitle = event.description.left(
1123  pos + (event.description[pos] == '?' ? 1 : 0));
1124  event.description = event.description.mid(pos + 2);
1125  }
1126  }
1127 
1128  // Teletext subtitles?
1129  int position = event.description.indexOf(m_comHemTT);
1130  if (position != -1)
1131  {
1132  event.subtitleType |= SUB_NORMAL;
1133  }
1134 
1135  // Try to findout if this is a rerun and if so the date.
1136  QRegExp tmpRerun1 = m_comHemRerun1;
1137  if (tmpRerun1.indexIn(event.description) == -1)
1138  return;
1139 
1140  // Rerun from today
1141  QStringList list = tmpRerun1.capturedTexts();
1142  if (list[1] == "i dag")
1143  {
1144  event.originalairdate = event.starttime.date();
1145  return;
1146  }
1147 
1148  // Rerun from yesterday afternoon
1149  if (list[1] == "eftermiddagen")
1150  {
1151  event.originalairdate = event.starttime.date().addDays(-1);
1152  return;
1153  }
1154 
1155  // Rerun with day, month and possibly year specified
1156  QRegExp tmpRerun2 = m_comHemRerun2;
1157  if (tmpRerun2.indexIn(list[1]) != -1)
1158  {
1159  QStringList datelist = tmpRerun2.capturedTexts();
1160  int day = datelist[1].toInt();
1161  int month = datelist[2].toInt();
1162  //int year;
1163 
1164  //if (datelist[3].length() > 0)
1165  // year = datelist[3].toInt();
1166  //else
1167  // year = event.starttime.date().year();
1168 
1169  if (day > 0 && month > 0)
1170  {
1171  QDate date(event.starttime.date().year(), month, day);
1172  // it's a rerun so it must be in the past
1173  if (date > event.starttime.date())
1174  date = date.addYears(-1);
1175  event.originalairdate = date;
1176  }
1177  return;
1178  }
1179 }
1180 
1185 {
1186  event.category = event.subtitle;
1187  /* Used for DVB-S Subtitles are separated by a colon */
1188  int position = event.description.indexOf(':');
1189  if (position != -1)
1190  {
1191  const QString stmp = event.description;
1192  event.subtitle = stmp.left(position);
1193  event.description = stmp.right(stmp.length() - position - 2);
1194  }
1195 }
1196 
1201 {
1202  if (event.description.startsWith("[Program data ") || event.description.startsWith("[Program info "))//TEN
1203  {
1204  event.description = "";//event.subtitle;
1205  }
1206  if (event.description.endsWith("Copyright West TV Ltd. 2011)"))
1207  event.description.resize(event.description.length()-40);
1208 
1209  if (event.description.isEmpty() && !event.subtitle.isEmpty())//due to ten's copyright info, this won't be caught before
1210  {
1211  event.description = event.subtitle;
1212  event.subtitle = QString::null;
1213  }
1214  if (event.description.startsWith(event.title+" - "))
1215  event.description.remove(0,event.title.length()+3);
1216  if (event.title.startsWith("LIVE: ", Qt::CaseInsensitive))
1217  {
1218  event.title.remove(0, 6);
1219  event.description.prepend("(Live) ");
1220  }
1221 }
1226 {
1227  QRegExp rating("\\((G|PG|M|MA)\\)");
1228  if (rating.indexIn(event.description) == 0)
1229  {
1230  EventRating prograting;
1231  prograting.system="AU"; prograting.rating = rating.cap(1);
1232  event.ratings.push_back(prograting);
1233  event.description.remove(0,rating.matchedLength()+1);
1234  }
1235  if (event.description.startsWith("[HD]"))
1236  {
1237  event.videoProps |= VID_HDTV;
1238  event.description.remove(0,5);
1239  }
1240  if (event.description.startsWith("[CC]"))
1241  {
1242  event.subtitleType |= SUB_NORMAL;
1243  event.description.remove(0,5);
1244  }
1245  if (event.subtitle == "Movie")
1246  {
1247  event.subtitle = QString::null;
1248  event.categoryType = ProgramInfo::kCategoryMovie;
1249  }
1250  if (event.description.startsWith(event.title))
1251  event.description.remove(0,event.title.length()+1);
1252 }
1257 {
1258  if (event.description.endsWith(" Rpt"))
1259  {
1260  event.previouslyshown = true;
1261  event.description.resize(event.description.size()-4);
1262  }
1263  QRegExp year("(\\d{4})$");
1264  if (year.indexIn(event.description) != -1)
1265  {
1266  event.airdate = year.cap(3).toUInt();
1267  event.description.resize(event.description.size()-5);
1268  }
1269  if (event.description.endsWith(" CC"))
1270  {
1271  event.subtitleType |= SUB_NORMAL;
1272  event.description.resize(event.description.size()-3);
1273  }
1274  QString advisories;//store the advisories to append later
1275  QRegExp adv("(\\([A-Z,]+\\))$");
1276  if (adv.indexIn(event.description) != -1)
1277  {
1278  advisories = adv.cap(1);
1279  event.description.resize(event.description.size()-(adv.matchedLength()+1));
1280  }
1281  QRegExp rating("(C|G|PG|M|MA)$");
1282  if (rating.indexIn(event.description) != -1)
1283  {
1284  EventRating prograting;
1285  prograting.system=""; prograting.rating = rating.cap(1);
1286  if (!advisories.isEmpty())
1287  prograting.rating.append(" ").append(advisories);
1288  event.ratings.push_back(prograting);
1289  event.description.resize(event.description.size()-(rating.matchedLength()+1));
1290  }
1291 }
1296 {
1297  if (event.description.endsWith(".."))//has been truncated to fit within the 'subtitle' eit field, so none of the following will work (ABC)
1298  return;
1299 
1300  if (m_AUFreeviewSY.indexIn(event.description.trimmed(), 0) != -1)
1301  {
1302  if (event.subtitle.isEmpty())//nine sometimes has an actual subtitle field and the brackets thingo)
1303  event.subtitle = m_AUFreeviewSY.cap(2);
1304  event.airdate = m_AUFreeviewSY.cap(3).toUInt();
1305  event.description = m_AUFreeviewSY.cap(1);
1306  }
1307  else if (m_AUFreeviewY.indexIn(event.description.trimmed(), 0) != -1)
1308  {
1309  event.airdate = m_AUFreeviewY.cap(2).toUInt();
1310  event.description = m_AUFreeviewY.cap(1);
1311  }
1312  else if (m_AUFreeviewSYC.indexIn(event.description.trimmed(), 0) != -1)
1313  {
1314  if (event.subtitle.isEmpty())
1315  event.subtitle = m_AUFreeviewSYC.cap(2);
1316  event.airdate = m_AUFreeviewSYC.cap(3).toUInt();
1317  QStringList actors = m_AUFreeviewSYC.cap(4).split("/");
1318  for (int i = 0; i < actors.size(); ++i)
1319  event.AddPerson(DBPerson::kActor, actors.at(i));
1320  event.description = m_AUFreeviewSYC.cap(1);
1321  }
1322  else if (m_AUFreeviewYC.indexIn(event.description.trimmed(), 0) != -1)
1323  {
1324  event.airdate = m_AUFreeviewYC.cap(2).toUInt();
1325  QStringList actors = m_AUFreeviewYC.cap(3).split("/");
1326  for (int i = 0; i < actors.size(); ++i)
1327  event.AddPerson(DBPerson::kActor, actors.at(i));
1328  event.description = m_AUFreeviewYC.cap(1);
1329  }
1330 }
1331 
1335 void EITFixUp::FixMCA(DBEventEIT &event) const
1336 {
1337  const uint SUBTITLE_PCT = 60; // % of description to allow subtitle to
1338  const uint SUBTITLE_MAX_LEN = 128;// max length of subtitle field in db.
1339  int position;
1340  QRegExp tmpExp1;
1341 
1342  // Remove subtitle, it contains category information too specific to use
1343  event.subtitle = QString("");
1344 
1345  // No need to continue without a description.
1346  if (event.description.length() <= 0)
1347  return;
1348 
1349  // Replace incomplete title if the full one is in the description
1350  tmpExp1 = m_mcaIncompleteTitle;
1351  if (tmpExp1.indexIn(event.title) != -1)
1352  {
1353  tmpExp1 = QRegExp( QString(m_mcaCompleteTitlea.pattern() + tmpExp1.cap(1) +
1354  m_mcaCompleteTitleb.pattern()));
1355  tmpExp1.setCaseSensitivity(Qt::CaseInsensitive);
1356  if (tmpExp1.indexIn(event.description) != -1)
1357  {
1358  event.title = tmpExp1.cap(1).trimmed();
1359  event.description = tmpExp1.cap(2).trimmed();
1360  }
1361  tmpExp1.setCaseSensitivity(Qt::CaseSensitive);
1362  }
1363 
1364  // Try to find subtitle in description
1365  tmpExp1 = m_mcaSubtitle;
1366  if ((position = tmpExp1.indexIn(event.description)) != -1)
1367  {
1368  uint tmpExp1Len = tmpExp1.cap(1).length();
1369  uint evDescLen = max(event.description.length(), 1);
1370 
1371  if ((tmpExp1Len < SUBTITLE_MAX_LEN) &&
1372  ((tmpExp1Len * 100 / evDescLen) < SUBTITLE_PCT))
1373  {
1374  event.subtitle = tmpExp1.cap(1);
1375  event.description = tmpExp1.cap(2);
1376  }
1377  }
1378 
1379  // Try to find episode numbers in subtitle
1380  tmpExp1 = m_mcaSeries;
1381  if ((position = tmpExp1.indexIn(event.subtitle)) != -1)
1382  {
1383  uint season = tmpExp1.cap(1).toUInt();
1384  uint episode = tmpExp1.cap(2).toUInt();
1385  event.subtitle = tmpExp1.cap(3).trimmed();
1386  event.syndicatedepisodenumber =
1387  QString("E%1S%2").arg(episode).arg(season);
1388  event.categoryType = ProgramInfo::kCategorySeries;
1389  }
1390 
1391  // Close captioned?
1392  position = event.description.indexOf(m_mcaCC);
1393  if (position > 0)
1394  {
1395  event.subtitleType |= SUB_HARDHEAR;
1396  event.description.replace(m_mcaCC, "");
1397  }
1398 
1399  // Dolby Digital 5.1?
1400  position = event.description.indexOf(m_mcaDD);
1401  if ((position > 0) && (position > (int) (event.description.length() - 7)))
1402  {
1403  event.audioProps |= AUD_DOLBY;
1404  event.description.replace(m_mcaDD, "");
1405  }
1406 
1407  // Remove bouquet tags
1408  event.description.replace(m_mcaAvail, "");
1409 
1410  // Try to find year and director from the end of the description
1411  bool isMovie = false;
1412  tmpExp1 = m_mcaCredits;
1413  position = tmpExp1.indexIn(event.description);
1414  if (position != -1)
1415  {
1416  isMovie = true;
1417  event.description = tmpExp1.cap(1).trimmed();
1418  bool ok;
1419  uint y = tmpExp1.cap(2).trimmed().toUInt(&ok);
1420  if (ok)
1421  event.airdate = y;
1422  event.AddPerson(DBPerson::kDirector, tmpExp1.cap(3).trimmed());
1423  }
1424  else
1425  {
1426  // Try to find year only from the end of the description
1427  tmpExp1 = m_mcaYear;
1428  position = tmpExp1.indexIn(event.description);
1429  if (position != -1)
1430  {
1431  isMovie = true;
1432  event.description = tmpExp1.cap(1).trimmed();
1433  bool ok;
1434  uint y = tmpExp1.cap(2).trimmed().toUInt(&ok);
1435  if (ok)
1436  event.airdate = y;
1437  }
1438  }
1439 
1440  if (isMovie)
1441  {
1442  tmpExp1 = m_mcaActors;
1443  position = tmpExp1.indexIn(event.description);
1444  if (position != -1)
1445  {
1446  const QStringList actors = tmpExp1.cap(2).split(
1447  m_mcaActorsSeparator, QString::SkipEmptyParts);
1448  QStringList::const_iterator it = actors.begin();
1449  for (; it != actors.end(); ++it)
1450  event.AddPerson(DBPerson::kActor, (*it).trimmed());
1451  event.description = tmpExp1.cap(1).trimmed();
1452  }
1453  event.categoryType = ProgramInfo::kCategoryMovie;
1454  }
1455 
1456 }
1457 
1461 void EITFixUp::FixRTL(DBEventEIT &event) const
1462 {
1463  int pos;
1464 
1465  // No need to continue without a description or with an subtitle.
1466  if (event.description.length() <= 0 || event.subtitle.length() > 0)
1467  return;
1468 
1469  // Repeat
1470  QRegExp tmpExpRepeat = m_RTLrepeat;
1471  if ((pos = tmpExpRepeat.indexIn(event.description)) != -1)
1472  {
1473  // remove '.' if it matches at the beginning of the description
1474  int length = tmpExpRepeat.cap(0).length() + (pos ? 0 : 1);
1475  event.description = event.description.remove(pos, length).trimmed();
1476  }
1477 
1478  QRegExp tmpExp1 = m_RTLSubtitle;
1479  QRegExp tmpExpSubtitle1 = m_RTLSubtitle1;
1480  tmpExpSubtitle1.setMinimal(true);
1481  QRegExp tmpExpSubtitle2 = m_RTLSubtitle2;
1482  QRegExp tmpExpSubtitle3 = m_RTLSubtitle3;
1483  QRegExp tmpExpSubtitle4 = m_RTLSubtitle4;
1484  QRegExp tmpExpSubtitle5 = m_RTLSubtitle5;
1485  tmpExpSubtitle5.setMinimal(true);
1486  QRegExp tmpExpEpisodeNo1 = m_RTLEpisodeNo1;
1487  QRegExp tmpExpEpisodeNo2 = m_RTLEpisodeNo2;
1488 
1489  // subtitle with episode number: "Folge *: 'subtitle'. description
1490  if (tmpExpSubtitle1.indexIn(event.description) != -1)
1491  {
1492  event.syndicatedepisodenumber = tmpExpSubtitle1.cap(1);
1493  event.subtitle = tmpExpSubtitle1.cap(2);
1494  event.description =
1495  event.description.remove(0, tmpExpSubtitle1.matchedLength());
1496  }
1497  // episode number subtitle
1498  else if (tmpExpSubtitle2.indexIn(event.description) != -1)
1499  {
1500  event.syndicatedepisodenumber = tmpExpSubtitle2.cap(1);
1501  event.subtitle = tmpExpSubtitle2.cap(2);
1502  event.description =
1503  event.description.remove(0, tmpExpSubtitle2.matchedLength());
1504  }
1505  // episode number subtitle
1506  else if (tmpExpSubtitle3.indexIn(event.description) != -1)
1507  {
1508  event.syndicatedepisodenumber = tmpExpSubtitle3.cap(1);
1509  event.subtitle = tmpExpSubtitle3.cap(2);
1510  event.description =
1511  event.description.remove(0, tmpExpSubtitle3.matchedLength());
1512  }
1513  // "Thema..."
1514  else if (tmpExpSubtitle4.indexIn(event.description) != -1)
1515  {
1516  event.subtitle = tmpExpSubtitle4.cap(1);
1517  event.description =
1518  event.description.remove(0, tmpExpSubtitle4.matchedLength());
1519  }
1520  // "'...'"
1521  else if (tmpExpSubtitle5.indexIn(event.description) != -1)
1522  {
1523  event.subtitle = tmpExpSubtitle5.cap(1);
1524  event.description =
1525  event.description.remove(0, tmpExpSubtitle5.matchedLength());
1526  }
1527  // episode number
1528  else if (tmpExpEpisodeNo1.indexIn(event.description) != -1)
1529  {
1530  event.syndicatedepisodenumber = tmpExpEpisodeNo1.cap(2);
1531  event.subtitle = tmpExpEpisodeNo1.cap(1);
1532  event.description =
1533  event.description.remove(0, tmpExpEpisodeNo1.matchedLength());
1534  }
1535  // episode number
1536  else if (tmpExpEpisodeNo2.indexIn(event.description) != -1)
1537  {
1538  event.syndicatedepisodenumber = tmpExpEpisodeNo2.cap(2);
1539  event.subtitle = tmpExpEpisodeNo2.cap(1);
1540  event.description =
1541  event.description.remove(0, tmpExpEpisodeNo2.matchedLength());
1542  }
1543 
1544  /* got an episode title now? (we did not have one at the start of this function) */
1545  if (!event.subtitle.isEmpty())
1546  {
1547  event.categoryType = ProgramInfo::kCategorySeries;
1548  }
1549 
1550  /* if we do not have an episode title by now try some guessing as last resort */
1551  if (event.subtitle.length() == 0)
1552  {
1553  int position;
1554  const uint SUBTITLE_PCT = 35; // % of description to allow subtitle up to
1555  const uint SUBTITLE_MAX_LEN = 50; // max length of subtitle field in db
1556 
1557  if ((position = tmpExp1.indexIn(event.description)) != -1)
1558  {
1559  uint tmpExp1Len = tmpExp1.cap(1).length();
1560  uint evDescLen = max(event.description.length(), 1);
1561 
1562  if ((tmpExp1Len < SUBTITLE_MAX_LEN) &&
1563  (tmpExp1Len * 100 / evDescLen < SUBTITLE_PCT))
1564  {
1565  event.subtitle = tmpExp1.cap(1);
1566  event.description = tmpExp1.cap(2);
1567  }
1568  }
1569  }
1570 }
1571 
1575 void EITFixUp::FixFI(DBEventEIT &event) const
1576 {
1577  int position = event.description.indexOf(m_fiRerun);
1578  if (position != -1)
1579  {
1580  event.previouslyshown = true;
1581  event.description = event.description.replace(m_fiRerun, "");
1582  }
1583 
1584  position = event.description.indexOf(m_fiRerun2);
1585  if (position != -1)
1586  {
1587  event.previouslyshown = true;
1588  event.description = event.description.replace(m_fiRerun2, "");
1589  }
1590 
1591  // Check for (Stereo) in the decription and set the <audio> tags
1592  position = event.description.indexOf(m_Stereo);
1593  if (position != -1)
1594  {
1595  event.audioProps |= AUD_STEREO;
1596  event.description = event.description.replace(m_Stereo, "");
1597  }
1598 }
1599 
1605 {
1606  QString country = "";
1607 
1608  // Find infos about country and year, regisseur and actors
1609  QRegExp tmpInfos = m_dePremiereInfos;
1610  if (tmpInfos.indexIn(event.description) != -1)
1611  {
1612  country = tmpInfos.cap(1).trimmed();
1613  bool ok;
1614  uint y = tmpInfos.cap(2).toUInt(&ok);
1615  if (ok)
1616  event.airdate = y;
1617  event.AddPerson(DBPerson::kDirector, tmpInfos.cap(3));
1618  const QStringList actors = tmpInfos.cap(4).split(
1619  ", ", QString::SkipEmptyParts);
1620  QStringList::const_iterator it = actors.begin();
1621  for (; it != actors.end(); ++it)
1622  event.AddPerson(DBPerson::kActor, *it);
1623  event.description = event.description.replace(tmpInfos.cap(0), "");
1624  }
1625 
1626  // move the original titel from the title to subtitle
1627  QRegExp tmpOTitle = m_dePremiereOTitle;
1628  if (tmpOTitle.indexIn(event.title) != -1)
1629  {
1630  event.subtitle = QString("%1, %2").arg(tmpOTitle.cap(1)).arg(country);
1631  event.title = event.title.replace(tmpOTitle.cap(0), "");
1632  }
1633 }
1634 
1638 void EITFixUp::FixNL(DBEventEIT &event) const
1639 {
1640  QString fullinfo = "";
1641  fullinfo.append (event.subtitle);
1642  fullinfo.append (event.description);
1643  event.subtitle = "";
1644 
1645  // Convert categories to Dutch categories Myth knows.
1646  // nog invoegen: comedy, sport, misdaad
1647 
1648  if (event.category == "Documentary")
1649  {
1650  event.category = "Documentaire";
1651  event.categoryType = ProgramInfo::kCategoryNone;
1652  }
1653  if (event.category == "News")
1654  {
1655  event.category = "Nieuws/actualiteiten";
1656  event.categoryType = ProgramInfo::kCategoryNone;
1657  }
1658  if (event.category == "Kids")
1659  {
1660  event.category = "Jeugd";
1661  event.categoryType = ProgramInfo::kCategoryNone;
1662  }
1663  if (event.category == "Show/game Show")
1664  {
1665  event.category = "Amusement";
1666  event.categoryType = ProgramInfo::kCategoryTVShow;
1667  }
1668  if (event.category == "Music/Ballet/Dance")
1669  {
1670  event.category = "Muziek";
1671  event.categoryType = ProgramInfo::kCategoryNone;
1672  }
1673  if (event.category == "News magazine")
1674  {
1675  event.category = "Informatief";
1676  event.categoryType = ProgramInfo::kCategoryNone;
1677  }
1678  if (event.category == "Movie")
1679  {
1680  event.category = "Film";
1681  event.categoryType = ProgramInfo::kCategoryMovie;
1682  }
1683  if (event.category == "Nature/animals/Environment")
1684  {
1685  event.category = "Natuur";
1686  event.categoryType = ProgramInfo::kCategoryNone;
1687  }
1688  if (event.category == "Movie - Adult")
1689  {
1690  event.category = "Erotiek";
1691  event.categoryType = ProgramInfo::kCategoryNone;
1692  }
1693  if (event.category == "Movie - Soap/melodrama/folkloric")
1694  {
1695  event.category = "Serie/soap";
1696  event.categoryType = ProgramInfo::kCategorySeries;
1697  }
1698  if (event.category == "Arts/Culture")
1699  {
1700  event.category = "Kunst/Cultuur";
1701  event.categoryType = ProgramInfo::kCategoryNone;
1702  }
1703  if (event.category == "Sports")
1704  {
1705  event.category = "Sport";
1706  event.categoryType = ProgramInfo::kCategorySports;
1707  }
1708  if (event.category == "Cartoons/Puppets")
1709  {
1710  event.category = "Animatie";
1711  event.categoryType = ProgramInfo::kCategoryNone;
1712  }
1713  if (event.category == "Movie - Comedy")
1714  {
1715  event.category = "Comedy";
1716  event.categoryType = ProgramInfo::kCategorySeries;
1717  }
1718  if (event.category == "Movie - Detective/Thriller")
1719  {
1720  event.category = "Misdaad";
1721  event.categoryType = ProgramInfo::kCategoryNone;
1722  }
1723  if (event.category == "Social/Spiritual Sciences")
1724  {
1725  event.category = "Religieus";
1726  event.categoryType = ProgramInfo::kCategoryNone;
1727  }
1728 
1729  // Film - categories are usually not Films
1730  if (event.category.startsWith("Film -"))
1731  {
1732  event.categoryType = ProgramInfo:: kCategorySeries;
1733  }
1734 
1735  // Get stereo info
1736  int position;
1737  if ((position = fullinfo.indexOf(m_Stereo)) != -1)
1738  {
1739  event.audioProps |= AUD_STEREO;
1740  fullinfo = fullinfo.replace(m_Stereo, ".");
1741  }
1742 
1743  //Get widescreen info
1744  if ((position = fullinfo.indexOf(m_nlWide)) != -1)
1745  {
1746  fullinfo = fullinfo.replace("breedbeeld", ".");
1747  }
1748 
1749  // Get repeat info
1750  if ((position = fullinfo.indexOf(m_nlRepeat)) != -1)
1751  {
1752  fullinfo = fullinfo.replace("herh.", ".");
1753  }
1754 
1755  // Get teletext subtitle info
1756  if ((position = fullinfo.indexOf(m_nlTxt)) != -1)
1757  {
1758  event.subtitleType |= SUB_NORMAL;
1759  fullinfo = fullinfo.replace("txt", ".");
1760  }
1761 
1762  // Get HDTV information
1763  if ((position = event.title.indexOf(m_nlHD)) != -1)
1764  {
1765  event.videoProps |= VID_HDTV;
1766  event.title = event.title.replace(m_nlHD, "");
1767  }
1768 
1769  // Try to make subtitle from Afl.:
1770  QRegExp tmpSub = m_nlSub;
1771  QString tmpSubString;
1772  if (tmpSub.indexIn(fullinfo) != -1)
1773  {
1774  tmpSubString = tmpSub.cap(0);
1775  tmpSubString = tmpSubString.right(tmpSubString.length() - 7);
1776  event.subtitle = tmpSubString.left(tmpSubString.length() -1);
1777  fullinfo = fullinfo.replace(tmpSub.cap(0), "");
1778  }
1779 
1780  // Try to make subtitle from " "
1781  QRegExp tmpSub2 = m_nlSub2;
1782  //QString tmpSubString2;
1783  if (tmpSub2.indexIn(fullinfo) != -1)
1784  {
1785  tmpSubString = tmpSub2.cap(0);
1786  tmpSubString = tmpSubString.right(tmpSubString.length() - 2);
1787  event.subtitle = tmpSubString.left(tmpSubString.length() -1);
1788  fullinfo = fullinfo.replace(tmpSub2.cap(0), "");
1789  }
1790 
1791 
1792  // This is trying to catch the case where the subtitle is in the main title
1793  // but avoid cases where it isn't a subtitle e.g cd:uk
1794  if (((position = event.title.indexOf(":")) != -1) &&
1795  (event.title[position + 1].toUpper() == event.title[position + 1]) &&
1796  (event.subtitle.isEmpty()))
1797  {
1798  event.subtitle = event.title.mid(position + 1);
1799  event.title = event.title.left(position);
1800  }
1801 
1802 
1803  // Get the actors
1804  QRegExp tmpActors = m_nlActors;
1805  if (tmpActors.indexIn(fullinfo) != -1)
1806  {
1807  QString tmpActorsString = tmpActors.cap(0);
1808  tmpActorsString = tmpActorsString.right(tmpActorsString.length() - 6);
1809  tmpActorsString = tmpActorsString.left(tmpActorsString.length() - 5);
1810  const QStringList actors =
1811  tmpActorsString.split(", ", QString::SkipEmptyParts);
1812  QStringList::const_iterator it = actors.begin();
1813  for (; it != actors.end(); ++it)
1814  event.AddPerson(DBPerson::kActor, *it);
1815  fullinfo = fullinfo.replace(tmpActors.cap(0), "");
1816  }
1817 
1818  // Try to find presenter
1819  QRegExp tmpPres = m_nlPres;
1820  if (tmpPres.indexIn(fullinfo) != -1)
1821  {
1822  QString tmpPresString = tmpPres.cap(0);
1823  tmpPresString = tmpPresString.right(tmpPresString.length() - 14);
1824  tmpPresString = tmpPresString.left(tmpPresString.length() -1);
1825  const QStringList host =
1826  tmpPresString.split(m_nlPersSeparator, QString::SkipEmptyParts);
1827  QStringList::const_iterator it = host.begin();
1828  for (; it != host.end(); ++it)
1829  event.AddPerson(DBPerson::kPresenter, *it);
1830  fullinfo = fullinfo.replace(tmpPres.cap(0), "");
1831  }
1832 
1833  // Try to find year
1834  QRegExp tmpYear1 = m_nlYear1;
1835  QRegExp tmpYear2 = m_nlYear2;
1836  if ((position = tmpYear1.indexIn(fullinfo)) != -1)
1837  {
1838  bool ok;
1839  uint y = tmpYear1.cap(0).toUInt(&ok);
1840  if (ok)
1841  event.originalairdate = QDate(y, 1, 1);
1842  }
1843 
1844  if ((position = tmpYear2.indexIn(fullinfo)) != -1)
1845  {
1846  bool ok;
1847  uint y = tmpYear2.cap(2).toUInt(&ok);
1848  if (ok)
1849  event.originalairdate = QDate(y, 1, 1);
1850  }
1851 
1852  // Try to find director
1853  QRegExp tmpDirector = m_nlDirector;
1854  QString tmpDirectorString;
1855  if ((position = fullinfo.indexOf(m_nlDirector)) != -1)
1856  {
1857  tmpDirectorString = tmpDirector.cap(0);
1858  event.AddPerson(DBPerson::kDirector, tmpDirectorString);
1859  }
1860 
1861  // Strip leftovers
1862  if ((position = fullinfo.indexOf(m_nlRub)) != -1)
1863  {
1864  fullinfo = fullinfo.replace(m_nlRub, "");
1865  }
1866 
1867  // Strip category info from description
1868  if ((position = fullinfo.indexOf(m_nlCat)) != -1)
1869  {
1870  fullinfo = fullinfo.replace(m_nlCat, "");
1871  }
1872 
1873  // Remove omroep from title
1874  if ((position = event.title.indexOf(m_nlOmroep)) != -1)
1875  {
1876  event.title = event.title.replace(m_nlOmroep, "");
1877  }
1878 
1879  // Put information back in description
1880 
1881  event.description = fullinfo;
1882  event.description = event.description.trimmed();
1883  event.title = event.title.trimmed();
1884  event.subtitle = event.subtitle.trimmed();
1885 
1886 }
1887 
1889 {
1890  // remove category movie from short events
1892  event.starttime.secsTo(event.endtime) < kMinMovieDuration)
1893  {
1894  /* default taken from ContentDescriptor::GetMythCategory */
1895  event.categoryType = ProgramInfo::kCategoryTVShow;
1896  }
1897 }
1898 
1902 void EITFixUp::FixNO(DBEventEIT &event) const
1903 {
1904  // Check for "title (R)" in the title
1905  int position = event.title.indexOf(m_noRerun);
1906  if (position != -1)
1907  {
1908  event.previouslyshown = true;
1909  event.title = event.title.replace(m_noRerun, "");
1910  }
1911  // Check for "subtitle (HD)" in the subtitle
1912  position = event.subtitle.indexOf(m_noHD);
1913  if (position != -1)
1914  {
1915  event.videoProps |= VID_HDTV;
1916  event.subtitle = event.subtitle.replace(m_noHD, "");
1917  }
1918  // Check for "description (HD)" in the description
1919  position = event.description.indexOf(m_noHD);
1920  if (position != -1)
1921  {
1922  event.videoProps |= VID_HDTV;
1923  event.description = event.description.replace(m_noHD, "");
1924  }
1925 }
1926 
1931 {
1932  int position;
1933  QRegExp tmpExp1;
1934  // Check for "title (R)" in the title
1935  position = event.title.indexOf(m_noRerun);
1936  if (position != -1)
1937  {
1938  event.previouslyshown = true;
1939  event.title = event.title.replace(m_noRerun, "");
1940  }
1941  // Check for "(R)" in the description
1942  position = event.description.indexOf(m_noRerun);
1943  if (position != -1)
1944  {
1945  event.previouslyshown = true;
1946  }
1947  // Move colon separated category from program-titles into description
1948  // Have seen "NRK2s historiekveld: Film: bla-bla"
1949  tmpExp1 = m_noNRKCategories;
1950  while (((position = tmpExp1.indexIn(event.title)) != -1) &&
1951  (tmpExp1.cap(2).length() > 1))
1952  {
1953  event.title = tmpExp1.cap(2);
1954  event.description = "(" + tmpExp1.cap(1) + ") " + event.description;
1955  }
1956  // Remove season premiere markings
1957  tmpExp1 = m_noPremiere;
1958  if ((position = tmpExp1.indexIn(event.title)) >=3)
1959  {
1960  event.title.remove(m_noPremiere);
1961  }
1962  // Try to find colon-delimited subtitle in title, only tested for NRK channels
1963  tmpExp1 = m_noColonSubtitle;
1964  if (!event.title.startsWith("CSI:") &&
1965  !event.title.startsWith("CD:") &&
1966  !event.title.startsWith("Distriktsnyheter: fra"))
1967  {
1968  if ((position = tmpExp1.indexIn(event.title)) != -1)
1969  {
1970 
1971  if (event.subtitle.length() <= 0)
1972  {
1973  event.title = tmpExp1.cap(1);
1974  event.subtitle = tmpExp1.cap(2);
1975  }
1976  else if (event.subtitle == tmpExp1.cap(2))
1977  {
1978  event.title = tmpExp1.cap(1);
1979  }
1980  }
1981  }
1982 }
1983 
1987 void EITFixUp::FixDK(DBEventEIT &event) const
1988 {
1989  // Source: YouSee Rules of Operation v1.16
1990  // url: http://yousee.dk/~/media/pdf/CPE/Rules_Operation.ashx
1991  int position = -1;
1992  int episode = -1;
1993  int season = -1;
1994  QRegExp tmpRegEx;
1995  // Title search
1996  // episode and part/part total
1997  tmpRegEx = m_dkEpisode;
1998  position = event.title.indexOf(tmpRegEx);
1999  if (position != -1)
2000  {
2001  episode = tmpRegEx.cap(1).toInt();
2002  event.partnumber = tmpRegEx.cap(1).toInt();
2003  event.title = event.title.replace(tmpRegEx, "");
2004  }
2005 
2006  tmpRegEx = m_dkPart;
2007  position = event.title.indexOf(tmpRegEx);
2008  if (position != -1)
2009  {
2010  episode = tmpRegEx.cap(1).toInt();
2011  event.partnumber = tmpRegEx.cap(1).toInt();
2012  event.parttotal = tmpRegEx.cap(2).toInt();
2013  event.title = event.title.replace(tmpRegEx, "");
2014  }
2015 
2016  // subtitle delimiters
2017  tmpRegEx = m_dkSubtitle1;
2018  position = event.title.indexOf(tmpRegEx);
2019  if (position != -1)
2020  {
2021  event.title = tmpRegEx.cap(1);
2022  event.subtitle = tmpRegEx.cap(2);
2023  }
2024  else
2025  {
2026  tmpRegEx = m_dkSubtitle2;
2027  if(event.title.indexOf(tmpRegEx) != -1)
2028  {
2029  event.title = tmpRegEx.cap(1);
2030  event.subtitle = tmpRegEx.cap(2);
2031  }
2032  }
2033  // Description search
2034  // Season (Sæson [:digit:]+.) => episode = season episode number
2035  // or year (- år [:digit:]+(\\)|:) ) => episode = total episode number
2036  tmpRegEx = m_dkSeason1;
2037  position = event.description.indexOf(tmpRegEx);
2038  if (position != -1)
2039  {
2040  season = tmpRegEx.cap(1).toInt();
2041  }
2042  else
2043  {
2044  tmpRegEx = m_dkSeason2;
2045  if(event.description.indexOf(tmpRegEx) != -1)
2046  {
2047  season = tmpRegEx.cap(1).toInt();
2048  }
2049  }
2050 
2051  //Feature:
2052  tmpRegEx = m_dkFeatures;
2053  position = event.description.indexOf(tmpRegEx);
2054  if (position != -1)
2055  {
2056  QString features = tmpRegEx.cap(1);
2057  event.description = event.description.replace(tmpRegEx, "");
2058  // 16:9
2059  if (features.indexOf(m_dkWidescreen) != -1)
2060  event.videoProps |= VID_WIDESCREEN;
2061  // HDTV
2062  if (features.indexOf(m_dkHD) != -1)
2063  event.videoProps |= VID_HDTV;
2064  // Dolby Digital surround
2065  if (features.indexOf(m_dkDolby) != -1)
2066  event.audioProps |= AUD_DOLBY;
2067  // surround
2068  if (features.indexOf(m_dkSurround) != -1)
2069  event.audioProps |= AUD_SURROUND;
2070  // stereo
2071  if (features.indexOf(m_dkStereo) != -1)
2072  event.audioProps |= AUD_STEREO;
2073  // (G)
2074  if (features.indexOf(m_dkReplay) != -1)
2075  event.previouslyshown = true;
2076  // TTV
2077  if (features.indexOf(m_dkTxt) != -1)
2078  event.subtitleType |= SUB_NORMAL;
2079  }
2080 
2081  // Series and program id
2082  // programid is currently not transmitted
2083  // YouSee doesn't use a default authority but uses the first byte after
2084  // the / to indicate if the seriesid is global unique or unique on the
2085  // service id
2086  if (event.seriesId.length() >= 1 && event.seriesId[0] == '/')
2087  {
2088  QString newid;
2089  if (event.seriesId[1] == '1')
2090  newid = QString("%1%2").arg(event.chanid).
2091  arg(event.seriesId.mid(2,8));
2092  else
2093  newid = event.seriesId.mid(2,8);
2094  event.seriesId = newid;
2095  }
2096 
2097  if (event.programId.length() >= 1 && event.programId[0] == '/')
2098  event.programId[0]='_';
2099 
2100  // Add season and episode number to subtitle
2101  if(episode>0)
2102  {
2103  event.subtitle = QString("%1 (%2").arg(event.subtitle).arg(episode);
2104  if (event.parttotal >0)
2105  event.subtitle = QString("%1:%2").arg(event.subtitle).
2106  arg(event.parttotal);
2107  if (season>0)
2108  {
2109  event.syndicatedepisodenumber =
2110  QString("E%1S%2").arg(episode).arg(season);
2111  event.subtitle = QString("%1 Sæson %2").arg(event.subtitle).
2112  arg(season);
2113  }
2114  event.subtitle = QString("%1)").arg(event.subtitle);
2115  }
2116  // Find actors and director in description
2117  tmpRegEx = m_dkDirector;
2118  bool directorPresent = false;
2119  position = event.description.indexOf(tmpRegEx);
2120  if (position != -1)
2121  {
2122  QString tmpDirectorsString = tmpRegEx.cap(1);
2123  const QStringList directors =
2124  tmpDirectorsString.split(m_dkPersonsSeparator, QString::SkipEmptyParts);
2125  QStringList::const_iterator it = directors.begin();
2126  for (; it != directors.end(); ++it)
2127  {
2128  tmpDirectorsString = it->split(":").last().trimmed().
2129  remove(QRegExp("\\.$"));
2130  if (tmpDirectorsString != "")
2131  event.AddPerson(DBPerson::kDirector, tmpDirectorsString);
2132  }
2133  directorPresent = true;
2134  }
2135 
2136  tmpRegEx = m_dkActors;
2137  position = event.description.indexOf(tmpRegEx);
2138  if (position != -1)
2139  {
2140  QString tmpActorsString = tmpRegEx.cap(1);
2141  if (directorPresent)
2142  tmpActorsString = tmpActorsString.replace(m_dkDirector,"");
2143  const QStringList actors =
2144  tmpActorsString.split(m_dkPersonsSeparator, QString::SkipEmptyParts);
2145  QStringList::const_iterator it = actors.begin();
2146  for (; it != actors.end(); ++it)
2147  {
2148  tmpActorsString = it->split(":").last().trimmed().
2149  remove(QRegExp("\\.$"));
2150  if (tmpActorsString != "")
2151  event.AddPerson(DBPerson::kActor, tmpActorsString);
2152  }
2153  }
2154  //find year
2155  tmpRegEx = m_dkYear;
2156  position = event.description.indexOf(tmpRegEx);
2157  if (position != -1)
2158  {
2159  bool ok;
2160  uint y = tmpRegEx.cap(1).toUInt(&ok);
2161  if (ok)
2162  event.originalairdate = QDate(y, 1, 1);
2163  }
2164  // Remove white spaces
2165  event.description = event.description.trimmed();
2166  event.title = event.title.trimmed();
2167  event.subtitle = event.subtitle.trimmed();
2168 }