MythTV  master
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 #include "mythlogging.h"
12 
13 /*------------------------------------------------------------------------
14  * Event Fix Up Scripts - Turned on by entry in dtv_privatetype table
15  *------------------------------------------------------------------------*/
16 
17 // Constituents of UK season regexp, decomposed for clarity
18 
19 // Matches Season 2, S 2 and "Series 2," etc but not "hits 2"
20 // cap1 = season
21 const QString seasonStr = R"(\b(?:Season|Series|S)\s*(\d+)\s*,?)";
22 
23 // Matches Episode 3, Ep 3/4, Ep 3 of 4 etc but not "step 1"
24 // cap1 = ep, cap2 = total
25 const QString longEp = R"(\b(?:Ep|Episode)\s*(\d+)\s*(?:(?:/|of)\s*(\d*))?)";
26 
27 // Matches S2 Ep 3/4, "Season 2, Ep 3 of 4", Episode 3 etc
28 // cap1 = season, cap2 = ep, cap3 = total
29 const QString longSeasEp = QString("\\(?(?:%1)?\\s*%2").arg(seasonStr, longEp);
30 
31 // Matches long seas/ep with surrounding parenthesis & trailing period
32 // cap1 = season, cap2 = ep, cap3 = total
33 const QString longContext = QString(R"(\(*%1\s*\)?\s*\.?)").arg(longSeasEp);
34 
35 // Matches 3/4, 3 of 4
36 // cap1 = ep, cap2 = total
37 const QString shortEp = R"((\d+)\s*(?:/|of)\s*(\d+))";
38 
39 // Matches short ep/total, ignoring Parts and idioms such as 9/11, 24/7 etc.
40 // ie. x/y in parenthesis or has no leading or trailing text in the sentence.
41 // cap0 may include previous/anchoring period
42 // cap1 = shortEp with surrounding parenthesis & trailing period (to remove)
43 // cap2 = ep, cap3 = total,
44 const QString shortContext =
45  QString(R"((?:^|\.)(\s*\(*\s*%1[\s)]*(?:[).:]|$)))").arg(shortEp);
46 
47 
49  : m_bellYear("[\\(]{1}[0-9]{4}[\\)]{1}"),
50  m_bellActors("\\set\\s|,"),
51  m_bellPPVTitleAllDayHD(R"(\s*\(All Day\, HD\)\s*$)"),
52  m_bellPPVTitleAllDay(R"(\s*\(All Day.*\)\s*$)"),
53  m_bellPPVTitleHD("^HD\\s?-\\s?"),
54  m_bellPPVSubtitleAllDay(R"(^All Day \(.*\sEastern\)\s*$)"),
55  m_bellPPVDescriptionAllDay(R"(^\(.*\sEastern\))"),
56  m_bellPPVDescriptionAllDay2(R"(^\([0-9].*am-[0-9].*am\sET\))"),
57  m_bellPPVDescriptionEventId("\\([0-9]{5}\\)"),
58  m_dishPPVTitleHD("\\sHD\\s*$"),
59  m_dishPPVTitleColon("\\:\\s*$"),
60  m_dishPPVSpacePerenEnd(R"(\s\)\s*$)"),
61  m_dishDescriptionNew(R"(\s*New\.\s*)"),
62  m_dishDescriptionFinale(R"(\s*(Series|Season)\sFinale\.\s*)"),
63  m_dishDescriptionFinale2(R"(\s*Finale\.\s*)"),
64  m_dishDescriptionPremiere(R"(\s*(Series|Season)\s(Premier|Premiere)\.\s*)"),
65  m_dishDescriptionPremiere2(R"(\s*(Premier|Premiere)\.\s*)"),
66  m_dishPPVCode(R"(\s*\(([A-Z]|[0-9]){5}\)\s*$)"),
67  m_ukThen("\\s*(Then|Followed by) 60 Seconds\\.", Qt::CaseInsensitive),
68  m_ukNew(R"((New\.|\s*(Brand New|New)\s*(Series|Episode)\s*[:\.\-]))",Qt::CaseInsensitive),
69  m_ukNewTitle("^(Brand New|New:)\\s*",Qt::CaseInsensitive),
70  m_ukAlsoInHD("\\s*Also in HD\\.",Qt::CaseInsensitive),
71  m_ukCEPQ(R"([:\!\.\?]\s)"),
72  m_ukColonPeriod("[:\\.]"),
73  m_ukDotSpaceStart("^\\. "),
74  m_ukDotEnd("\\.$"),
75  m_ukSpaceColonStart("^[ |:]*"),
76  m_ukSpaceStart("^ "),
77  m_ukPart(R"([-(\:,.]\s*(?:Part|Pt)\s*(\d+)\s*(?:(?:of|/)\s*(\d+))?\s*[-):,.])", Qt::CaseInsensitive),
78  // Prefer long format resorting to short format
79  // cap0 = long match to remove, cap1 = long season, cap2 = long ep, cap3 = long total,
80  // cap4 = short match to remove, cap5 = short ep, cap6 = short total
81  m_ukSeries("(?:" + longContext + "|" + shortContext + ")", Qt::CaseInsensitive),
82  m_ukCC("\\[(?:(AD|SL|S|W|HD),?)+\\]"),
83  m_ukYear(R"([\[\(]([\d]{4})[\)\]])"),
84  m_uk24ep("^\\d{1,2}:00[ap]m to \\d{1,2}:00[ap]m: "),
85  m_ukStarring(R"((?:Western\s)?[Ss]tarring ([\w\s\-']+)[Aa]nd\s([\w\s\-']+)[\.|,](?:\s)*(\d{4})?(?:\.\s)?)"),
86  m_ukBBC7rpt(R"(\[Rptd?[^]]+\d{1,2}\.\d{1,2}[ap]m\]\.)"),
87  m_ukDescriptionRemove(R"(^(?:CBBC\s*\.|CBeebies\s*\.|Class TV\s*:|BBC Switch\.))"),
88  m_ukTitleRemove("^(?:[tT]4:|Schools\\s*:)"),
89  m_ukDoubleDotEnd("\\.\\.+$"),
90  m_ukDoubleDotStart("^\\.\\.+"),
91  m_ukTime(R"(\d{1,2}[\.:]\d{1,2}\s*(am|pm|))"),
92  m_ukBBC34("BBC (?:THREE|FOUR) on BBC (?:ONE|TWO)\\.",Qt::CaseInsensitive),
93  m_ukYearColon("^[\\d]{4}:"),
94  m_ukExclusionFromSubtitle("(starring|stars\\s|drama|series|sitcom)",Qt::CaseInsensitive),
95  m_ukCompleteDots("^\\.\\.+$"),
96  m_ukQuotedSubtitle(R"((?:^')([\w\s\-,]+)(?:\.' ))"),
97  m_ukAllNew("All New To 4Music!\\s?"),
98  m_ukLaONoSplit("^Law & Order: (?:Criminal Intent|LA|Special Victims Unit|Trial by Jury|UK|You the Jury)"),
99  m_comHemCountry("^(\\(.+\\))?\\s?([^ ]+)\\s([^\\.0-9]+)"
100  "(?:\\sfr\xE5n\\s([0-9]{4}))(?:\\smed\\s([^\\.]+))?\\.?"),
101  m_comHemDirector("[Rr]egi"),
102  m_comHemActor("[Ss]k\xE5""despelare|[Ii] rollerna"),
103  m_comHemHost("[Pp]rogramledare"),
104  m_comHemSub("[.\\?\\!] "),
105  m_comHemRerun1("[Rr]epris\\sfr\xE5n\\s([^\\.]+)(?:\\.|$)"),
106  m_comHemRerun2("([0-9]+)/([0-9]+)(?:\\s-\\s([0-9]{4}))?"),
107  m_comHemTT("[Tt]ext-[Tt][Vv]"),
108  m_comHemPersSeparator("(, |\\soch\\s)"),
109  m_comHemPersons("\\s?([Rr]egi|[Ss]k\xE5""despelare|[Pp]rogramledare|"
110  "[Ii] rollerna):\\s([^\\.]+)\\."),
111  m_comHemSubEnd(R"(\s?\.\s?$)"),
112  m_comHemSeries1("\\s?(?:[dD]el|[eE]pisode)\\s([0-9]+)"
113  "(?:\\s?(?:/|:|av)\\s?([0-9]+))?\\."),
114  m_comHemSeries2(R"(\s?-?\s?([Dd]el\s+([0-9]+)))"),
115  m_comHemTSub(R"(\s+-\s+([^\-]+))"),
116  m_mcaIncompleteTitle(R"((.*).\.\.\.$)"),
117  m_mcaCompleteTitlea("^'?("),
118  m_mcaCompleteTitleb(R"([^\.\?]+[^\'])'?[\.\?]\s+(.+))"),
119  m_mcaSubtitle(R"(^'([^\.]+)'\.\s+(.+))"),
120  m_mcaSeries(R"(^S?(\d+)\/E?(\d+)\s-\s(.*)$)"),
121  m_mcaCredits(R"((.*)\s\((\d{4})\)\s*([^\.]+)\.?\s*$)"),
122  m_mcaAvail(R"(\s(Only available on [^\.]*bouquet|Not available in RSA [^\.]*)\.?)"),
123  m_mcaActors(R"((.*\.)\s+([^\.]+\s[A-Z][^\.]+)\.\s*)"),
124  m_mcaActorsSeparator("(,\\s+)"),
125  m_mcaYear(R"((.*)\s\((\d{4})\)\s*$)"),
126  m_mcaCC(",?\\s(HI|English) Subtitles\\.?"),
127  m_mcaDD(",?\\sDD\\.?"),
128  m_rtlRepeat(R"((\(|\s)?Wiederholung.+vo[m|n].+((?:\d{2}\.\d{2}\.\d{4})|(?:\d{2}[:\.]\d{2}\sUhr))\)?)"),
129  m_rtlSubtitle(R"(^([^\.]{3,})\.\s+(.+))"),
130  /* should be (?:\x{8a}|\\.\\s*|$) but 0x8A gets replaced with 0x20 */
131  m_rtlSubtitle1(R"(^Folge\s(\d{1,4})\s*:\s+'(.*)'(?:\s|\.\s*|$))"),
132  m_rtlSubtitle2(R"(^Folge\s(\d{1,4})\s+(.{,5}[^\.]{,120})[\?!\.]\s*)"),
133  m_rtlSubtitle3(R"(^(?:Folge\s)?(\d{1,4}(?:\/[IVX]+)?)\s+(.{,5}[^\.]{,120})[\?!\.]\s*)"),
134  m_rtlSubtitle4(R"(^Thema.{0,5}:\s([^\.]+)\.\s*)"),
135  m_rtlSubtitle5("^'(.+)'\\.\\s*"),
136  m_pro7Subtitle(",{0,1}([^,]*),([^,]+)\\s{0,1}(\\d{4})$"),
137  m_pro7Crew("\n\n(Regie:.*)$"),
138  m_pro7CrewOne("^(.*):\\s+(.*)$"),
139  m_pro7Cast("\n\nDarsteller:\n(.*)$"),
140  m_pro7CastOne(R"(^([^\(]*)\((.*)\)$)"),
141  m_atvSubtitle(R"(,{0,1}\sFolge\s(\d{1,3})$)"),
142  m_disneyChannelSubtitle(",([^,]+)\\s{0,1}(\\d{4})$"),
143  m_rtlEpisodeNo1(R"(^(Folge\s\d{1,4})\.*\s*)"),
144  m_rtlEpisodeNo2(R"(^(\d{1,2}\/[IVX]+)\.*\s*)"),
145  m_fiRerun(R"(\ ?Uusinta[a-zA-Z\ ]*\.?)"),
146  m_fiRerun2("\\([Uu]\\)"),
147  m_fiAgeLimit("\\(((1?[0-9]?)|[ST])\\)$"),
148  m_fiFilm("^(Film|Elokuva): "),
149  m_dePremiereLength(R"(\s?[0-9]+\sMin\.)"),
150  m_dePremiereAirdate(R"(\s?([^\s^\.]+)\s((?:1|2)[0-9]{3})\.)"),
151  m_dePremiereCredits(R"(\sVon\s([^,]+)(?:,|\su\.\sa\.)\smit\s([^\.]*)\.)"),
152  m_dePremiereOTitle(R"(\s*\(([^\)]*)\)$)"),
153  m_deSkyDescriptionSeasonEpisode(R"(^(\d{1,2}).\sStaffel,\sFolge\s(\d{1,2}):\s)"),
154  m_nlTxt("txt"),
155  m_nlWide("breedbeeld"),
156  m_nlRepeat("herh."),
157  m_nlHD("\\sHD$"),
158  m_nlSub(R"(\sAfl\.:\s([^\.]+)\.)"),
159  m_nlSub2("\\s\"([^\"]+)\""),
160  m_nlActors(R"(\sMet:\s.+e\.a\.)"),
161  m_nlPres(R"(\sPresentatie:\s([^\.]+)\.)"),
162  m_nlPersSeparator("(, |\\sen\\s)"),
163  m_nlRub(R"(\s?\({1}\W+\){1}\s?)"),
164  m_nlYear1("(?=\\suit\\s)([1-2]{2}[0-9]{2})"),
165  m_nlYear2(R"(([\s]{1}[\(]{1}[A-Z]{0,3}/?)([1-2]{2}[0-9]{2})([\)]{1}))"),
166  m_nlDirector(R"((?=\svan\s)(([A-Z]{1}[a-z]+\s)|([A-Z]{1}\.\s)))"),
167  m_nlCat("^(Amusement|Muziek|Informatief|Nieuws/actualiteiten|Jeugd|Animatie|Sport|Serie/soap|Kunst/Cultuur|Documentaire|Film|Natuur|Erotiek|Comedy|Misdaad|Religieus)\\.\\s"),
168  m_nlOmroep (R"(\s\(([A-Z]+/?)+\)$)"),
169  m_noRerun("\\(R\\)"),
170  m_noHD(R"([\(\[]HD[\)\]])"),
171  m_noColonSubtitle("^([^:]+): (.+)"),
172  m_noNRKCategories("^(Superstrek[ea]r|Supersomm[ea]r|Superjul|Barne-tv|Fantorangen|Kuraffen|Supermorg[eo]n|Julemorg[eo]n|Sommermorg[eo]n|"
173  "Kuraffen-TV|Sport i dag|NRKs sportsl.rdag|NRKs sportss.ndag|Dagens dokumentar|"
174  "NRK2s historiekveld|Detektimen|Nattkino|Filmklassiker|Film|Kortfilm|P.skemorg[eo]n|"
175  "Radioteatret|Opera|P2-Akademiet|Nyhetsmorg[eo]n i P2 og Alltid Nyheter:): (.+)"),
176  m_noPremiere("\\s+-\\s+(Sesongpremiere|Premiere|premiere)!?$"),
177  m_stereo(R"(\b\(?[sS]tereo\)?\b)"),
178  m_dkEpisode("\\(([0-9]+)\\)"),
179  m_dkPart("\\(([0-9]+):([0-9]+)\\)"),
180  m_dkSubtitle1("^([^:]+): (.+)"),
181  m_dkSubtitle2("^([^:]+) - (.+)"),
182  m_dkSeason1("S\xE6son ([0-9]+)\\."),
183  m_dkSeason2("- \xE5r ([0-9]+)(?: :)"),
184  m_dkFeatures("Features:(.+)"),
185  m_dkWidescreen(" 16:9"),
186  m_dkDolby(" 5:1"),
187  m_dkSurround(R"( \(\(S\)\))"),
188  m_dkStereo(" S"),
189  m_dkReplay(" \\(G\\)"),
190  m_dkTxt(" TTV"),
191  m_dkHD(" HD"),
192  m_dkActors("(?:Medvirkende: |Medv\\.: )(.+)"),
193  m_dkPersonsSeparator("(, )|(og )"),
194  m_dkDirector("(?:Instr.: |Instrukt.r: )(.+)$"),
195  m_dkYear(" fra ([0-9]{4})[ \\.]"),
196  m_auFreeviewSY(R"((.*) \((.+)\) \(([12][0-9][0-9][0-9])\)$)"),
197  m_auFreeviewY("(.*) \\(([12][0-9][0-9][0-9])\\)$"),
198  m_auFreeviewYC(R"((.*) \(([12][0-9][0-9][0-9])\) \((.+)\)$)"),
199  m_auFreeviewSYC(R"((.*) \((.+)\) \(([12][0-9][0-9][0-9])\) \((.+)\)$)"),
200  m_html("</?EM>", Qt::CaseInsensitive),
201  m_grReplay("\\([ΕE]\\)"),
202  m_grDescriptionFinale("\\s*Τελευταίο\\sΕπεισόδιο\\.\\s*"),
203  m_grActors("(?:[Ππ]α[ιί]ζουν:|[ΜMμ]ε τους:|Πρωταγωνιστο[υύ]ν:|Πρωταγωνιστε[ιί]:?)(?:\\s+στο ρόλο(?: του| της)?\\s(?:\\w+\\s[οη]\\s))?([-\\w\\s']+(?:,[-\\w\\s']+)*)(?:κ\\.[αά])?(?:\\W?)"),
204  // cap(1) actors, just names
205  m_grFixnofullstopActors("(\\w\\s(Παίζουν:|Πρωταγων))"),
206  m_grFixnofullstopDirectors("((\\w\\s(Σκηνοθ[εέ]))"),
207  m_grPeopleSeparator("([,-]\\s+)"),
208  m_grDirector("(?:Σκηνοθεσία: |Σκηνοθέτης: |Σκηνοθέτης - Επιμέλεια: )(\\w+\\s\\w+\\s?)(?:\\W?)"),
209  m_grPres("(?:Παρουσ[ιί]αση:(?:\\b)*|Παρουσι[αά]ζ(?:ουν|ει)(?::|\\sο|\\sη)|Παρουσι[αά]στ(?:[ηή]ς|ρια|ριες|[εέ]ς)(?::|\\sο|\\sη)|Με τ(?:ον |ην )(?:[\\s|:|ο|η])*(?:\\b)*)([-\\w\\s]+(?:,[-\\w\\s]+)*)(?:\\W?)"),
210  m_grYear("(?:\\W?)(?:\\s?παραγωγ[ηή]ς|\\s?-|,)\\s*([1-2]{1}[0-9]{3})(?:-\\d{1,4})?",Qt::CaseInsensitive),
211  m_grCountry("(?:\\W|\\b)(?:(ελλην|τουρκ|αμερικ[αά]ν|γαλλ|αγγλ|βρεττ?αν|γερμαν|ρωσσ?|ιταλ|ελβετ|σουηδ|ισπαν|πορτογαλ|μεξικ[αά]ν|κιν[εέ]ζικ|ιαπων|καναδ|βραζιλι[αά]ν)(ικ[ηή][ςσ]))",Qt::CaseInsensitive),
212  m_grlongEp("\\b(?:Επ.|επεισ[οό]διο:?)\\s*(\\d+)(?:\\W?)",Qt::CaseInsensitive),
213  m_grSeasonAsRomanNumerals(",\\s*([MDCLXVIΙΧ]+)$",Qt::CaseInsensitive),
214  m_grSeason("(?:\\W-?)*(?:\\(-\\s*)?\\b(([Α-Ω]{1,2})(?:'|΄)?|(\\d{1,2})(?:ος|ου|oς|os)?)(?:\\s*κ[υύ]κλο(?:[σς]|υ)){1}\\s?",Qt::CaseInsensitive),
215  m_grRealTitleinDescription(R"((?:^\()([A-Za-z\s\d-]+)(?:\))(?:\s*))"),
216  // cap1 = real title
217  // cap0 = real title in parentheses.
218  m_grRealTitleinTitle(R"((?:\()([A-Za-z\s\d-]+)(?:\))(?:\s*$)*)"),
219  // cap1 = real title
220  // cap0 = real title in parentheses.
221  m_grCommentsinTitle("(?:\\()([Α-Ωα-ω\\s\\d-]+)(?:\\))(?:\\s*$)*"),
222  // cap1 = real title
223  // cap0 = real title in parentheses.
224  m_grNotPreviouslyShown("(?:\\W?)(?:-\\s*)*(?:\\b[Α1]['΄η]?\\s*(?:τηλεοπτικ[ηή]\\s*)?(?:μετ[αά]δοση|προβολ[ηή]))(?:\\W?)",Qt::CaseInsensitive),
225  // Try to exctract Greek categories from keywords in description.
226  m_grEpisodeAsSubtitle("(?:^Επεισ[οό]διο:\\s?)([\\w\\s-,']+)\\.(?:\\s)?"),
227  m_grCategFood("(?:\\W)?(?:εκπομπ[ηή]\\W)?(Γαστρονομ[ιί]α[σς]?|μαγειρικ[ηή][σς]?|chef|συνταγ[εέηή]|διατροφ|wine|μ[αά]γειρα[σς]?)(?:\\W)?",Qt::CaseInsensitive),
228  m_grCategDrama("(?:\\W)?(κοινωνικ[ηήό]|δραματικ[ηή]|δρ[αά]μα)(?:\\W)(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?",Qt::CaseInsensitive),
229  m_grCategComedy("(?:\\W)?(κωμικ[ηήοό]|χιουμοριστικ[ηήοό]|κωμωδ[ιί]α)(?:\\W)(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?",Qt::CaseInsensitive),
230  m_grCategChildren("(?:\\W)?(παιδικ[ηήοό]|κινο[υύ]μ[εέ]ν(ων|α)\\sσχ[εέ]δ[ιί](ων|α))(?:\\W)(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?",Qt::CaseInsensitive),
231  m_grCategMystery("(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?(?:\\W)?(μυστηρ[ιί]ου)(?:\\W)?",Qt::CaseInsensitive),
232  m_grCategFantasy("(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?(?:\\W)?(φαντασ[ιί]ας)(?:\\W)?",Qt::CaseInsensitive),
233  m_grCategHistory("(?:\\W)?(ιστορικ[ηήοό])(?:\\W)?(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?",Qt::CaseInsensitive),
234  m_grCategTeleMag("(?:\\W)?(ενημερωτικ[ηή]|ψυχαγωγικ[ηή]|τηλεπεριοδικ[οό]|μαγκαζ[ιί]νο)(?:\\W)?(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?",Qt::CaseInsensitive),
235  m_grCategTeleShop("(?:\\W)?(οδηγ[οό][σς]?\\sαγορ[ωώ]ν|τηλεπ[ωώ]λ[ηή]σ|τηλεαγορ|τηλεμ[αά]ρκετ|telemarket)(?:\\W)?(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?",Qt::CaseInsensitive),
236  m_grCategGameShow("(?:\\W)?(τηλεπαιχν[ιί]δι|quiz)(?:\\W)?",Qt::CaseInsensitive),
237  m_grCategDocumentary("(?:\\W)?(ντοκ[ιυ]μαντ[εέ]ρ)(?:\\W)?",Qt::CaseInsensitive),
238  m_grCategBiography("(?:\\W)?(βιογραφ[ιί]α|βιογραφικ[οό][σς]?)(?:\\W)?",Qt::CaseInsensitive),
239  m_grCategNews("(?:\\W)?(δελτ[ιί]ο\\W?|ειδ[ηή]σε(ι[σς]|ων))(?:\\W)?",Qt::CaseInsensitive),
240  m_grCategSports("(?:\\W)?(champion|αθλητικ[αάοόηή]|πρωτ[αά]θλημα|ποδ[οό]σφαιρο(ου)?|κολ[υύ]μβηση|πατιν[αά]ζ|formula|μπ[αά]σκετ|β[οό]λε[ιϊ])(?:\\W)?",Qt::CaseInsensitive),
241  m_grCategMusic("(?:\\W)?(μουσικ[οόηή]|eurovision|τραγο[υύ]δι)(?:\\W)?",Qt::CaseInsensitive),
242  m_grCategReality("(?:\\W)?(ρι[αά]λιτι|reality)(?:\\W)?",Qt::CaseInsensitive),
243  m_grCategReligion("(?:\\W)?(θρησκε[ιί]α|θρησκευτικ|να[οό][σς]?|θε[ιί]α λειτουργ[ιί]α)(?:\\W)?",Qt::CaseInsensitive),
244  m_grCategCulture("(?:\\W)?(τ[εέ]χν(η|ε[σς])|πολιτισμ)(?:\\W)?",Qt::CaseInsensitive),
245  m_grCategNature("(?:\\W)?(φ[υύ]ση|περιβ[αά]λλο|κατασκευ|επιστ[ηή]μ(?!ονικ[ηή]ς φαντασ[ιί]ας))(?:\\W)?",Qt::CaseInsensitive),
246  m_grCategSciFi("(?:\\W)?(επιστ(.|ημονικ[ηή]ς)\\s?φαντασ[ιί]ας)(?:\\W)?",Qt::CaseInsensitive),
247  m_grCategHealth("(?:\\W)?(υγε[ιί]α|υγειιν|ιατρικ|διατροφ)(?:\\W)?",Qt::CaseInsensitive),
248  m_grCategSpecial("(?:\\W)?(αφι[εέ]ρωμα)(?:\\W)?",Qt::CaseInsensitive),
249  m_unitymediaImdbrating(R"(\s*IMDb Rating: (\d\.\d)\s?/10$)")
250 {
251 }
252 
253 void EITFixUp::Fix(DBEventEIT &event) const
254 {
255  if (event.m_fixup)
256  {
257  if (event.m_subtitle == event.m_title)
258  event.m_subtitle = QString("");
259 
260  if (event.m_description.isEmpty() && !event.m_subtitle.isEmpty())
261  {
262  event.m_description = event.m_subtitle;
263  event.m_subtitle = QString("");
264  }
265  }
266 
267  if (kFixHTML & event.m_fixup)
268  FixStripHTML(event);
269 
270  if (kFixHDTV & event.m_fixup)
271  event.m_videoProps |= VID_HDTV;
272 
273  if (kFixBell & event.m_fixup)
274  FixBellExpressVu(event);
275 
276  if (kFixDish & event.m_fixup)
277  FixBellExpressVu(event);
278 
279  if (kFixUK & event.m_fixup)
280  FixUK(event);
281 
282  if (kFixPBS & event.m_fixup)
283  FixPBS(event);
284 
285  if (kFixComHem & event.m_fixup)
286  FixComHem(event, (kFixSubtitle & event.m_fixup) != 0U);
287 
288  if (kFixAUStar & event.m_fixup)
289  FixAUStar(event);
290 
291  if (kFixAUDescription & event.m_fixup)
292  FixAUDescription(event);
293 
294  if (kFixAUFreeview & event.m_fixup)
295  FixAUFreeview(event);
296 
297  if (kFixAUNine & event.m_fixup)
298  FixAUNine(event);
299 
300  if (kFixAUSeven & event.m_fixup)
301  FixAUSeven(event);
302 
303  if (kFixMCA & event.m_fixup)
304  FixMCA(event);
305 
306  if (kFixRTL & event.m_fixup)
307  FixRTL(event);
308 
309  if (kFixP7S1 & event.m_fixup)
310  FixPRO7(event);
311 
312  if (kFixATV & event.m_fixup)
313  FixATV(event);
314 
315  if (kFixDisneyChannel & event.m_fixup)
316  FixDisneyChannel(event);
317 
318  if (kFixFI & event.m_fixup)
319  FixFI(event);
320 
321  if (kFixPremiere & event.m_fixup)
322  FixPremiere(event);
323 
324  if (kFixNL & event.m_fixup)
325  FixNL(event);
326 
327  if (kFixNO & event.m_fixup)
328  FixNO(event);
329 
330  if (kFixNRK_DVBT & event.m_fixup)
331  FixNRK_DVBT(event);
332 
333  if (kFixDK & event.m_fixup)
334  FixDK(event);
335 
336  if (kFixCategory & event.m_fixup)
337  FixCategory(event);
338 
339  if (kFixGreekSubtitle & event.m_fixup)
340  FixGreekSubtitle(event);
341 
342  if (kFixGreekEIT & event.m_fixup)
343  FixGreekEIT(event);
344 
345  if (kFixGreekCategories & event.m_fixup)
346  FixGreekCategories(event);
347 
348  if (kFixUnitymedia & event.m_fixup)
349  FixUnitymedia(event);
350 
351  if (event.m_fixup)
352  {
353  if (!event.m_title.isEmpty())
354  {
355  event.m_title = event.m_title.replace(QChar('\0'), "");
356  event.m_title = event.m_title.trimmed();
357  }
358 
359  if (!event.m_subtitle.isEmpty())
360  {
361  event.m_subtitle = event.m_subtitle.replace(QChar('\0'), "");
362  event.m_subtitle = event.m_subtitle.trimmed();
363  }
364 
365  if (!event.m_description.isEmpty())
366  {
367  event.m_description = event.m_description.replace(QChar('\0'), "");
368  event.m_description = event.m_description.trimmed();
369  }
370  }
371 
372  if (kFixGenericDVB & event.m_fixup)
373  {
374  event.m_programId = AddDVBEITAuthority(event.m_chanid, event.m_programId);
375  event.m_seriesId = AddDVBEITAuthority(event.m_chanid, event.m_seriesId);
376  }
377 
378  // Are any items left unhandled? report them to allow fixups improvements
379  if (!event.m_items.empty())
380  {
381  for (auto i = event.m_items.begin(); i != event.m_items.end(); ++i)
382  {
383  LOG(VB_EIT, LOG_DEBUG, QString("Unhandled item in EIT for"
384  " channel id \"%1\", \"%2\": %3").arg(event.m_chanid)
385  .arg(i.key()).arg(i.value()));
386  }
387  }
388 }
389 
405 QString EITFixUp::AddDVBEITAuthority(uint chanid, const QString &id)
406 {
407  if (id.isEmpty())
408  return id;
409 
410  // CRIDs are not case sensitive, so change all to lower case
411  QString crid = id.toLower();
412 
413  // remove "crid://"
414  if (crid.startsWith("crid://"))
415  crid.remove(0,7);
416 
417  // if id is a CRID with authority, return it
418  if (crid.length() >= 1 && crid[0] != '/')
419  return crid;
420 
421  QString authority = ChannelUtil::GetDefaultAuthority(chanid);
422  if (authority.isEmpty())
423  return ""; // no authority, not a valid CRID, return empty
424 
425  return authority + crid;
426 }
427 
433 {
434  // A 0x0D character is present between the content
435  // and the subtitle if its present
436  int position = event.m_description.indexOf(0x0D);
437 
438  if (position != -1)
439  {
440  // Subtitle present in the title, so get
441  // it and adjust the description
442  event.m_subtitle = event.m_description.left(position);
443  event.m_description = event.m_description.right(
444  event.m_description.length() - position - 2);
445  }
446 
447  // Take out the content description which is
448  // always next with a period after it
449  position = event.m_description.indexOf(".");
450  // Make sure they didn't leave it out and
451  // you come up with an odd category
452  if (position < 10)
453  {
454  }
455  else
456  {
457  event.m_category = "Unknown";
458  }
459 
460  // If the content descriptor didn't come up with anything, try parsing the category
461  // out of the description.
462  if (event.m_category.isEmpty())
463  {
464  // Take out the content description which is
465  // always next with a period after it
466  position = event.m_description.indexOf(".");
467  if ((position + 1) < event.m_description.length())
468  position = event.m_description.indexOf(". ");
469  // Make sure they didn't leave it out and
470  // you come up with an odd category
471  if ((position > -1) && position < 20)
472  {
473  const QString stmp = event.m_description;
474  event.m_description = stmp.right(stmp.length() - position - 2);
475  event.m_category = stmp.left(position);
476 
477  int position_p = event.m_category.indexOf("(");
478  if (position_p == -1)
479  event.m_description = stmp.right(stmp.length() - position - 2);
480  else
481  event.m_category = "Unknown";
482  }
483  else
484  {
485  event.m_category = "Unknown";
486  }
487 
488  // When a channel is off air the category is "-"
489  // so leave the category as blank
490  if (event.m_category == "-")
491  event.m_category = "OffAir";
492 
493  if (event.m_category.length() > 20)
494  event.m_category = "Unknown";
495  }
496  else if (event.m_categoryType)
497  {
498  QString theme = dish_theme_type_to_string(event.m_categoryType);
499  event.m_description = event.m_description.replace(theme, "");
500  if (event.m_description.startsWith("."))
501  event.m_description = event.m_description.right(event.m_description.length() - 1);
502  if (event.m_description.startsWith(" "))
503  event.m_description = event.m_description.right(event.m_description.length() - 1);
504  }
505 
506  // See if a year is present as (xxxx)
507  position = event.m_description.indexOf(m_bellYear);
508  if (position != -1 && !event.m_category.isEmpty())
509  {
510  // Parse out the year
511  bool ok = false;
512  uint y = event.m_description.mid(position + 1, 4).toUInt(&ok);
513  if (ok)
514  {
515  event.m_originalairdate = QDate(y, 1, 1);
516  event.m_airdate = y;
517  event.m_previouslyshown = true;
518  }
519 
520  // Get the actors if they exist
521  if (position > 3)
522  {
523  QString tmp = event.m_description.left(position-3);
524  QStringList actors =
525  tmp.split(m_bellActors, QString::SkipEmptyParts);
526  for (const auto & actor : qAsConst(actors))
527  event.AddPerson(DBPerson::kActor, actor);
528  }
529  // Remove the year and actors from the description
530  event.m_description = event.m_description.right(
531  event.m_description.length() - position - 7);
532  }
533 
534  // Check for (CC) in the decription and
535  // set the <subtitles type="teletext"> flag
536  position = event.m_description.indexOf("(CC)");
537  if (position != -1)
538  {
539  event.m_subtitleType |= SUB_HARDHEAR;
540  event.m_description = event.m_description.replace("(CC)", "");
541  }
542 
543  // Check for (Stereo) in the decription and set the <audio> tags
544  position = event.m_description.indexOf(m_stereo);
545  if (position != -1)
546  {
547  event.m_audioProps |= AUD_STEREO;
548  event.m_description = event.m_description.replace(m_stereo, "");
549  }
550 
551  // Check for "title (All Day, HD)" in the title
552  position = event.m_title.indexOf(m_bellPPVTitleAllDayHD);
553  if (position != -1)
554  {
555  event.m_title = event.m_title.replace(m_bellPPVTitleAllDayHD, "");
556  event.m_videoProps |= VID_HDTV;
557  }
558 
559  // Check for "title (All Day)" in the title
560  position = event.m_title.indexOf(m_bellPPVTitleAllDay);
561  if (position != -1)
562  {
563  event.m_title = event.m_title.replace(m_bellPPVTitleAllDay, "");
564  }
565 
566  // Check for "HD - title" in the title
567  position = event.m_title.indexOf(m_bellPPVTitleHD);
568  if (position != -1)
569  {
570  event.m_title = event.m_title.replace(m_bellPPVTitleHD, "");
571  event.m_videoProps |= VID_HDTV;
572  }
573 
574  // Check for (HD) in the decription
575  position = event.m_description.indexOf("(HD)");
576  if (position != -1)
577  {
578  event.m_description = event.m_description.replace("(HD)", "");
579  event.m_videoProps |= VID_HDTV;
580  }
581 
582  // Check for (HD) in the title
583  position = event.m_title.indexOf("(HD)");
584  if (position != -1)
585  {
586  event.m_description = event.m_title.replace("(HD)", "");
587  event.m_videoProps |= VID_HDTV;
588  }
589 
590  // Check for HD at the end of the title
591  position = event.m_title.indexOf(m_dishPPVTitleHD);
592  if (position != -1)
593  {
594  event.m_title = event.m_title.replace(m_dishPPVTitleHD, "");
595  event.m_videoProps |= VID_HDTV;
596  }
597 
598  // Check for (DD) at the end of the description
599  position = event.m_description.indexOf("(DD)");
600  if (position != -1)
601  {
602  event.m_description = event.m_description.replace("(DD)", "");
603  event.m_audioProps |= AUD_DOLBY;
604  event.m_audioProps |= AUD_STEREO;
605  }
606 
607  // Remove SAP from Dish descriptions
608  position = event.m_description.indexOf("(SAP)");
609  if (position != -1)
610  {
611  event.m_description = event.m_description.replace("(SAP", "");
612  event.m_subtitleType |= SUB_HARDHEAR;
613  }
614 
615  // Remove any trailing colon in title
616  position = event.m_title.indexOf(m_dishPPVTitleColon);
617  if (position != -1)
618  {
619  event.m_title = event.m_title.replace(m_dishPPVTitleColon, "");
620  }
621 
622  // Remove New at the end of the description
623  position = event.m_description.indexOf(m_dishDescriptionNew);
624  if (position != -1)
625  {
626  event.m_previouslyshown = false;
627  event.m_description = event.m_description.replace(m_dishDescriptionNew, "");
628  }
629 
630  // Remove Series Finale at the end of the desciption
631  position = event.m_description.indexOf(m_dishDescriptionFinale);
632  if (position != -1)
633  {
634  event.m_previouslyshown = false;
635  event.m_description = event.m_description.replace(m_dishDescriptionFinale, "");
636  }
637 
638  // Remove Series Finale at the end of the desciption
639  position = event.m_description.indexOf(m_dishDescriptionFinale2);
640  if (position != -1)
641  {
642  event.m_previouslyshown = false;
643  event.m_description = event.m_description.replace(m_dishDescriptionFinale2, "");
644  }
645 
646  // Remove Series Premiere at the end of the description
647  position = event.m_description.indexOf(m_dishDescriptionPremiere);
648  if (position != -1)
649  {
650  event.m_previouslyshown = false;
651  event.m_description = event.m_description.replace(m_dishDescriptionPremiere, "");
652  }
653 
654  // Remove Series Premiere at the end of the description
655  position = event.m_description.indexOf(m_dishDescriptionPremiere2);
656  if (position != -1)
657  {
658  event.m_previouslyshown = false;
659  event.m_description = event.m_description.replace(m_dishDescriptionPremiere2, "");
660  }
661 
662  // Remove Dish's PPV code at the end of the description
663  QRegExp ppvcode = m_dishPPVCode;
664  ppvcode.setCaseSensitivity(Qt::CaseInsensitive);
665  position = event.m_description.indexOf(ppvcode);
666  if (position != -1)
667  {
668  event.m_description = event.m_description.replace(ppvcode, "");
669  }
670 
671  // Remove trailing garbage
672  position = event.m_description.indexOf(m_dishPPVSpacePerenEnd);
673  if (position != -1)
674  {
675  event.m_description = event.m_description.replace(m_dishPPVSpacePerenEnd, "");
676  }
677 
678  // Check for subtitle "All Day (... Eastern)" in the subtitle
679  position = event.m_subtitle.indexOf(m_bellPPVSubtitleAllDay);
680  if (position != -1)
681  {
682  event.m_subtitle = event.m_subtitle.replace(m_bellPPVSubtitleAllDay, "");
683  }
684 
685  // Check for description "(... Eastern)" in the description
686  position = event.m_description.indexOf(m_bellPPVDescriptionAllDay);
687  if (position != -1)
688  {
689  event.m_description = event.m_description.replace(m_bellPPVDescriptionAllDay, "");
690  }
691 
692  // Check for description "(... ET)" in the description
693  position = event.m_description.indexOf(m_bellPPVDescriptionAllDay2);
694  if (position != -1)
695  {
696  event.m_description = event.m_description.replace(m_bellPPVDescriptionAllDay2, "");
697  }
698 
699  // Check for description "(nnnnn)" in the description
700  position = event.m_description.indexOf(m_bellPPVDescriptionEventId);
701  if (position != -1)
702  {
703  event.m_description = event.m_description.replace(m_bellPPVDescriptionEventId, "");
704  }
705 
706 }
707 
712 {
713  QStringList strListColon = event.m_description.split(":");
714  QStringList strListEnd;
715 
716  bool fColon = false;
717  bool fQuotedSubtitle = false;
718  QString strEnd;
719  if (strListColon.count()>1)
720  {
721  bool fDoubleDot = false;
722  bool fSingleDot = true;
723  int nLength = strListColon[0].length();
724 
725  int nPosition1 = event.m_description.indexOf("..");
726  if ((nPosition1 < nLength) && (nPosition1 >= 0))
727  fDoubleDot = true;
728  nPosition1 = event.m_description.indexOf(".");
729  if (nPosition1==-1)
730  fSingleDot = false;
731  if (nPosition1 > nLength)
732  fSingleDot = false;
733  else
734  {
735  QString strTmp = event.m_description.mid(nPosition1+1,
736  nLength-nPosition1);
737 
738  QStringList tmp = strTmp.split(" ");
739  if (((uint) tmp.size()) < kMaxDotToColon)
740  fSingleDot = false;
741  }
742 
743  if (fDoubleDot)
744  {
745  strListEnd = strListColon;
746  fColon = true;
747  }
748  else if (!fSingleDot)
749  {
750  QStringList strListTmp;
751  uint nTitle=0;
752  int nTitleMax=-1;
753  for (int i =0; (i<strListColon.count()) && (nTitleMax==-1);i++)
754  {
755  const QStringList tmp = strListColon[i].split(" ");
756 
757  nTitle += tmp.size();
758 
759  if (nTitle < kMaxToTitle)
760  strListTmp.push_back(strListColon[i]);
761  else
762  nTitleMax=i;
763  }
764  QString strPartial;
765  for (int i=0;i<(nTitleMax-1);i++)
766  strPartial+=strListTmp[i]+":";
767  if (nTitleMax>0)
768  {
769  strPartial+=strListTmp[nTitleMax-1];
770  strListEnd.push_back(strPartial);
771  }
772  for (int i=nTitleMax+1;i<strListColon.count();i++)
773  strListEnd.push_back(strListColon[i]);
774  fColon = true;
775  }
776  }
777  QRegExp tmpQuotedSubtitle = m_ukQuotedSubtitle;
778  if (tmpQuotedSubtitle.indexIn(event.m_description) != -1)
779  {
780  event.m_subtitle = tmpQuotedSubtitle.cap(1);
781  event.m_description.remove(m_ukQuotedSubtitle);
782  fQuotedSubtitle = true;
783  }
784  QStringList strListPeriod;
785  QStringList strListQuestion;
786  QStringList strListExcl;
787  if (!(fColon || fQuotedSubtitle))
788  {
789  strListPeriod = event.m_description.split(".");
790  if (strListPeriod.count() >1)
791  {
792  int nPosition1 = event.m_description.indexOf(".");
793  int nPosition2 = event.m_description.indexOf("..");
794  if ((nPosition1 < nPosition2) || (nPosition2==-1))
795  strListEnd = strListPeriod;
796  }
797 
798  strListQuestion = event.m_description.split("?");
799  strListExcl = event.m_description.split("!");
800  if ((strListQuestion.size() > 1) &&
801  ((uint)strListQuestion.size() <= kMaxQuestionExclamation))
802  {
803  strListEnd = strListQuestion;
804  strEnd = "?";
805  }
806  else if ((strListExcl.size() > 1) &&
807  ((uint)strListExcl.size() <= kMaxQuestionExclamation))
808  {
809  strListEnd = strListExcl;
810  strEnd = "!";
811  }
812  else
813  strEnd.clear();
814  }
815 
816  if (!strListEnd.empty())
817  {
818  QStringList strListSpace = strListEnd[0].split(
819  " ", QString::SkipEmptyParts);
820  if (fColon && ((uint)strListSpace.size() > kMaxToTitle))
821  return;
822  if ((uint)strListSpace.size() > kDotToTitle)
823  return;
824  if (strListSpace.filter(m_ukExclusionFromSubtitle).empty())
825  {
826  event.m_subtitle = strListEnd[0]+strEnd;
827  event.m_subtitle.remove(m_ukSpaceColonStart);
828  event.m_description=
829  event.m_description.mid(strListEnd[0].length()+1);
830  event.m_description.remove(m_ukSpaceColonStart);
831  }
832  }
833 }
834 
835 
839 void EITFixUp::FixUK(DBEventEIT &event) const
840 {
841  QString strFull;
842 
843  bool isMovie = event.m_category.startsWith("Movie",Qt::CaseInsensitive) ||
844  event.m_category.startsWith("Film",Qt::CaseInsensitive);
845  // BBC three case (could add another record here ?)
846  event.m_description = event.m_description.remove(m_ukThen);
847  event.m_description = event.m_description.remove(m_ukNew);
848  event.m_title = event.m_title.remove(m_ukNewTitle);
849 
850  // Removal of Class TV, CBBC and CBeebies etc..
851  event.m_title = event.m_title.remove(m_ukTitleRemove);
852  event.m_description = event.m_description.remove(m_ukDescriptionRemove);
853 
854  // Removal of BBC FOUR and BBC THREE
855  event.m_description = event.m_description.remove(m_ukBBC34);
856 
857  // BBC 7 [Rpt of ...] case.
858  event.m_description = event.m_description.remove(m_ukBBC7rpt);
859 
860  // "All New To 4Music!
861  event.m_description = event.m_description.remove(m_ukAllNew);
862 
863  // Removal of 'Also in HD' text
864  event.m_description = event.m_description.remove(m_ukAlsoInHD);
865 
866  // Remove [AD,S] etc.
867  bool ccMatched = false;
868  QRegExp tmpCC = m_ukCC;
869  int position1 = 0;
870  while ((position1 = tmpCC.indexIn(event.m_description, position1)) != -1)
871  {
872  ccMatched = true;
873  position1 += tmpCC.matchedLength();
874 
875  QStringList tmpCCitems = tmpCC.cap(0).remove("[").remove("]").split(",");
876  if (tmpCCitems.contains("AD"))
878  if (tmpCCitems.contains("HD"))
879  event.m_videoProps |= VID_HDTV;
880  if (tmpCCitems.contains("S"))
881  event.m_subtitleType |= SUB_NORMAL;
882  if (tmpCCitems.contains("SL"))
883  event.m_subtitleType |= SUB_SIGNED;
884  if (tmpCCitems.contains("W"))
885  event.m_videoProps |= VID_WIDESCREEN;
886  }
887 
888  if(ccMatched)
889  event.m_description = event.m_description.remove(m_ukCC);
890 
891  event.m_title = event.m_title.trimmed();
892  event.m_description = event.m_description.trimmed();
893 
894  // Work out the season and episode numbers (if any)
895  // Matching pattern "Season 2 Episode|Ep 3 of 14|3/14" etc
896  bool series = false;
897  QRegExp tmpSeries = m_ukSeries;
898  int position2 = 0;
899  if ((position1 = tmpSeries.indexIn(event.m_title)) != -1
900  || (position2 = tmpSeries.indexIn(event.m_description)) != -1)
901  {
902  if (!tmpSeries.cap(1).isEmpty())
903  {
904  event.m_season = tmpSeries.cap(1).toUInt();
905  series = true;
906  }
907 
908  if (!tmpSeries.cap(2).isEmpty())
909  {
910  event.m_episode = tmpSeries.cap(2).toUInt();
911  series = true;
912  }
913  else if (!tmpSeries.cap(5).isEmpty())
914  {
915  event.m_episode = tmpSeries.cap(5).toUInt();
916  series = true;
917  }
918 
919  if (!tmpSeries.cap(3).isEmpty())
920  {
921  event.m_totalepisodes = tmpSeries.cap(3).toUInt();
922  series = true;
923  }
924  else if (!tmpSeries.cap(6).isEmpty())
925  {
926  event.m_totalepisodes = tmpSeries.cap(6).toUInt();
927  series = true;
928  }
929 
930  // Remove long or short match. Short text doesn't start at position2
931  int form = tmpSeries.cap(4).isEmpty() ? 0 : 4;
932 
933  if (position1 != -1)
934  {
935  LOG(VB_EIT, LOG_DEBUG, QString("Extracted S%1E%2/%3 from title (%4) \"%5\"")
936  .arg(event.m_season).arg(event.m_episode).arg(event.m_totalepisodes)
937  .arg(event.m_title, event.m_description));
938 
939  event.m_title.remove(tmpSeries.cap(form));
940  }
941  else
942  {
943  LOG(VB_EIT, LOG_DEBUG, QString("Extracted S%1E%2/%3 from description (%4) \"%5\"")
944  .arg(event.m_season).arg(event.m_episode).arg(event.m_totalepisodes)
945  .arg(event.m_title, event.m_description));
946 
947  if (position2 == 0)
948  {
949  // Remove from the start of the description.
950  // Otherwise it ends up in the subtitle.
951  event.m_description.remove(tmpSeries.cap(form));
952  }
953  }
954  }
955 
956  if (isMovie)
957  event.m_categoryType = ProgramInfo::kCategoryMovie;
958  else if (series)
959  event.m_categoryType = ProgramInfo::kCategorySeries;
960 
961  // Multi-part episodes, or films (e.g. ITV film split by news)
962  // Matches Part 1, Pt 1/2, Part 1 of 2 etc.
963  QRegExp tmpPart = m_ukPart;
964  if (tmpPart.indexIn(event.m_title) != -1)
965  {
966  event.m_partnumber = tmpPart.cap(1).toUInt();
967  event.m_parttotal = tmpPart.cap(2).toUInt();
968 
969  LOG(VB_EIT, LOG_DEBUG, QString("Extracted Part %1/%2 from title (%3)")
970  .arg(event.m_partnumber).arg(event.m_parttotal).arg(event.m_title));
971 
972  // Remove from the title
973  event.m_title = event.m_title.remove(tmpPart.cap(0));
974  }
975  else if ((position1 = tmpPart.indexIn(event.m_description)) != -1)
976  {
977  event.m_partnumber = tmpPart.cap(1).toUInt();
978  event.m_parttotal = tmpPart.cap(2).toUInt();
979 
980  LOG(VB_EIT, LOG_DEBUG, QString("Extracted Part %1/%2 from description (%3) \"%4\"")
981  .arg(event.m_partnumber).arg(event.m_parttotal)
982  .arg(event.m_title, event.m_description));
983 
984  // Remove from the start of the description.
985  // Otherwise it ends up in the subtitle.
986  if (position1 == 0)
987  {
988  // Retain a single colon (subtitle separator) if we remove any
989  QString sub = tmpPart.cap(0).contains(":") ? ":" : "";
990  event.m_description = event.m_description.replace(tmpPart.cap(0), sub);
991  }
992  }
993 
994  QRegExp tmpStarring = m_ukStarring;
995  if (tmpStarring.indexIn(event.m_description) != -1)
996  {
997  // if we match this we've captured 2 actors and an (optional) airdate
998  event.AddPerson(DBPerson::kActor, tmpStarring.cap(1));
999  event.AddPerson(DBPerson::kActor, tmpStarring.cap(2));
1000  if (tmpStarring.cap(3).length() > 0)
1001  {
1002  bool ok = false;
1003  uint y = tmpStarring.cap(3).toUInt(&ok);
1004  if (ok)
1005  {
1006  event.m_airdate = y;
1007  event.m_originalairdate = QDate(y, 1, 1);
1008  }
1009  }
1010  }
1011 
1012  QRegExp tmp24ep = m_uk24ep;
1013  if (!event.m_title.startsWith("CSI:") && !event.m_title.startsWith("CD:") &&
1014  !event.m_title.contains(m_ukLaONoSplit) &&
1015  !event.m_title.startsWith("Mission: Impossible"))
1016  {
1017  if ((event.m_title.indexOf(m_ukDoubleDotEnd) != -1) &&
1018  (event.m_description.indexOf(m_ukDoubleDotStart) != -1))
1019  {
1020  QString strPart=event.m_title.remove(m_ukDoubleDotEnd)+" ";
1021  strFull = strPart + event.m_description.remove(m_ukDoubleDotStart);
1022  if (isMovie &&
1023  ((position1 = strFull.indexOf(m_ukCEPQ,strPart.length())) != -1))
1024  {
1025  if (strFull[position1] == '!' || strFull[position1] == '?'
1026  || (position1>2 && strFull[position1] == '.' && strFull[position1-2] == '.'))
1027  position1++;
1028  event.m_title = strFull.left(position1);
1029  event.m_description = strFull.mid(position1 + 1);
1030  event.m_description.remove(m_ukSpaceStart);
1031  }
1032  else if ((position1 = strFull.indexOf(m_ukCEPQ)) != -1)
1033  {
1034  if (strFull[position1] == '!' || strFull[position1] == '?'
1035  || (position1>2 && strFull[position1] == '.' && strFull[position1-2] == '.'))
1036  position1++;
1037  event.m_title = strFull.left(position1);
1038  event.m_description = strFull.mid(position1 + 1);
1039  event.m_description.remove(m_ukSpaceStart);
1040  SetUKSubtitle(event);
1041  }
1042  }
1043  else if ((position1 = tmp24ep.indexIn(event.m_description)) != -1)
1044  {
1045  // Special case for episodes of 24.
1046  // -2 from the length cause we don't want ": " on the end
1047  event.m_subtitle = event.m_description.mid(position1,
1048  tmp24ep.cap(0).length() - 2);
1049  event.m_description = event.m_description.remove(tmp24ep.cap(0));
1050  }
1051  else if (event.m_description.indexOf(m_ukTime) == -1)
1052  {
1053  if (!isMovie && (event.m_title.indexOf(m_ukYearColon) < 0))
1054  {
1055  if (((position1 = event.m_title.indexOf(":")) != -1) &&
1056  (event.m_description.indexOf(":") < 0 ))
1057  {
1058  if (event.m_title.mid(position1+1).indexOf(m_ukCompleteDots)==0)
1059  {
1060  SetUKSubtitle(event);
1061  QString strTmp = event.m_title.mid(position1+1);
1062  event.m_title.resize(position1);
1063  event.m_subtitle = strTmp+event.m_subtitle;
1064  }
1065  else if ((uint)position1 < kSubtitleMaxLen)
1066  {
1067  event.m_subtitle = event.m_title.mid(position1 + 1);
1068  event.m_title = event.m_title.left(position1);
1069  }
1070  }
1071  else
1072  SetUKSubtitle(event);
1073  }
1074  }
1075  }
1076 
1077  if (!isMovie && event.m_subtitle.isEmpty() &&
1078  !event.m_title.startsWith("The X-Files"))
1079  {
1080  if ((position1=event.m_description.indexOf(m_ukTime)) != -1)
1081  {
1082  position2 = event.m_description.indexOf(m_ukColonPeriod);
1083  if ((position2>=0) && (position2 < (position1-2)))
1084  SetUKSubtitle(event);
1085  }
1086  else if ((position1=event.m_title.indexOf("-")) != -1)
1087  {
1088  if ((uint)position1 < kSubtitleMaxLen)
1089  {
1090  event.m_subtitle = event.m_title.mid(position1 + 1);
1091  event.m_subtitle.remove(m_ukSpaceColonStart);
1092  event.m_title = event.m_title.left(position1);
1093  }
1094  }
1095  else
1096  SetUKSubtitle(event);
1097  }
1098 
1099  // Work out the year (if any)
1100  QRegExp tmpUKYear = m_ukYear;
1101  if ((position1 = tmpUKYear.indexIn(event.m_description)) != -1)
1102  {
1103  QString stmp = event.m_description;
1104  int itmp = position1 + tmpUKYear.cap(0).length();
1105  event.m_description = stmp.left(position1) + stmp.mid(itmp);
1106  bool ok = false;
1107  uint y = tmpUKYear.cap(1).toUInt(&ok);
1108  if (ok)
1109  {
1110  event.m_airdate = y;
1111  event.m_originalairdate = QDate(y, 1, 1);
1112  }
1113  }
1114 
1115  // Trim leading/trailing '.'
1116  event.m_subtitle.remove(m_ukDotSpaceStart);
1117  if (event.m_subtitle.lastIndexOf("..") != (event.m_subtitle.length()-2))
1118  event.m_subtitle.remove(m_ukDotEnd);
1119 
1120  // Reverse the subtitle and empty description
1121  if (event.m_description.isEmpty() && !event.m_subtitle.isEmpty())
1122  {
1123  event.m_description=event.m_subtitle;
1124  event.m_subtitle.clear();
1125  }
1126 }
1127 
1132 {
1133  /* Used for PBS ATSC Subtitles are separated by a colon */
1134  int position = event.m_description.indexOf(':');
1135  if (position != -1)
1136  {
1137  const QString stmp = event.m_description;
1138  event.m_subtitle = stmp.left(position);
1139  event.m_description = stmp.right(stmp.length() - position - 2);
1140  }
1141 }
1142 
1146 void EITFixUp::FixComHem(DBEventEIT &event, bool process_subtitle) const
1147 {
1148  // Reverse what EITFixUp::Fix() did
1149  if (event.m_subtitle.isEmpty() && !event.m_description.isEmpty())
1150  {
1151  event.m_subtitle = event.m_description;
1152  event.m_description = "";
1153  }
1154 
1155  // Remove subtitle, it contains the category and we already know that
1156  event.m_subtitle = "";
1157 
1158  bool isSeries = false;
1159  // Try to find episode numbers
1160  int pos = 0;
1161  QRegExp tmpSeries1 = m_comHemSeries1;
1162  QRegExp tmpSeries2 = m_comHemSeries2;
1163  if (tmpSeries2.indexIn(event.m_title) != -1)
1164  {
1165  QStringList list = tmpSeries2.capturedTexts();
1166  event.m_partnumber = list[2].toUInt();
1167  event.m_title = event.m_title.replace(list[0],"");
1168  }
1169  else if ((pos = tmpSeries1.indexIn(event.m_description)) != -1)
1170  {
1171  QStringList list = tmpSeries1.capturedTexts();
1172  if (!list[1].isEmpty())
1173  {
1174  event.m_partnumber = list[1].toUInt();
1175  }
1176  if (!list[2].isEmpty())
1177  {
1178  event.m_parttotal = list[2].toUInt();
1179  }
1180 
1181  // Remove the episode numbers, but only if it's not at the begining
1182  // of the description (subtitle code might use it)
1183  if(pos > 0)
1184  event.m_description = event.m_description.replace(list[0],"");
1185  isSeries = true;
1186  }
1187 
1188  // Add partnumber/parttotal to subtitle
1189  // This will be overwritten if we find a better subtitle
1190  if (event.m_partnumber > 0)
1191  {
1192  event.m_subtitle = QString("Del %1").arg(event.m_partnumber);
1193  if (event.m_parttotal > 0)
1194  {
1195  event.m_subtitle += QString(" av %1").arg(event.m_parttotal);
1196  }
1197  }
1198 
1199  // Move subtitle info from title to subtitle
1200  QRegExp tmpTSub = m_comHemTSub;
1201  if (tmpTSub.indexIn(event.m_title) != -1)
1202  {
1203  event.m_subtitle = tmpTSub.cap(1);
1204  event.m_title = event.m_title.replace(tmpTSub.cap(0),"");
1205  }
1206 
1207  // No need to continue without a description.
1208  if (event.m_description.length() <= 0)
1209  return;
1210 
1211  // Try to find country category, year and possibly other information
1212  // from the begining of the description
1213  QRegExp tmpCountry = m_comHemCountry;
1214  pos = tmpCountry.indexIn(event.m_description);
1215  if (pos != -1)
1216  {
1217  QStringList list = tmpCountry.capturedTexts();
1218  QString replacement;
1219 
1220  // Original title, usually english title
1221  // note: list[1] contains extra () around the text that needs removing
1222  if (list[1].length() > 0)
1223  {
1224  replacement = list[1] + " ";
1225  //store it somewhere?
1226  }
1227 
1228  // Countr(y|ies)
1229  if (list[2].length() > 0)
1230  {
1231  replacement += list[2] + " ";
1232  //store it somewhere?
1233  }
1234 
1235  // Category
1236  if (list[3].length() > 0)
1237  {
1238  replacement += list[3] + ".";
1239  if(event.m_category.isEmpty())
1240  {
1241  event.m_category = list[3];
1242  }
1243 
1244  if(list[3].indexOf("serie")!=-1)
1245  {
1246  isSeries = true;
1247  }
1248  }
1249 
1250  // Year
1251  if (list[4].length() > 0)
1252  {
1253  bool ok = false;
1254  uint y = list[4].trimmed().toUInt(&ok);
1255  if (ok)
1256  event.m_airdate = y;
1257  }
1258 
1259  // Actors
1260  if (list[5].length() > 0)
1261  {
1262  const QStringList actors =
1263  list[5].split(m_comHemPersSeparator, QString::SkipEmptyParts);
1264  for (const auto & actor : qAsConst(actors))
1265  event.AddPerson(DBPerson::kActor, actor);
1266  }
1267 
1268  // Remove year and actors.
1269  // The reason category is left in the description is because otherwise
1270  // the country would look wierd like "Amerikansk. Rest of description."
1271  event.m_description = event.m_description.replace(list[0],replacement);
1272  }
1273 
1274  if (isSeries)
1275  event.m_categoryType = ProgramInfo::kCategorySeries;
1276 
1277  // Look for additional persons in the description
1278  QRegExp tmpPersons = m_comHemPersons;
1279  while(pos = tmpPersons.indexIn(event.m_description),pos!=-1)
1280  {
1282  QStringList list = tmpPersons.capturedTexts();
1283 
1284  QRegExp tmpDirector = m_comHemDirector;
1285  QRegExp tmpActor = m_comHemActor;
1286  QRegExp tmpHost = m_comHemHost;
1287  if (tmpDirector.indexIn(list[1])!=-1)
1288  {
1289  role = DBPerson::kDirector;
1290  }
1291  else if(tmpActor.indexIn(list[1])!=-1)
1292  {
1293  role = DBPerson::kActor;
1294  }
1295  else if(tmpHost.indexIn(list[1])!=-1)
1296  {
1297  role = DBPerson::kHost;
1298  }
1299  else
1300  {
1301  event.m_description=event.m_description.replace(list[0],"");
1302  continue;
1303  }
1304 
1305  const QStringList actors =
1306  list[2].split(m_comHemPersSeparator, QString::SkipEmptyParts);
1307  for (const auto & actor : qAsConst(actors))
1308  event.AddPerson(role, actor);
1309 
1310  // Remove it
1311  event.m_description=event.m_description.replace(list[0],"");
1312  }
1313 
1314  // Is this event on a channel we shoud look for a subtitle?
1315  // The subtitle is the first sentence in the description, but the
1316  // subtitle can't be the only thing in the description and it must be
1317  // shorter than 55 characters or we risk picking up the wrong thing.
1318  if (process_subtitle)
1319  {
1320  int pos2 = event.m_description.indexOf(m_comHemSub);
1321  bool pvalid = pos2 != -1 && pos2 <= 55;
1322  if (pvalid && (event.m_description.length() - (pos2 + 2)) > 0)
1323  {
1324  event.m_subtitle = event.m_description.left(
1325  pos2 + (event.m_description[pos2] == '?' ? 1 : 0));
1326  event.m_description = event.m_description.mid(pos2 + 2);
1327  }
1328  }
1329 
1330  // Teletext subtitles?
1331  int position = event.m_description.indexOf(m_comHemTT);
1332  if (position != -1)
1333  {
1334  event.m_subtitleType |= SUB_NORMAL;
1335  }
1336 
1337  // Try to findout if this is a rerun and if so the date.
1338  QRegExp tmpRerun1 = m_comHemRerun1;
1339  if (tmpRerun1.indexIn(event.m_description) == -1)
1340  return;
1341 
1342  // Rerun from today
1343  QStringList list = tmpRerun1.capturedTexts();
1344  if (list[1] == "i dag")
1345  {
1346  event.m_originalairdate = event.m_starttime.date();
1347  return;
1348  }
1349 
1350  // Rerun from yesterday afternoon
1351  if (list[1] == "eftermiddagen")
1352  {
1353  event.m_originalairdate = event.m_starttime.date().addDays(-1);
1354  return;
1355  }
1356 
1357  // Rerun with day, month and possibly year specified
1358  QRegExp tmpRerun2 = m_comHemRerun2;
1359  if (tmpRerun2.indexIn(list[1]) != -1)
1360  {
1361  QStringList datelist = tmpRerun2.capturedTexts();
1362  int day = datelist[1].toInt();
1363  int month = datelist[2].toInt();
1364  //int year;
1365 
1366  //if (datelist[3].length() > 0)
1367  // year = datelist[3].toInt();
1368  //else
1369  // year = event.m_starttime.date().year();
1370 
1371  if (day > 0 && month > 0)
1372  {
1373  QDate date(event.m_starttime.date().year(), month, day);
1374  // it's a rerun so it must be in the past
1375  if (date > event.m_starttime.date())
1376  date = date.addYears(-1);
1377  event.m_originalairdate = date;
1378  }
1379  return;
1380  }
1381 }
1382 
1387 {
1388  event.m_category = event.m_subtitle;
1389  /* Used for DVB-S Subtitles are separated by a colon */
1390  int position = event.m_description.indexOf(':');
1391  if (position != -1)
1392  {
1393  const QString stmp = event.m_description;
1394  event.m_subtitle = stmp.left(position);
1395  event.m_description = stmp.right(stmp.length() - position - 2);
1396  }
1397 }
1398 
1403 {
1404  if (event.m_description.startsWith("[Program data ") || event.m_description.startsWith("[Program info "))//TEN
1405  {
1406  event.m_description = "";//event.m_subtitle;
1407  }
1408  if (event.m_description.endsWith("Copyright West TV Ltd. 2011)"))
1409  event.m_description.resize(event.m_description.length()-40);
1410 
1411  if (event.m_description.isEmpty() && !event.m_subtitle.isEmpty())//due to ten's copyright info, this won't be caught before
1412  {
1413  event.m_description = event.m_subtitle;
1414  event.m_subtitle.clear();
1415  }
1416  if (event.m_description.startsWith(event.m_title+" - "))
1417  event.m_description.remove(0,event.m_title.length()+3);
1418  if (event.m_title.startsWith("LIVE: ", Qt::CaseInsensitive))
1419  {
1420  event.m_title.remove(0, 6);
1421  event.m_description.prepend("(Live) ");
1422  }
1423 }
1428 {
1429  QRegExp rating("\\((G|PG|M|MA)\\)");
1430  if (rating.indexIn(event.m_description) == 0)
1431  {
1432  EventRating prograting;
1433  prograting.m_system="AU"; prograting.m_rating = rating.cap(1);
1434  event.m_ratings.push_back(prograting);
1435  event.m_description.remove(0,rating.matchedLength()+1);
1436  }
1437  if (event.m_description.startsWith("[HD]"))
1438  {
1439  event.m_videoProps |= VID_HDTV;
1440  event.m_description.remove(0,5);
1441  }
1442  if (event.m_description.startsWith("[CC]"))
1443  {
1444  event.m_subtitleType |= SUB_NORMAL;
1445  event.m_description.remove(0,5);
1446  }
1447  if (event.m_subtitle == "Movie")
1448  {
1449  event.m_subtitle.clear();
1450  event.m_categoryType = ProgramInfo::kCategoryMovie;
1451  }
1452  if (event.m_description.startsWith(event.m_title))
1453  event.m_description.remove(0,event.m_title.length()+1);
1454 }
1459 {
1460  if (event.m_description.endsWith(" Rpt"))
1461  {
1462  event.m_previouslyshown = true;
1463  event.m_description.resize(event.m_description.size()-4);
1464  }
1465  QRegExp year("(\\d{4})$");
1466  if (year.indexIn(event.m_description) != -1)
1467  {
1468  event.m_airdate = year.cap(3).toUInt();
1469  event.m_description.resize(event.m_description.size()-5);
1470  }
1471  if (event.m_description.endsWith(" CC"))
1472  {
1473  event.m_subtitleType |= SUB_NORMAL;
1474  event.m_description.resize(event.m_description.size()-3);
1475  }
1476  QString advisories;//store the advisories to append later
1477  QRegExp adv("(\\([A-Z,]+\\))$");
1478  if (adv.indexIn(event.m_description) != -1)
1479  {
1480  advisories = adv.cap(1);
1481  event.m_description.resize(event.m_description.size()-(adv.matchedLength()+1));
1482  }
1483  QRegExp rating("(C|G|PG|M|MA)$");
1484  if (rating.indexIn(event.m_description) != -1)
1485  {
1486  EventRating prograting;
1487  prograting.m_system=""; prograting.m_rating = rating.cap(1);
1488  if (!advisories.isEmpty())
1489  prograting.m_rating.append(" ").append(advisories);
1490  event.m_ratings.push_back(prograting);
1491  event.m_description.resize(event.m_description.size()-(rating.matchedLength()+1));
1492  }
1493 }
1498 {
1499  if (event.m_description.endsWith(".."))//has been truncated to fit within the 'subtitle' eit field, so none of the following will work (ABC)
1500  return;
1501 
1502  if (m_auFreeviewSY.indexIn(event.m_description.trimmed(), 0) != -1)
1503  {
1504  if (event.m_subtitle.isEmpty())//nine sometimes has an actual subtitle field and the brackets thingo)
1505  event.m_subtitle = m_auFreeviewSY.cap(2);
1506  event.m_airdate = m_auFreeviewSY.cap(3).toUInt();
1507  event.m_description = m_auFreeviewSY.cap(1);
1508  }
1509  else if (m_auFreeviewY.indexIn(event.m_description.trimmed(), 0) != -1)
1510  {
1511  event.m_airdate = m_auFreeviewY.cap(2).toUInt();
1512  event.m_description = m_auFreeviewY.cap(1);
1513  }
1514  else if (m_auFreeviewSYC.indexIn(event.m_description.trimmed(), 0) != -1)
1515  {
1516  if (event.m_subtitle.isEmpty())
1517  event.m_subtitle = m_auFreeviewSYC.cap(2);
1518  event.m_airdate = m_auFreeviewSYC.cap(3).toUInt();
1519  QStringList actors = m_auFreeviewSYC.cap(4).split("/");
1520  for (int i = 0; i < actors.size(); ++i)
1521  event.AddPerson(DBPerson::kActor, actors.at(i));
1522  event.m_description = m_auFreeviewSYC.cap(1);
1523  }
1524  else if (m_auFreeviewYC.indexIn(event.m_description.trimmed(), 0) != -1)
1525  {
1526  event.m_airdate = m_auFreeviewYC.cap(2).toUInt();
1527  QStringList actors = m_auFreeviewYC.cap(3).split("/");
1528  for (int i = 0; i < actors.size(); ++i)
1529  event.AddPerson(DBPerson::kActor, actors.at(i));
1530  event.m_description = m_auFreeviewYC.cap(1);
1531  }
1532 }
1533 
1537 void EITFixUp::FixMCA(DBEventEIT &event) const
1538 {
1539  const uint SUBTITLE_PCT = 60; // % of description to allow subtitle to
1540  const uint lSUBTITLE_MAX_LEN = 128;// max length of subtitle field in db.
1541  QRegExp tmpExp1;
1542 
1543  // Remove subtitle, it contains category information too specific to use
1544  event.m_subtitle = QString("");
1545 
1546  // No need to continue without a description.
1547  if (event.m_description.length() <= 0)
1548  return;
1549 
1550  // Replace incomplete title if the full one is in the description
1551  tmpExp1 = m_mcaIncompleteTitle;
1552  if (tmpExp1.indexIn(event.m_title) != -1)
1553  {
1554  tmpExp1 = QRegExp( m_mcaCompleteTitlea.pattern() + tmpExp1.cap(1) +
1555  m_mcaCompleteTitleb.pattern());
1556  tmpExp1.setCaseSensitivity(Qt::CaseInsensitive);
1557  if (tmpExp1.indexIn(event.m_description) != -1)
1558  {
1559  event.m_title = tmpExp1.cap(1).trimmed();
1560  event.m_description = tmpExp1.cap(2).trimmed();
1561  }
1562  tmpExp1.setCaseSensitivity(Qt::CaseSensitive);
1563  }
1564 
1565  // Try to find subtitle in description
1566  tmpExp1 = m_mcaSubtitle;
1567  if (tmpExp1.indexIn(event.m_description) != -1)
1568  {
1569  uint tmpExp1Len = tmpExp1.cap(1).length();
1570  uint evDescLen = max(event.m_description.length(), 1);
1571 
1572  if ((tmpExp1Len < lSUBTITLE_MAX_LEN) &&
1573  ((tmpExp1Len * 100 / evDescLen) < SUBTITLE_PCT))
1574  {
1575  event.m_subtitle = tmpExp1.cap(1);
1576  event.m_description = tmpExp1.cap(2);
1577  }
1578  }
1579 
1580  // Try to find episode numbers in subtitle
1581  tmpExp1 = m_mcaSeries;
1582  if (tmpExp1.indexIn(event.m_subtitle) != -1)
1583  {
1584  uint season = tmpExp1.cap(1).toUInt();
1585  uint episode = tmpExp1.cap(2).toUInt();
1586  event.m_subtitle = tmpExp1.cap(3).trimmed();
1587  event.m_syndicatedepisodenumber =
1588  QString("S%1E%2").arg(season).arg(episode);
1589  event.m_season = season;
1590  event.m_episode = episode;
1591  event.m_categoryType = ProgramInfo::kCategorySeries;
1592  }
1593 
1594  // Close captioned?
1595  int position = event.m_description.indexOf(m_mcaCC);
1596  if (position > 0)
1597  {
1598  event.m_subtitleType |= SUB_HARDHEAR;
1599  event.m_description.replace(m_mcaCC, "");
1600  }
1601 
1602  // Dolby Digital 5.1?
1603  position = event.m_description.indexOf(m_mcaDD);
1604  if ((position > 0) && (position > event.m_description.length() - 7))
1605  {
1606  event.m_audioProps |= AUD_DOLBY;
1607  event.m_description.replace(m_mcaDD, "");
1608  }
1609 
1610  // Remove bouquet tags
1611  event.m_description.replace(m_mcaAvail, "");
1612 
1613  // Try to find year and director from the end of the description
1614  bool isMovie = false;
1615  tmpExp1 = m_mcaCredits;
1616  position = tmpExp1.indexIn(event.m_description);
1617  if (position != -1)
1618  {
1619  isMovie = true;
1620  event.m_description = tmpExp1.cap(1).trimmed();
1621  bool ok = false;
1622  uint y = tmpExp1.cap(2).trimmed().toUInt(&ok);
1623  if (ok)
1624  event.m_airdate = y;
1625  event.AddPerson(DBPerson::kDirector, tmpExp1.cap(3).trimmed());
1626  }
1627  else
1628  {
1629  // Try to find year only from the end of the description
1630  tmpExp1 = m_mcaYear;
1631  position = tmpExp1.indexIn(event.m_description);
1632  if (position != -1)
1633  {
1634  isMovie = true;
1635  event.m_description = tmpExp1.cap(1).trimmed();
1636  bool ok = false;
1637  uint y = tmpExp1.cap(2).trimmed().toUInt(&ok);
1638  if (ok)
1639  event.m_airdate = y;
1640  }
1641  }
1642 
1643  if (isMovie)
1644  {
1645  tmpExp1 = m_mcaActors;
1646  position = tmpExp1.indexIn(event.m_description);
1647  if (position != -1)
1648  {
1649  const QStringList actors = tmpExp1.cap(2).split(
1650  m_mcaActorsSeparator, QString::SkipEmptyParts);
1651  for (const auto & actor : qAsConst(actors))
1652  event.AddPerson(DBPerson::kActor, actor.trimmed());
1653  event.m_description = tmpExp1.cap(1).trimmed();
1654  }
1655  event.m_categoryType = ProgramInfo::kCategoryMovie;
1656  }
1657 
1658 }
1659 
1663 void EITFixUp::FixRTL(DBEventEIT &event) const
1664 {
1665  int pos = 0;
1666 
1667  // No need to continue without a description or with an subtitle.
1668  if (event.m_description.length() <= 0 || event.m_subtitle.length() > 0)
1669  return;
1670 
1671  // Repeat
1672  QRegExp tmpExpRepeat = m_rtlRepeat;
1673  if ((pos = tmpExpRepeat.indexIn(event.m_description)) != -1)
1674  {
1675  // remove '.' if it matches at the beginning of the description
1676  int length = tmpExpRepeat.cap(0).length() + (pos ? 0 : 1);
1677  event.m_description = event.m_description.remove(pos, length).trimmed();
1678  }
1679 
1680  QRegExp tmpExp1 = m_rtlSubtitle;
1681  QRegExp tmpExpSubtitle1 = m_rtlSubtitle1;
1682  tmpExpSubtitle1.setMinimal(true);
1683  QRegExp tmpExpSubtitle2 = m_rtlSubtitle2;
1684  QRegExp tmpExpSubtitle3 = m_rtlSubtitle3;
1685  QRegExp tmpExpSubtitle4 = m_rtlSubtitle4;
1686  QRegExp tmpExpSubtitle5 = m_rtlSubtitle5;
1687  tmpExpSubtitle5.setMinimal(true);
1688  QRegExp tmpExpEpisodeNo1 = m_rtlEpisodeNo1;
1689  QRegExp tmpExpEpisodeNo2 = m_rtlEpisodeNo2;
1690 
1691  // subtitle with episode number: "Folge *: 'subtitle'. description
1692  if (tmpExpSubtitle1.indexIn(event.m_description) != -1)
1693  {
1694  event.m_syndicatedepisodenumber = tmpExpSubtitle1.cap(1);
1695  event.m_subtitle = tmpExpSubtitle1.cap(2);
1696  event.m_description =
1697  event.m_description.remove(0, tmpExpSubtitle1.matchedLength());
1698  }
1699  // episode number subtitle
1700  else if (tmpExpSubtitle2.indexIn(event.m_description) != -1)
1701  {
1702  event.m_syndicatedepisodenumber = tmpExpSubtitle2.cap(1);
1703  event.m_subtitle = tmpExpSubtitle2.cap(2);
1704  event.m_description =
1705  event.m_description.remove(0, tmpExpSubtitle2.matchedLength());
1706  }
1707  // episode number subtitle
1708  else if (tmpExpSubtitle3.indexIn(event.m_description) != -1)
1709  {
1710  event.m_syndicatedepisodenumber = tmpExpSubtitle3.cap(1);
1711  event.m_subtitle = tmpExpSubtitle3.cap(2);
1712  event.m_description =
1713  event.m_description.remove(0, tmpExpSubtitle3.matchedLength());
1714  }
1715  // "Thema..."
1716  else if (tmpExpSubtitle4.indexIn(event.m_description) != -1)
1717  {
1718  event.m_subtitle = tmpExpSubtitle4.cap(1);
1719  event.m_description =
1720  event.m_description.remove(0, tmpExpSubtitle4.matchedLength());
1721  }
1722  // "'...'"
1723  else if (tmpExpSubtitle5.indexIn(event.m_description) != -1)
1724  {
1725  event.m_subtitle = tmpExpSubtitle5.cap(1);
1726  event.m_description =
1727  event.m_description.remove(0, tmpExpSubtitle5.matchedLength());
1728  }
1729  // episode number
1730  else if (tmpExpEpisodeNo1.indexIn(event.m_description) != -1)
1731  {
1732  event.m_syndicatedepisodenumber = tmpExpEpisodeNo1.cap(2);
1733  event.m_subtitle = tmpExpEpisodeNo1.cap(1);
1734  event.m_description =
1735  event.m_description.remove(0, tmpExpEpisodeNo1.matchedLength());
1736  }
1737  // episode number
1738  else if (tmpExpEpisodeNo2.indexIn(event.m_description) != -1)
1739  {
1740  event.m_syndicatedepisodenumber = tmpExpEpisodeNo2.cap(2);
1741  event.m_subtitle = tmpExpEpisodeNo2.cap(1);
1742  event.m_description =
1743  event.m_description.remove(0, tmpExpEpisodeNo2.matchedLength());
1744  }
1745 
1746  /* got an episode title now? (we did not have one at the start of this function) */
1747  if (!event.m_subtitle.isEmpty())
1748  {
1749  event.m_categoryType = ProgramInfo::kCategorySeries;
1750  }
1751 
1752  /* if we do not have an episode title by now try some guessing as last resort */
1753  if (event.m_subtitle.length() == 0)
1754  {
1755  const uint SUBTITLE_PCT = 35; // % of description to allow subtitle up to
1756  const uint lSUBTITLE_MAX_LEN = 50; // max length of subtitle field in db
1757 
1758  if (tmpExp1.indexIn(event.m_description) != -1)
1759  {
1760  uint tmpExp1Len = tmpExp1.cap(1).length();
1761  uint evDescLen = max(event.m_description.length(), 1);
1762 
1763  if ((tmpExp1Len < lSUBTITLE_MAX_LEN) &&
1764  (tmpExp1Len * 100 / evDescLen < SUBTITLE_PCT))
1765  {
1766  event.m_subtitle = tmpExp1.cap(1);
1767  event.m_description = tmpExp1.cap(2);
1768  }
1769  }
1770  }
1771 }
1772 
1776 void EITFixUp::FixPRO7(DBEventEIT &event) const
1777 {
1778  QRegExp tmp = m_pro7Subtitle;
1779 
1780  int pos = tmp.indexIn(event.m_subtitle);
1781  if (pos != -1)
1782  {
1783  if (event.m_airdate == 0)
1784  {
1785  event.m_airdate = tmp.cap(3).toUInt();
1786  }
1787  event.m_subtitle.replace(tmp, "");
1788  }
1789 
1790  /* handle cast, the very last in description */
1791  tmp = m_pro7Cast;
1792  pos = tmp.indexIn(event.m_description);
1793  if (pos != -1)
1794  {
1795  QStringList cast = tmp.cap(1).split("\n");
1796  QRegExp tmpOne = m_pro7CastOne;
1797  QStringListIterator i(cast);
1798  while (i.hasNext())
1799  {
1800  pos = tmpOne.indexIn (i.next());
1801  if (pos != -1)
1802  {
1803  event.AddPerson (DBPerson::kActor, tmpOne.cap(1).simplified());
1804  }
1805  }
1806  event.m_description.replace(tmp, "");
1807  }
1808 
1809  /* handle crew, the new very last in description
1810  * format: "Role: Name" or "Role: Name1, Name2"
1811  */
1812  tmp = m_pro7Crew;
1813  pos = tmp.indexIn(event.m_description);
1814  if (pos != -1)
1815  {
1816  QStringList crew = tmp.cap(1).split("\n");
1817  QRegExp tmpOne = m_pro7CrewOne;
1818  QStringListIterator i(crew);
1819  while (i.hasNext())
1820  {
1821  pos = tmpOne.indexIn (i.next());
1822  if (pos != -1)
1823  {
1825  if (QString::compare (tmpOne.cap(1), "Regie") == 0)
1826  {
1827  role = DBPerson::kDirector;
1828  }
1829  else if ((QString::compare (tmpOne.cap(1), "Drehbuch") == 0) ||
1830  (QString::compare (tmpOne.cap(1), "Autor") == 0))
1831  {
1832  role = DBPerson::kWriter;
1833  }
1834  // FIXME add more jobs
1835 
1836  QStringList names = tmpOne.cap(2).simplified().split("\\s*,\\s*");
1837  QStringListIterator j(names);
1838  while (j.hasNext())
1839  {
1840  event.AddPerson (role, j.next());
1841  }
1842  }
1843  }
1844  event.m_description.replace(tmp, "");
1845  }
1846 
1847  /* FIXME unless its Jamie Oliver, then there is neither Crew nor Cast only
1848  * \n\nKoch: Jamie Oliver
1849  */
1850 }
1851 
1856 {
1857  QRegExp tmp = m_disneyChannelSubtitle;
1858  int pos = tmp.indexIn(event.m_subtitle);
1859  if (pos != -1)
1860  {
1861  if (event.m_airdate == 0)
1862  {
1863  event.m_airdate = tmp.cap(3).toUInt();
1864  }
1865  event.m_subtitle.replace(tmp, "");
1866  }
1867  tmp = QRegExp("\\s[^\\s]+-(Serie)");
1868  pos = tmp.indexIn(event.m_subtitle);
1869  if (pos != -1)
1870  {
1871  event.m_categoryType = ProgramInfo::kCategorySeries;
1872  event.m_category=tmp.cap(0).trimmed();
1873  event.m_subtitle.replace(tmp, "");
1874  }
1875 }
1876 
1880 void EITFixUp::FixATV(DBEventEIT &event) const
1881 {
1882  event.m_subtitle.replace(m_atvSubtitle, "");
1883 }
1884 
1885 
1889 void EITFixUp::FixFI(DBEventEIT &event) const
1890 {
1891  int position = event.m_description.indexOf(m_fiRerun);
1892  if (position != -1)
1893  {
1894  event.m_previouslyshown = true;
1895  event.m_description = event.m_description.replace(m_fiRerun, "");
1896  }
1897 
1898  position = event.m_description.indexOf(m_fiRerun2);
1899  if (position != -1)
1900  {
1901  event.m_previouslyshown = true;
1902  event.m_description = event.m_description.replace(m_fiRerun2, "");
1903  }
1904 
1905  // Check for (Stereo) in the decription and set the <audio> tags
1906  position = event.m_description.indexOf(m_stereo);
1907  if (position != -1)
1908  {
1909  event.m_audioProps |= AUD_STEREO;
1910  event.m_description = event.m_description.replace(m_stereo, "");
1911  }
1912 
1913  // Remove age limit in parenthesis at end of title
1914  position = event.m_title.indexOf(m_fiAgeLimit);
1915  if (position != -1)
1916  {
1917  event.m_title = event.m_title.replace(m_fiAgeLimit, "");
1918  }
1919 
1920  // Remove Film or Elokuva at start of title
1921  position = event.m_title.indexOf(m_fiFilm);
1922  if (position != -1)
1923  {
1924  event.m_title = event.m_title.replace(m_fiFilm, "");
1925  }
1926 
1927 }
1928 
1934 {
1935  QString country = "";
1936 
1937  QRegExp tmplength = m_dePremiereLength;
1938  QRegExp tmpairdate = m_dePremiereAirdate;
1939  QRegExp tmpcredits = m_dePremiereCredits;
1940 
1941  event.m_description = event.m_description.replace(tmplength, "");
1942 
1943  if (tmpairdate.indexIn(event.m_description) != -1)
1944  {
1945  country = tmpairdate.cap(1).trimmed();
1946  bool ok = false;
1947  uint y = tmpairdate.cap(2).toUInt(&ok);
1948  if (ok)
1949  event.m_airdate = y;
1950  event.m_description = event.m_description.replace(tmpairdate, "");
1951  }
1952 
1953  if (tmpcredits.indexIn(event.m_description) != -1)
1954  {
1955  event.AddPerson(DBPerson::kDirector, tmpcredits.cap(1));
1956  const QStringList actors = tmpcredits.cap(2).split(
1957  ", ", QString::SkipEmptyParts);
1958  for (const auto & actor : qAsConst(actors))
1959  event.AddPerson(DBPerson::kActor, actor);
1960  event.m_description = event.m_description.replace(tmpcredits, "");
1961  }
1962 
1963  event.m_description = event.m_description.replace("\u000A$", "");
1964  event.m_description = event.m_description.replace("\u000A", " ");
1965 
1966  // move the original titel from the title to subtitle
1967  QRegExp tmpOTitle = m_dePremiereOTitle;
1968  if (tmpOTitle.indexIn(event.m_title) != -1)
1969  {
1970  event.m_subtitle = QString("%1, %2").arg(tmpOTitle.cap(1)).arg(country);
1971  event.m_title = event.m_title.replace(tmpOTitle, "");
1972  }
1973 
1974  // Find infos about season and episode number
1975  QRegExp tmpSeasonEpisode = m_deSkyDescriptionSeasonEpisode;
1976  if (tmpSeasonEpisode.indexIn(event.m_description) != -1)
1977  {
1978  event.m_season = tmpSeasonEpisode.cap(1).trimmed().toUInt();
1979  event.m_episode = tmpSeasonEpisode.cap(2).trimmed().toUInt();
1980  event.m_description.replace(tmpSeasonEpisode, "");
1981  }
1982 }
1983 
1987 void EITFixUp::FixNL(DBEventEIT &event) const
1988 {
1989  QString fullinfo = "";
1990  fullinfo.append (event.m_subtitle);
1991  fullinfo.append (event.m_description);
1992  event.m_subtitle = "";
1993 
1994  // Convert categories to Dutch categories Myth knows.
1995  // nog invoegen: comedy, sport, misdaad
1996 
1997  if (event.m_category == "Documentary")
1998  {
1999  event.m_category = "Documentaire";
2000  event.m_categoryType = ProgramInfo::kCategoryNone;
2001  }
2002  if (event.m_category == "News")
2003  {
2004  event.m_category = "Nieuws/actualiteiten";
2005  event.m_categoryType = ProgramInfo::kCategoryNone;
2006  }
2007  if (event.m_category == "Kids")
2008  {
2009  event.m_category = "Jeugd";
2010  event.m_categoryType = ProgramInfo::kCategoryNone;
2011  }
2012  if (event.m_category == "Show/game Show")
2013  {
2014  event.m_category = "Amusement";
2015  event.m_categoryType = ProgramInfo::kCategoryTVShow;
2016  }
2017  if (event.m_category == "Music/Ballet/Dance")
2018  {
2019  event.m_category = "Muziek";
2020  event.m_categoryType = ProgramInfo::kCategoryNone;
2021  }
2022  if (event.m_category == "News magazine")
2023  {
2024  event.m_category = "Informatief";
2025  event.m_categoryType = ProgramInfo::kCategoryNone;
2026  }
2027  if (event.m_category == "Movie")
2028  {
2029  event.m_category = "Film";
2030  event.m_categoryType = ProgramInfo::kCategoryMovie;
2031  }
2032  if (event.m_category == "Nature/animals/Environment")
2033  {
2034  event.m_category = "Natuur";
2035  event.m_categoryType = ProgramInfo::kCategoryNone;
2036  }
2037  if (event.m_category == "Movie - Adult")
2038  {
2039  event.m_category = "Erotiek";
2040  event.m_categoryType = ProgramInfo::kCategoryNone;
2041  }
2042  if (event.m_category == "Movie - Soap/melodrama/folkloric")
2043  {
2044  event.m_category = "Serie/soap";
2045  event.m_categoryType = ProgramInfo::kCategorySeries;
2046  }
2047  if (event.m_category == "Arts/Culture")
2048  {
2049  event.m_category = "Kunst/Cultuur";
2050  event.m_categoryType = ProgramInfo::kCategoryNone;
2051  }
2052  if (event.m_category == "Sports")
2053  {
2054  event.m_category = "Sport";
2055  event.m_categoryType = ProgramInfo::kCategorySports;
2056  }
2057  if (event.m_category == "Cartoons/Puppets")
2058  {
2059  event.m_category = "Animatie";
2060  event.m_categoryType = ProgramInfo::kCategoryNone;
2061  }
2062  if (event.m_category == "Movie - Comedy")
2063  {
2064  event.m_category = "Comedy";
2065  event.m_categoryType = ProgramInfo::kCategorySeries;
2066  }
2067  if (event.m_category == "Movie - Detective/Thriller")
2068  {
2069  event.m_category = "Misdaad";
2070  event.m_categoryType = ProgramInfo::kCategoryNone;
2071  }
2072  if (event.m_category == "Social/Spiritual Sciences")
2073  {
2074  event.m_category = "Religieus";
2075  event.m_categoryType = ProgramInfo::kCategoryNone;
2076  }
2077 
2078  // Film - categories are usually not Films
2079  if (event.m_category.startsWith("Film -"))
2080  {
2081  event.m_categoryType = ProgramInfo::kCategorySeries;
2082  }
2083 
2084  // Get stereo info
2085  if (fullinfo.indexOf(m_stereo) != -1)
2086  {
2087  event.m_audioProps |= AUD_STEREO;
2088  fullinfo = fullinfo.replace(m_stereo, ".");
2089  }
2090 
2091  //Get widescreen info
2092  if (fullinfo.indexOf(m_nlWide) != -1)
2093  {
2094  fullinfo = fullinfo.replace("breedbeeld", ".");
2095  }
2096 
2097  // Get repeat info
2098  if (fullinfo.indexOf(m_nlRepeat) != -1)
2099  {
2100  fullinfo = fullinfo.replace("herh.", ".");
2101  }
2102 
2103  // Get teletext subtitle info
2104  if (fullinfo.indexOf(m_nlTxt) != -1)
2105  {
2106  event.m_subtitleType |= SUB_NORMAL;
2107  fullinfo = fullinfo.replace("txt", ".");
2108  }
2109 
2110  // Get HDTV information
2111  if (event.m_title.indexOf(m_nlHD) != -1)
2112  {
2113  event.m_videoProps |= VID_HDTV;
2114  event.m_title = event.m_title.replace(m_nlHD, "");
2115  }
2116 
2117  // Try to make subtitle from Afl.:
2118  QRegExp tmpSub = m_nlSub;
2119  QString tmpSubString;
2120  if (tmpSub.indexIn(fullinfo) != -1)
2121  {
2122  tmpSubString = tmpSub.cap(0);
2123  tmpSubString = tmpSubString.right(tmpSubString.length() - 7);
2124  event.m_subtitle = tmpSubString.left(tmpSubString.length() -1);
2125  fullinfo = fullinfo.replace(tmpSub.cap(0), "");
2126  }
2127 
2128  // Try to make subtitle from " "
2129  QRegExp tmpSub2 = m_nlSub2;
2130  //QString tmpSubString2;
2131  if (tmpSub2.indexIn(fullinfo) != -1)
2132  {
2133  tmpSubString = tmpSub2.cap(0);
2134  tmpSubString = tmpSubString.right(tmpSubString.length() - 2);
2135  event.m_subtitle = tmpSubString.left(tmpSubString.length() -1);
2136  fullinfo = fullinfo.replace(tmpSub2.cap(0), "");
2137  }
2138 
2139 
2140  // This is trying to catch the case where the subtitle is in the main title
2141  // but avoid cases where it isn't a subtitle e.g cd:uk
2142  int position = 0;
2143  if (((position = event.m_title.indexOf(":")) != -1) &&
2144  (event.m_title[position + 1].toUpper() == event.m_title[position + 1]) &&
2145  (event.m_subtitle.isEmpty()))
2146  {
2147  event.m_subtitle = event.m_title.mid(position + 1);
2148  event.m_title = event.m_title.left(position);
2149  }
2150 
2151 
2152  // Get the actors
2153  QRegExp tmpActors = m_nlActors;
2154  if (tmpActors.indexIn(fullinfo) != -1)
2155  {
2156  QString tmpActorsString = tmpActors.cap(0);
2157  tmpActorsString = tmpActorsString.right(tmpActorsString.length() - 6);
2158  tmpActorsString = tmpActorsString.left(tmpActorsString.length() - 5);
2159  const QStringList actors =
2160  tmpActorsString.split(", ", QString::SkipEmptyParts);
2161  for (const auto & actor : qAsConst(actors))
2162  event.AddPerson(DBPerson::kActor, actor);
2163  fullinfo = fullinfo.replace(tmpActors.cap(0), "");
2164  }
2165 
2166  // Try to find presenter
2167  QRegExp tmpPres = m_nlPres;
2168  if (tmpPres.indexIn(fullinfo) != -1)
2169  {
2170  QString tmpPresString = tmpPres.cap(0);
2171  tmpPresString = tmpPresString.right(tmpPresString.length() - 14);
2172  tmpPresString = tmpPresString.left(tmpPresString.length() -1);
2173  const QStringList presenters =
2174  tmpPresString.split(m_nlPersSeparator, QString::SkipEmptyParts);
2175  for (const auto & presenter : qAsConst(presenters))
2176  event.AddPerson(DBPerson::kPresenter, presenter);
2177  fullinfo = fullinfo.replace(tmpPres.cap(0), "");
2178  }
2179 
2180  // Try to find year
2181  QRegExp tmpYear1 = m_nlYear1;
2182  QRegExp tmpYear2 = m_nlYear2;
2183  if (tmpYear1.indexIn(fullinfo) != -1)
2184  {
2185  bool ok = false;
2186  uint y = tmpYear1.cap(0).toUInt(&ok);
2187  if (ok)
2188  event.m_originalairdate = QDate(y, 1, 1);
2189  }
2190 
2191  if (tmpYear2.indexIn(fullinfo) != -1)
2192  {
2193  bool ok = false;
2194  uint y = tmpYear2.cap(2).toUInt(&ok);
2195  if (ok)
2196  event.m_originalairdate = QDate(y, 1, 1);
2197  }
2198 
2199  // Try to find director
2200  QRegExp tmpDirector = m_nlDirector;
2201  QString tmpDirectorString;
2202  if (fullinfo.indexOf(m_nlDirector) != -1)
2203  {
2204  tmpDirectorString = tmpDirector.cap(0);
2205  event.AddPerson(DBPerson::kDirector, tmpDirectorString);
2206  }
2207 
2208  // Strip leftovers
2209  if (fullinfo.indexOf(m_nlRub) != -1)
2210  {
2211  fullinfo = fullinfo.replace(m_nlRub, "");
2212  }
2213 
2214  // Strip category info from description
2215  if (fullinfo.indexOf(m_nlCat) != -1)
2216  {
2217  fullinfo = fullinfo.replace(m_nlCat, "");
2218  }
2219 
2220  // Remove omroep from title
2221  if (event.m_title.indexOf(m_nlOmroep) != -1)
2222  {
2223  event.m_title = event.m_title.replace(m_nlOmroep, "");
2224  }
2225 
2226  // Put information back in description
2227 
2228  event.m_description = fullinfo;
2229  event.m_description = event.m_description.trimmed();
2230  event.m_title = event.m_title.trimmed();
2231  event.m_subtitle = event.m_subtitle.trimmed();
2232 
2233 }
2234 
2236 {
2237  // remove category movie from short events
2239  event.m_starttime.secsTo(event.m_endtime) < kMinMovieDuration)
2240  {
2241  /* default taken from ContentDescriptor::GetMythCategory */
2242  event.m_categoryType = ProgramInfo::kCategoryTVShow;
2243  }
2244 }
2245 
2249 void EITFixUp::FixNO(DBEventEIT &event) const
2250 {
2251  // Check for "title (R)" in the title
2252  int position = event.m_title.indexOf(m_noRerun);
2253  if (position != -1)
2254  {
2255  event.m_previouslyshown = true;
2256  event.m_title = event.m_title.replace(m_noRerun, "");
2257  }
2258  // Check for "subtitle (HD)" in the subtitle
2259  position = event.m_subtitle.indexOf(m_noHD);
2260  if (position != -1)
2261  {
2262  event.m_videoProps |= VID_HDTV;
2263  event.m_subtitle = event.m_subtitle.replace(m_noHD, "");
2264  }
2265  // Check for "description (HD)" in the description
2266  position = event.m_description.indexOf(m_noHD);
2267  if (position != -1)
2268  {
2269  event.m_videoProps |= VID_HDTV;
2270  event.m_description = event.m_description.replace(m_noHD, "");
2271  }
2272 }
2273 
2278 {
2279  QRegExp tmpExp1;
2280  // Check for "title (R)" in the title
2281  if (event.m_title.indexOf(m_noRerun) != -1)
2282  {
2283  event.m_previouslyshown = true;
2284  event.m_title = event.m_title.replace(m_noRerun, "");
2285  }
2286  // Check for "(R)" in the description
2287  if (event.m_description.indexOf(m_noRerun) != -1)
2288  {
2289  event.m_previouslyshown = true;
2290  }
2291  // Move colon separated category from program-titles into description
2292  // Have seen "NRK2s historiekveld: Film: bla-bla"
2293  tmpExp1 = m_noNRKCategories;
2294  while ((tmpExp1.indexIn(event.m_title) != -1) &&
2295  (tmpExp1.cap(2).length() > 1))
2296  {
2297  event.m_title = tmpExp1.cap(2);
2298  event.m_description = "(" + tmpExp1.cap(1) + ") " + event.m_description;
2299  }
2300  // Remove season premiere markings
2301  tmpExp1 = m_noPremiere;
2302  if (tmpExp1.indexIn(event.m_title) >= 3)
2303  {
2304  event.m_title.remove(m_noPremiere);
2305  }
2306  // Try to find colon-delimited subtitle in title, only tested for NRK channels
2307  tmpExp1 = m_noColonSubtitle;
2308  if (!event.m_title.startsWith("CSI:") &&
2309  !event.m_title.startsWith("CD:") &&
2310  !event.m_title.startsWith("Distriktsnyheter: fra"))
2311  {
2312  if (tmpExp1.indexIn(event.m_title) != -1)
2313  {
2314 
2315  if (event.m_subtitle.length() <= 0)
2316  {
2317  event.m_title = tmpExp1.cap(1);
2318  event.m_subtitle = tmpExp1.cap(2);
2319  }
2320  else if (event.m_subtitle == tmpExp1.cap(2))
2321  {
2322  event.m_title = tmpExp1.cap(1);
2323  }
2324  }
2325  }
2326 }
2327 
2331 void EITFixUp::FixDK(DBEventEIT &event) const
2332 {
2333  // Source: YouSee Rules of Operation v1.16
2334  // url: http://yousee.dk/~/media/pdf/CPE/Rules_Operation.ashx
2335  int episode = -1;
2336  int season = -1;
2337  QRegExp tmpRegEx;
2338  // Title search
2339  // episode and part/part total
2340  tmpRegEx = m_dkEpisode;
2341  int position = event.m_title.indexOf(tmpRegEx);
2342  if (position != -1)
2343  {
2344  episode = tmpRegEx.cap(1).toInt();
2345  event.m_partnumber = tmpRegEx.cap(1).toInt();
2346  event.m_title = event.m_title.replace(tmpRegEx, "");
2347  }
2348 
2349  tmpRegEx = m_dkPart;
2350  position = event.m_title.indexOf(tmpRegEx);
2351  if (position != -1)
2352  {
2353  episode = tmpRegEx.cap(1).toInt();
2354  event.m_partnumber = tmpRegEx.cap(1).toInt();
2355  event.m_parttotal = tmpRegEx.cap(2).toInt();
2356  event.m_title = event.m_title.replace(tmpRegEx, "");
2357  }
2358 
2359  // subtitle delimiters
2360  tmpRegEx = m_dkSubtitle1;
2361  position = event.m_title.indexOf(tmpRegEx);
2362  if (position != -1)
2363  {
2364  event.m_title = tmpRegEx.cap(1);
2365  event.m_subtitle = tmpRegEx.cap(2);
2366  }
2367  else
2368  {
2369  tmpRegEx = m_dkSubtitle2;
2370  if(event.m_title.indexOf(tmpRegEx) != -1)
2371  {
2372  event.m_title = tmpRegEx.cap(1);
2373  event.m_subtitle = tmpRegEx.cap(2);
2374  }
2375  }
2376  // Description search
2377  // Season (Sæson [:digit:]+.) => episode = season episode number
2378  // or year (- år [:digit:]+(\\)|:) ) => episode = total episode number
2379  tmpRegEx = m_dkSeason1;
2380  position = event.m_description.indexOf(tmpRegEx);
2381  if (position != -1)
2382  {
2383  season = tmpRegEx.cap(1).toInt();
2384  }
2385  else
2386  {
2387  tmpRegEx = m_dkSeason2;
2388  if(event.m_description.indexOf(tmpRegEx) != -1)
2389  {
2390  season = tmpRegEx.cap(1).toInt();
2391  }
2392  }
2393 
2394  if (episode > 0)
2395  event.m_episode = episode;
2396 
2397  if (season > 0)
2398  event.m_season = season;
2399 
2400  //Feature:
2401  tmpRegEx = m_dkFeatures;
2402  position = event.m_description.indexOf(tmpRegEx);
2403  if (position != -1)
2404  {
2405  QString features = tmpRegEx.cap(1);
2406  event.m_description = event.m_description.replace(tmpRegEx, "");
2407  // 16:9
2408  if (features.indexOf(m_dkWidescreen) != -1)
2409  event.m_videoProps |= VID_WIDESCREEN;
2410  // HDTV
2411  if (features.indexOf(m_dkHD) != -1)
2412  event.m_videoProps |= VID_HDTV;
2413  // Dolby Digital surround
2414  if (features.indexOf(m_dkDolby) != -1)
2415  event.m_audioProps |= AUD_DOLBY;
2416  // surround
2417  if (features.indexOf(m_dkSurround) != -1)
2418  event.m_audioProps |= AUD_SURROUND;
2419  // stereo
2420  if (features.indexOf(m_dkStereo) != -1)
2421  event.m_audioProps |= AUD_STEREO;
2422  // (G)
2423  if (features.indexOf(m_dkReplay) != -1)
2424  event.m_previouslyshown = true;
2425  // TTV
2426  if (features.indexOf(m_dkTxt) != -1)
2427  event.m_subtitleType |= SUB_NORMAL;
2428  }
2429 
2430  // Series and program id
2431  // programid is currently not transmitted
2432  // YouSee doesn't use a default authority but uses the first byte after
2433  // the / to indicate if the seriesid is global unique or unique on the
2434  // service id
2435  if (event.m_seriesId.length() >= 1 && event.m_seriesId[0] == '/')
2436  {
2437  QString newid;
2438  if (event.m_seriesId[1] == '1')
2439  {
2440  newid = QString("%1%2").arg(event.m_chanid).
2441  arg(event.m_seriesId.mid(2,8));
2442  }
2443  else
2444  {
2445  newid = event.m_seriesId.mid(2,8);
2446  }
2447  event.m_seriesId = newid;
2448  }
2449 
2450  if (event.m_programId.length() >= 1 && event.m_programId[0] == '/')
2451  event.m_programId[0]='_';
2452 
2453  // Add season and episode number to subtitle
2454  if (episode > 0)
2455  {
2456  event.m_subtitle = QString("%1 (%2").arg(event.m_subtitle).arg(episode);
2457  if (event.m_parttotal >0)
2458  event.m_subtitle = QString("%1:%2").arg(event.m_subtitle).
2459  arg(event.m_parttotal);
2460  if (season > 0)
2461  {
2462  event.m_season = season;
2463  event.m_episode = episode;
2464  event.m_syndicatedepisodenumber =
2465  QString("S%1E%2").arg(season).arg(episode);
2466  event.m_subtitle = QString("%1 S\xE6son %2").arg(event.m_subtitle).
2467  arg(season);
2468  }
2469  event.m_subtitle = QString("%1)").arg(event.m_subtitle);
2470  }
2471 
2472  // Find actors and director in description
2473  tmpRegEx = m_dkDirector;
2474  bool directorPresent = false;
2475  position = event.m_description.indexOf(tmpRegEx);
2476  if (position != -1)
2477  {
2478  QString tmpDirectorsString = tmpRegEx.cap(1);
2479  const QStringList directors =
2480  tmpDirectorsString.split(m_dkPersonsSeparator, QString::SkipEmptyParts);
2481  for (const auto & director : qAsConst(directors))
2482  {
2483  tmpDirectorsString = director.split(":").last().trimmed().
2484  remove(QRegExp("\\.$"));
2485  if (tmpDirectorsString != "")
2486  event.AddPerson(DBPerson::kDirector, tmpDirectorsString);
2487  }
2488  directorPresent = true;
2489  }
2490 
2491  tmpRegEx = m_dkActors;
2492  position = event.m_description.indexOf(tmpRegEx);
2493  if (position != -1)
2494  {
2495  QString tmpActorsString = tmpRegEx.cap(1);
2496  if (directorPresent)
2497  tmpActorsString = tmpActorsString.replace(m_dkDirector,"");
2498  const QStringList actors =
2499  tmpActorsString.split(m_dkPersonsSeparator, QString::SkipEmptyParts);
2500  for (const auto & actor : qAsConst(actors))
2501  {
2502  tmpActorsString = actor.split(":").last().trimmed().
2503  remove(QRegExp("\\.$"));
2504  if (tmpActorsString != "")
2505  event.AddPerson(DBPerson::kActor, tmpActorsString);
2506  }
2507  }
2508  //find year
2509  tmpRegEx = m_dkYear;
2510  position = event.m_description.indexOf(tmpRegEx);
2511  if (position != -1)
2512  {
2513  bool ok = false;
2514  uint y = tmpRegEx.cap(1).toUInt(&ok);
2515  if (ok)
2516  event.m_originalairdate = QDate(y, 1, 1);
2517  }
2518  // Remove white spaces
2519  event.m_description = event.m_description.trimmed();
2520  event.m_title = event.m_title.trimmed();
2521  event.m_subtitle = event.m_subtitle.trimmed();
2522 }
2523 
2528 {
2529  LOG(VB_EIT, LOG_INFO, QString("Applying html strip to %1").arg(event.m_title));
2530  event.m_title.remove(m_html);
2531 }
2532 
2533 // Moves the subtitle field into the description since it's just used
2534 // as more description field. All the sort-out will happen in the description
2535 // field. Also, sometimes the description is just a repeat of the title. If so,
2536 // we remove it.
2538 {
2539  if (event.m_title == event.m_description)
2540  {
2541  event.m_description = QString("");
2542  }
2543  if (!event.m_subtitle.isEmpty())
2544  {
2545  if (event.m_subtitle.trimmed().right(1) != ".'" )
2546  event.m_subtitle = event.m_subtitle.trimmed() + ".";
2547  event.m_description = event.m_subtitle.trimmed() + QString(" ") + event.m_description;
2548  event.m_subtitle = QString("");
2549  }
2550 }
2551 
2553 {
2554  //Live show
2555  QRegExp tmpRegEx;
2556  int position = event.m_title.indexOf("(Ζ)");
2557  if (position != -1)
2558  {
2559  event.m_title = event.m_title.replace("(Ζ)", "");
2560  event.m_description.prepend("Ζωντανή Μετάδοση. ");
2561  }
2562 
2563  // Greek not previously Shown
2564  position = event.m_title.indexOf(m_grNotPreviouslyShown);
2565  if (position != -1)
2566  {
2567  event.m_previouslyshown = false;
2568  event.m_title = event.m_title.replace(m_grNotPreviouslyShown, "");
2569  }
2570 
2571  // Greek Replay (Ε)
2572  // it might look redundant compared to previous check but at least it helps
2573  // remove the (Ε) From the title.
2574  tmpRegEx = m_grReplay;
2575  if (event.m_title.indexOf(tmpRegEx) != -1)
2576  {
2577  event.m_previouslyshown = true;
2578  event.m_title = event.m_title.replace(tmpRegEx, "");
2579  }
2580 
2581  // Check for (HD) in the decription
2582  position = event.m_description.indexOf("(HD)");
2583  if (position != -1)
2584  {
2585  event.m_description = event.m_description.replace("(HD)", "");
2586  event.m_videoProps |= VID_HDTV;
2587  }
2588 
2589  // Check for (Full HD) in the decription
2590  position = event.m_description.indexOf("(Full HD)");
2591  if (position != -1)
2592  {
2593  event.m_description = event.m_description.replace("(Full HD)", "");
2594  event.m_videoProps |= VID_HDTV;
2595  }
2596 
2597 
2598  tmpRegEx = m_grFixnofullstopActors;
2599  position = event.m_description.indexOf(tmpRegEx);
2600  if (position != -1)
2601  {
2602  event.m_description.insert(position + 1, ".");
2603  }
2604 
2605  // If they forgot the "." at the end of the sentence before the actors/directors begin, let's insert it.
2606  tmpRegEx = m_grFixnofullstopDirectors;
2607  position = event.m_description.indexOf(tmpRegEx);
2608  if (position != -1)
2609  {
2610  event.m_description.insert(position + 1, ".");
2611  }
2612 
2613  // Find actors and director in description
2614  // I am looking for actors first and then for directors/presenters because
2615  // sometimes punctuation is missing and the "Παίζουν:" label is mistaken
2616  // for a director's/presenter's surname (directors/presenters are shown
2617  // before actors in the description field.). So removing the text after
2618  // adding the actors AND THEN looking for dir/pres helps to clear things up.
2619  tmpRegEx = m_grActors;
2620  position = event.m_description.indexOf(tmpRegEx);
2621  if (position != -1)
2622  {
2623  QString tmpActorsString = tmpRegEx.cap(1);
2624  const QStringList actors =
2625  tmpActorsString.split(m_grPeopleSeparator, QString::SkipEmptyParts);
2626  for (const auto & actor : qAsConst(actors))
2627  {
2628  tmpActorsString = actor.split(":").last().trimmed().
2629  remove(QRegExp("\\.$"));
2630  if (tmpActorsString != "")
2631  event.AddPerson(DBPerson::kActor, tmpActorsString);
2632  }
2633  event.m_description.replace(tmpRegEx.cap(0), "");
2634  }
2635  // Director
2636  tmpRegEx = m_grDirector;
2637  position = event.m_description.indexOf(tmpRegEx);
2638  if (position != -1)
2639  {
2640  QString tmpDirectorsString = tmpRegEx.cap(1);
2641  const QStringList directors =
2642  tmpDirectorsString.split(m_grPeopleSeparator, QString::SkipEmptyParts);
2643  for (const auto & director : qAsConst(directors))
2644  {
2645  tmpDirectorsString = director.split(":").last().trimmed().
2646  remove(QRegExp("\\.$"));
2647  if (tmpDirectorsString != "")
2648  {
2649  event.AddPerson(DBPerson::kDirector, tmpDirectorsString);
2650  }
2651  }
2652  event.m_description.replace(tmpRegEx.cap(0), "");
2653  }
2654 
2655  //Try to find presenter
2656  tmpRegEx = m_grPres;
2657  position = event.m_description.indexOf(tmpRegEx);
2658  if (position != -1)
2659  {
2660  QString tmpPresentersString = tmpRegEx.cap(1);
2661  const QStringList presenters =
2662  tmpPresentersString.split(m_grPeopleSeparator, QString::SkipEmptyParts);
2663  for (const auto & presenter : qAsConst(presenters))
2664  {
2665  tmpPresentersString = presenter.split(":").last().trimmed().
2666  remove(QRegExp("\\.$"));
2667  if (tmpPresentersString != "")
2668  {
2669  event.AddPerson(DBPerson::kPresenter, tmpPresentersString);
2670  }
2671  }
2672  event.m_description.replace(tmpRegEx.cap(0), "");
2673  }
2674 
2675  //find year e.g Παραγωγής 1966 ή ΝΤΟΚΙΜΑΝΤΕΡ - 1998 Κατάλληλο για όλους
2676  // Used in Private channels (not 'secret', just not owned by Government!)
2677  tmpRegEx = m_grYear;
2678  position = event.m_description.indexOf(tmpRegEx);
2679  if (position != -1)
2680  {
2681  bool ok = false;
2682  uint y = tmpRegEx.cap(1).toUInt(&ok);
2683  if (ok)
2684  {
2685  event.m_originalairdate = QDate(y, 1, 1);
2686  event.m_description.replace(tmpRegEx, "");
2687  }
2688  }
2689  // Remove white spaces
2690  event.m_description = event.m_description.trimmed();
2691  event.m_title = event.m_title.trimmed();
2692  event.m_subtitle = event.m_subtitle.trimmed();
2693  // Remove " ."
2694  event.m_description = event.m_description.replace(" .",".").trimmed();
2695 
2696  //find country of origin and remove it from description.
2697  tmpRegEx = m_grCountry;
2698  position = event.m_description.indexOf(tmpRegEx);
2699  if (position != -1)
2700  {
2701  event.m_description.replace(tmpRegEx, "");
2702  }
2703 
2704  // Work out the season and episode numbers (if any)
2705  // Matching pattern "Επεισ[όο]διο:?|Επ 3 από 14|3/14" etc
2706  bool series = false;
2707  QRegExp tmpSeries = m_grSeason;
2708  // cap(2) is the season for ΑΒΓΔ
2709  // cap(3) is the season for 1234
2710  int position1 = tmpSeries.indexIn(event.m_title);
2711  int position2 = tmpSeries.indexIn(event.m_description);
2712  if ((position1 != -1) || (position2 != -1))
2713  {
2714  if (!tmpSeries.cap(2).isEmpty()) // we found a letter representing a number
2715  {
2716  //sometimes Nat. TV writes numbers as letters, i.e Α=1, Β=2, Γ=3, etc
2717  //must convert them to numbers.
2718  int tmpinteger = tmpSeries.cap(2).toUInt();
2719  if (tmpinteger < 1)
2720  {
2721  if (tmpSeries.cap(2) == "ΣΤ") // 6, don't ask!
2722  event.m_season = 6;
2723  else
2724  {
2725  QString LettToNumber = "0ΑΒΓΔΕ6ΖΗΘΙΚΛΜΝ";
2726  tmpinteger = LettToNumber.indexOf(tmpSeries.cap(2));
2727  if (tmpinteger != -1)
2728  event.m_season = tmpinteger;
2729  }
2730  }
2731  }
2732  else if (!tmpSeries.cap(3).isEmpty()) //number
2733  {
2734  event.m_season = tmpSeries.cap(3).toUInt();
2735  }
2736  series = true;
2737  if (position1 != -1)
2738  event.m_title.replace(tmpSeries.cap(0),"");
2739  if (position2 != -1)
2740  event.m_description.replace(tmpSeries.cap(0),"");
2741  }
2742  // If Season is in Roman Numerals (I,II,etc)
2743  tmpSeries = m_grSeasonAsRomanNumerals;
2744  if ((position1 = tmpSeries.indexIn(event.m_title)) != -1
2745  || (position2 = tmpSeries.indexIn(event.m_description)) != -1)
2746  {
2747  if (!tmpSeries.isEmpty()) //number
2748  {
2749  // make sure I replace greek Ι with english I
2750  QString romanSeries = tmpSeries.cap(1).replace("Ι","I").toUpper();
2751  if (romanSeries == "I")
2752  event.m_season = 1;
2753  else if (romanSeries == "II")
2754  event.m_season = 2;
2755  else if (romanSeries== "III")
2756  event.m_season = 3;
2757  else if (romanSeries == "IV")
2758  event.m_season = 4;
2759  else if (romanSeries == "V")
2760  event.m_season = 5;
2761  else if (romanSeries== "VI")
2762  event.m_season = 6;
2763  else if (romanSeries == "VII")
2764  event.m_season = 7;
2765  else if (romanSeries == "VIII")
2766  event.m_season = 8;
2767  else if (romanSeries == "IX")
2768  event.m_season = 9;
2769  else if (romanSeries == "X")
2770  event.m_season = 10;
2771  else if (romanSeries == "XI")
2772  event.m_season = 11;
2773  else if (romanSeries == "XII")
2774  event.m_season = 12;
2775  else if (romanSeries == "XII")
2776  event.m_season = 13;
2777  else if (romanSeries == "XIV")
2778  event.m_season = 14;
2779  else if (romanSeries == "XV")
2780  event.m_season = 15;
2781  else if (romanSeries == "XVI")
2782  event.m_season = 16;
2783  else if (romanSeries == "XVII")
2784  event.m_season = 17;
2785  else if (romanSeries == "XIII")
2786  event.m_season = 18;
2787  else if (romanSeries == "XIX")
2788  event.m_season = 19;
2789  else if (romanSeries == "XX")
2790  event.m_season = 20;
2791  }
2792  series = true;
2793  if (position1 != -1)
2794  {
2795  event.m_title.replace(tmpSeries.cap(0),"");
2796  event.m_title = event.m_title.trimmed();
2797  if (event.m_title.right(1) == ",")
2798  event.m_title.chop(1);
2799  }
2800  if (position2 != -1)
2801  {
2802  event.m_description.replace(tmpSeries.cap(0),"");
2803  event.m_description = event.m_description.trimmed();
2804  if (event.m_description.right(1) == ",")
2805  event.m_description.chop(1);
2806  }
2807  }
2808 
2809 
2810  QRegExp tmpEpisode = m_grlongEp;
2811  //tmpEpisode.setMinimal(true);
2812  // cap(1) is the Episode No.
2813  if ((position1 = tmpEpisode.indexIn(event.m_title)) != -1
2814  || (position2 = tmpEpisode.indexIn(event.m_description)) != -1)
2815  {
2816  if (!tmpEpisode.cap(1).isEmpty())
2817  {
2818  event.m_episode = tmpEpisode.cap(1).toUInt();
2819  series = true;
2820  if (position1 != -1)
2821  event.m_title.replace(tmpEpisode.cap(0),"");
2822  if (position2 != -1)
2823  event.m_description.replace(tmpEpisode.cap(0),"");
2824  // Sometimes description omits Season if it's 1. We fix this
2825  if (0 == event.m_season)
2826  event.m_season = 1;
2827  }
2828  }
2829  // Sometimes, especially on greek national tv, they include comments in the
2830  // title, e.g "connection to ert1", "ert archives".
2831  // Because they obscure the real title, I'll isolate and remove them.
2832 
2833  QRegExp tmpComment = m_grCommentsinTitle;
2834  tmpComment.setMinimal(true);
2835  position = event.m_title.indexOf(tmpComment);
2836  if (position != -1)
2837  {
2838  event.m_title.replace(tmpComment.cap(0),"");
2839  }
2840 
2841  // Sometimes the real (mostly English) title of a movie or series is
2842  // enclosed in parentheses in the event title, subtitle or description.
2843  // Since the subtitle has been moved to the description field by
2844  // EITFixUp::FixGreekSubtitle, I will search for it only in the description.
2845  // It will replace the translated one to get better chances of metadata
2846  // retrieval. The old title will be moved in the description.
2847  QRegExp tmptitle = m_grRealTitleinDescription;
2848  tmptitle.setMinimal(true);
2849  position = event.m_description.indexOf(tmptitle);
2850  if (position != -1)
2851  {
2852  event.m_description = event.m_description.replace(tmptitle, "");
2853  if (tmptitle.cap(0) != event.m_title.trimmed())
2854  {
2855  event.m_description = "(" + event.m_title.trimmed() + "). " + event.m_description;
2856  }
2857  event.m_title = tmptitle.cap(1);
2858  // Remove the real title from the description
2859  }
2860  else // search in title
2861  {
2862  tmptitle = m_grRealTitleinTitle;
2863  position = event.m_title.indexOf(tmptitle);
2864  if (position != -1) // found in title instead
2865  {
2866  event.m_title.replace(tmptitle.cap(0),"");
2867  QString tmpTranslTitle = event.m_title;
2868  //QString tmpTranslTitle = event.m_title.replace(tmptitle.cap(0),"");
2869  event.m_title = tmptitle.cap(1);
2870  event.m_description = "(" + tmpTranslTitle.trimmed() + "). " + event.m_description;
2871  }
2872  }
2873 
2874  // Description field: "^Episode: Lion in the cage. (Description follows)"
2875  tmpRegEx = m_grEpisodeAsSubtitle;
2876  position = event.m_description.indexOf(tmpRegEx);
2877  if (position != -1)
2878  {
2879  event.m_subtitle = tmpRegEx.cap(1).trimmed();
2880  event.m_description.replace(tmpRegEx, "");
2881  }
2882  QRegExp m_grMovie("\\bταιν[ιί]α\\b",Qt::CaseInsensitive);
2883  bool isMovie = (event.m_description.indexOf(m_grMovie) !=-1) ;
2884  if (isMovie)
2885  {
2886  event.m_categoryType = ProgramInfo::kCategoryMovie;
2887  }
2888  else if (series)
2889  {
2890  event.m_categoryType = ProgramInfo::kCategorySeries;
2891  }
2892  // just for luck, retrim fields.
2893  event.m_description = event.m_description.trimmed();
2894  event.m_title = event.m_title.trimmed();
2895  event.m_subtitle = event.m_subtitle.trimmed();
2896 
2897 // να σβήσω τα κομμάτια που περισσεύουν από την περιγραφή πχ παραγωγής χχχχ
2898 }
2899 
2901 {
2902  if (event.m_description.indexOf(m_grCategComedy) != -1)
2903  {
2904  event.m_category = "Κωμωδία";
2905  }
2906  else if (event.m_description.indexOf(m_grCategTeleMag) != -1)
2907  {
2908  event.m_category = "Τηλεπεριοδικό";
2909  }
2910  else if (event.m_description.indexOf(m_grCategNature) != -1)
2911  {
2912  event.m_category = "Επιστήμη/Φύση";
2913  }
2914  else if (event.m_description.indexOf(m_grCategHealth) != -1)
2915  {
2916  event.m_category = "Υγεία";
2917  }
2918  else if (event.m_description.indexOf(m_grCategReality) != -1)
2919  {
2920  event.m_category = "Ριάλιτι";
2921  }
2922  else if (event.m_description.indexOf(m_grCategDrama) != -1)
2923  {
2924  event.m_category = "Κοινωνικό";
2925  }
2926  else if (event.m_description.indexOf(m_grCategChildren) != -1)
2927  {
2928  event.m_category = "Παιδικό";
2929  }
2930  else if (event.m_description.indexOf(m_grCategSciFi) != -1)
2931  {
2932  event.m_category = "Επιστ.Φαντασίας";
2933  }
2934  else if ((event.m_description.indexOf(m_grCategFantasy) != -1)
2935  && (event.m_description.indexOf(m_grCategMystery) != -1))
2936  {
2937  event.m_category = "Φαντασίας/Μυστηρίου";
2938  }
2939  else if (event.m_description.indexOf(m_grCategMystery) != -1)
2940  {
2941  event.m_category = "Μυστηρίου";
2942  }
2943  else if (event.m_description.indexOf(m_grCategFantasy) != -1)
2944  {
2945  event.m_category = "Φαντασίας";
2946  }
2947  else if (event.m_description.indexOf(m_grCategHistory) != -1)
2948  {
2949  event.m_category = "Ιστορικό";
2950  }
2951  else if (event.m_description.indexOf(m_grCategTeleShop) != -1
2952  || event.m_title.indexOf(m_grCategTeleShop) != -1)
2953  {
2954  event.m_category = "Τηλεπωλήσεις";
2955  }
2956  else if (event.m_description.indexOf(m_grCategFood) != -1)
2957  {
2958  event.m_category = "Γαστρονομία";
2959  }
2960  else if (event.m_description.indexOf(m_grCategGameShow) != -1
2961  || event.m_title.indexOf(m_grCategGameShow) != -1)
2962  {
2963  event.m_category = "Τηλεπαιχνίδι";
2964  }
2965  else if (event.m_description.indexOf(m_grCategBiography) != -1)
2966  {
2967  event.m_category = "Βιογραφία";
2968  }
2969  else if (event.m_title.indexOf(m_grCategNews) != -1)
2970  {
2971  event.m_category = "Ειδήσεις";
2972  }
2973  else if (event.m_description.indexOf(m_grCategSports) != -1)
2974  {
2975  event.m_category = "Αθλητικά";
2976  }
2977  else if (event.m_description.indexOf(m_grCategMusic) != -1
2978  || event.m_title.indexOf(m_grCategMusic) != -1)
2979  {
2980  event.m_category = "Μουσική";
2981  }
2982  else if (event.m_description.indexOf(m_grCategDocumentary) != -1)
2983  {
2984  event.m_category = "Ντοκιμαντέρ";
2985  }
2986  else if (event.m_description.indexOf(m_grCategReligion) != -1)
2987  {
2988  event.m_category = "Θρησκεία";
2989  }
2990  else if (event.m_description.indexOf(m_grCategCulture) != -1)
2991  {
2992  event.m_category = "Τέχνες/Πολιτισμός";
2993  }
2994  else if (event.m_description.indexOf(m_grCategSpecial) != -1)
2995  {
2996  event.m_category = "Αφιέρωμα";
2997  }
2998 
2999 }
3000 
3002 {
3003  // TODO handle scraping the category and category_type from localized text in the short/long description
3004  // TODO remove short description (stored as episode title) which is just the beginning of the long description (actual description)
3005 
3006  // drop the short description if its copy the start of the long description
3007  if (event.m_description.startsWith (event.m_subtitle))
3008  {
3009  event.m_subtitle = "";
3010  }
3011 
3012  // handle cast and crew in items in the DVB Extended Event Descriptor
3013  // remove handled items from the map, so the left overs can be reported
3014  QMap<QString,QString>::iterator i = event.m_items.begin();
3015  while (i != event.m_items.end())
3016  {
3017  if ((QString::compare (i.key(), "Role Player") == 0) ||
3018  (QString::compare (i.key(), "Performing Artist") == 0))
3019  {
3020  event.AddPerson (DBPerson::kActor, i.value());
3021  i = event.m_items.erase (i);
3022  }
3023  else if (QString::compare (i.key(), "Director") == 0)
3024  {
3025  event.AddPerson (DBPerson::kDirector, i.value());
3026  i = event.m_items.erase (i);
3027  }
3028  else if (QString::compare (i.key(), "Commentary or Commentator") == 0)
3029  {
3030  event.AddPerson (DBPerson::kCommentator, i.value());
3031  i = event.m_items.erase (i);
3032  }
3033  else if (QString::compare (i.key(), "Presenter") == 0)
3034  {
3035  event.AddPerson (DBPerson::kPresenter, i.value());
3036  i = event.m_items.erase (i);
3037  }
3038  else if (QString::compare (i.key(), "Producer") == 0)
3039  {
3040  event.AddPerson (DBPerson::kProducer, i.value());
3041  i = event.m_items.erase (i);
3042  }
3043  else if (QString::compare (i.key(), "Scriptwriter") == 0)
3044  {
3045  event.AddPerson (DBPerson::kWriter, i.value());
3046  i = event.m_items.erase (i);
3047  }
3048  else
3049  {
3050  ++i;
3051  }
3052  }
3053 
3054  // handle star rating in the description
3055  QRegExp tmp = m_unitymediaImdbrating;
3056  if (event.m_description.indexOf (tmp) != -1)
3057  {
3058  float stars = tmp.cap(1).toFloat();
3059  event.m_stars = stars / 10.0F;
3060  event.m_description.replace (m_unitymediaImdbrating, "");
3061  }
3062 }
const QRegExp m_mcaDD
Definition: eitfixup.h:196
const QRegExp m_grCountry
Definition: eitfixup.h:275
const QRegExp m_auFreeviewYC
Definition: eitfixup.h:263
void FixComHem(DBEventEIT &event, bool process_subtitle) const
Use this to standardize ComHem DVB-C service in Sweden.
Definition: eitfixup.cpp:1146
QDateTime m_endtime
Definition: programdata.h:139
const QRegExp m_grSeason
Definition: eitfixup.h:278
QString m_description
Definition: programdata.h:136
const QRegExp m_noHD
Definition: eitfixup.h:238
const QRegExp m_comHemRerun2
Definition: eitfixup.h:177
const QRegExp m_bellPPVDescriptionEventId
Definition: eitfixup.h:132
const QRegExp m_dkWidescreen
Definition: eitfixup.h:250
const QRegExp m_dishPPVTitleColon
Definition: eitfixup.h:134
const QRegExp m_dePremiereCredits
Definition: eitfixup.h:219
const QString longEp
Definition: eitfixup.cpp:25
const QRegExp m_dishPPVSpacePerenEnd
Definition: eitfixup.h:135
const QRegExp m_dishPPVCode
Definition: eitfixup.h:141
const QRegExp m_pro7CastOne
Definition: eitfixup.h:208
const QRegExp m_ukYearColon
Definition: eitfixup.h:165
QString dish_theme_type_to_string(uint theme_type)
uint16_t m_airdate
movie year / production year
Definition: programdata.h:140
const QRegExp m_dishDescriptionPremiere2
Definition: eitfixup.h:140
const QRegExp m_comHemSeries1
Definition: eitfixup.h:182
const QRegExp m_dkDirector
Definition: eitfixup.h:259
static const uint kMaxQuestionExclamation
Definition: eitfixup.h:23
QString m_category
Definition: programdata.h:137
void FixGreekEIT(DBEventEIT &event) const
Definition: eitfixup.cpp:2552
void FixNRK_DVBT(DBEventEIT &event) const
Use this to clean DVB-T guide in Norway (NRK)
Definition: eitfixup.cpp:2277
const QRegExp m_mcaSeries
Definition: eitfixup.h:189
const QRegExp m_noNRKCategories
Definition: eitfixup.h:240
const QRegExp m_grCategDrama
Definition: eitfixup.h:286
void FixGreekCategories(DBEventEIT &event) const
Definition: eitfixup.cpp:2900
const QRegExp m_dkPersonsSeparator
Definition: eitfixup.h:258
const QRegExp m_ukDotEnd
Definition: eitfixup.h:149
const QRegExp m_dkSurround
Definition: eitfixup.h:252
const QRegExp m_mcaIncompleteTitle
Definition: eitfixup.h:185
void FixPremiere(DBEventEIT &event) const
Use this to standardize DVB-C guide in Germany for the providers Kabel Deutschland and Premiere.
Definition: eitfixup.cpp:1933
const QRegExp m_bellPPVTitleAllDay
Definition: eitfixup.h:127
void FixAUFreeview(DBEventEIT &event) const
Use this to standardize DVB-T guide in Australia.
Definition: eitfixup.cpp:1497
const QRegExp m_dkSeason1
Definition: eitfixup.h:247
const QRegExp m_grCategHealth
Definition: eitfixup.h:305
const QRegExp m_dkSubtitle1
Definition: eitfixup.h:245
const QRegExp m_dkSeason2
Definition: eitfixup.h:248
QString m_title
Definition: programdata.h:134
const QString seasonStr
Definition: eitfixup.cpp:21
const QRegExp m_dkDolby
Definition: eitfixup.h:251
QString m_system
Definition: programdata.h:68
void FixUK(DBEventEIT &event) const
Use this in the United Kingdom to standardize DVB-T guide.
Definition: eitfixup.cpp:839
const QRegExp m_noPremiere
Definition: eitfixup.h:241
static const int kMinMovieDuration
Definition: eitfixup.h:27
const QRegExp m_ukSeries
Definition: eitfixup.h:153
const QRegExp m_ukSpaceStart
Definition: eitfixup.h:151
const QRegExp m_ukYear
Definition: eitfixup.h:155
const QRegExp m_grPeopleSeparator
Definition: eitfixup.h:271
const QRegExp m_grCategSpecial
Definition: eitfixup.h:306
const QRegExp m_mcaCredits
Definition: eitfixup.h:190
const QRegExp m_comHemSeries2
Definition: eitfixup.h:183
void AddPerson(DBPerson::Role role, const QString &name)
const QRegExp m_ukAlsoInHD
Definition: eitfixup.h:145
const QRegExp m_html
Definition: eitfixup.h:265
const QRegExp m_mcaCC
Definition: eitfixup.h:195
static const uint kDotToTitle
Definition: eitfixup.h:21
const QRegExp m_dishDescriptionFinale2
Definition: eitfixup.h:138
void FixUnitymedia(DBEventEIT &event) const
Definition: eitfixup.cpp:3001
const QString shortContext
Definition: eitfixup.cpp:44
const QRegExp m_pro7CrewOne
Definition: eitfixup.h:206
const QRegExp m_rtlSubtitle2
Definition: eitfixup.h:200
void FixBellExpressVu(DBEventEIT &event) const
Use this for the Canadian BellExpressVu to standardize DVB-S guide.
Definition: eitfixup.cpp:432
static const uint kMaxToTitle
Definition: eitfixup.h:19
const QRegExp m_fiRerun2
Definition: eitfixup.h:214
static guint32 * tmp
Definition: goom_core.cpp:30
const QRegExp m_ukDoubleDotEnd
Definition: eitfixup.h:161
const QRegExp m_bellPPVTitleHD
Definition: eitfixup.h:128
const QRegExp m_pro7Subtitle
Definition: eitfixup.h:204
QString m_subtitle
Definition: programdata.h:135
const QRegExp m_ukCC
Definition: eitfixup.h:154
const QRegExp m_dkSubtitle2
Definition: eitfixup.h:246
uint m_season
Definition: programdata.h:158
const QRegExp m_ukSpaceColonStart
Definition: eitfixup.h:150
const QRegExp m_grYear
Definition: eitfixup.h:274
const QRegExp m_unitymediaImdbrating
IMDb Rating.
Definition: eitfixup.h:307
const QRegExp m_grCategSports
Definition: eitfixup.h:298
const QRegExp m_mcaCompleteTitleb
Definition: eitfixup.h:187
const QRegExp m_grNotPreviouslyShown
Definition: eitfixup.h:283
const QRegExp m_pro7Crew
Definition: eitfixup.h:205
const QRegExp m_ukQuotedSubtitle
Definition: eitfixup.h:168
bool m_previouslyshown
Definition: programdata.h:154
const QString longSeasEp
Definition: eitfixup.cpp:29
const QRegExp m_ukPart
Definition: eitfixup.h:152
const QRegExp m_mcaYear
Definition: eitfixup.h:194
static const uint kSubtitleMaxLen
Definition: eitfixup.h:17
const QRegExp m_nlOmroep
Definition: eitfixup.h:236
const QRegExp m_grCategSciFi
Definition: eitfixup.h:304
const QRegExp m_rtlSubtitle1
Definition: eitfixup.h:199
if(query.exec() &&query.next())
const QRegExp m_rtlRepeat
Definition: eitfixup.h:197
const QRegExp m_nlActors
Definition: eitfixup.h:228
const QRegExp m_dkHD
Definition: eitfixup.h:256
const QRegExp m_mcaCompleteTitlea
Definition: eitfixup.h:186
const QRegExp m_comHemDirector
Definition: eitfixup.h:172
const QRegExp m_dkFeatures
Definition: eitfixup.h:249
const QString shortEp
Definition: eitfixup.cpp:37
const QRegExp m_disneyChannelSubtitle
Definition: eitfixup.h:210
const QRegExp m_dkPart
Definition: eitfixup.h:244
const QRegExp m_grCategTeleMag
Definition: eitfixup.h:292
const QRegExp m_ukCompleteDots
Definition: eitfixup.h:167
const QRegExp m_grActors
Definition: eitfixup.h:268
const QRegExp m_auFreeviewSY
Definition: eitfixup.h:261
def rating(profile, smoonURL, gate)
Definition: scan.py:39
const QRegExp m_grFixnofullstopActors
Definition: eitfixup.h:269
const QRegExp m_ukExclusionFromSubtitle
Definition: eitfixup.h:166
const QRegExp m_dePremiereAirdate
Definition: eitfixup.h:218
const QRegExp m_bellPPVDescriptionAllDay2
Definition: eitfixup.h:131
static void FixGreekSubtitle(DBEventEIT &event)
Definition: eitfixup.cpp:2537
const QRegExp m_nlHD
Definition: eitfixup.h:225
void FixNL(DBEventEIT &event) const
Use this to standardize @Home DVB-C guide in the Netherlands.
Definition: eitfixup.cpp:1987
unsigned char m_audioProps
Definition: programdata.h:147
const QRegExp m_dePremiereOTitle
Definition: eitfixup.h:220
const QRegExp m_dkEpisode
Definition: eitfixup.h:243
const QRegExp m_grDirector
Definition: eitfixup.h:272
static const uint kMaxDotToColon
Definition: eitfixup.h:25
unsigned char m_subtitleType
Definition: programdata.h:146
const QRegExp m_nlWide
Definition: eitfixup.h:223
EITFixUp()
Definition: eitfixup.cpp:48
const QRegExp m_comHemSub
Definition: eitfixup.h:175
const QRegExp m_bellYear
Definition: eitfixup.h:124
const QRegExp m_ukNew
Definition: eitfixup.h:143
const QRegExp m_mcaSubtitle
Definition: eitfixup.h:188
const QRegExp m_pro7Cast
Definition: eitfixup.h:207
QDateTime m_starttime
Definition: programdata.h:138
void FixNO(DBEventEIT &event) const
Use this to clean DVB-S guide in Norway.
Definition: eitfixup.cpp:2249
const QRegExp m_mcaAvail
Definition: eitfixup.h:191
const QRegExp m_ukColonPeriod
Definition: eitfixup.h:147
const QRegExp m_rtlEpisodeNo1
Definition: eitfixup.h:211
static void FixAUDescription(DBEventEIT &event)
Use this to standardize DVB-T guide in Australia.
Definition: eitfixup.cpp:1402
void FixDisneyChannel(DBEventEIT &event) const
Use this to standardise the Disney Channel guide in Germany.
Definition: eitfixup.cpp:1855
unsigned int uint
Definition: compat.h:140
const QRegExp m_ukNewTitle
Definition: eitfixup.h:144
const QRegExp m_grCategComedy
Definition: eitfixup.h:287
const QRegExp m_rtlSubtitle5
Definition: eitfixup.h:203
static void FixCategory(DBEventEIT &event)
Definition: eitfixup.cpp:2235
const QRegExp m_comHemTSub
Definition: eitfixup.h:184
const QRegExp m_dkActors
Definition: eitfixup.h:257
const QRegExp m_comHemCountry
Definition: eitfixup.h:171
uint m_episode
Definition: programdata.h:159
const QRegExp m_ukDescriptionRemove
Definition: eitfixup.h:159
const QRegExp m_ukStarring
Definition: eitfixup.h:157
static QString AddDVBEITAuthority(uint chanid, const QString &id)
This adds a DVB EIT default authority to series id or program id if one exists in the DB for that cha...
Definition: eitfixup.cpp:405
const QRegExp m_ukBBC7rpt
Definition: eitfixup.h:158
void FixRTL(DBEventEIT &event) const
Use this to standardise the RTL group guide in Germany.
Definition: eitfixup.cpp:1663
const QRegExp m_rtlSubtitle4
Definition: eitfixup.h:202
const QRegExp m_mcaActorsSeparator
Definition: eitfixup.h:193
const QRegExp m_mcaActors
Definition: eitfixup.h:192
const QRegExp m_dishDescriptionPremiere
Definition: eitfixup.h:139
const QRegExp m_auFreeviewSYC
Definition: eitfixup.h:264
void FixMCA(DBEventEIT &event) const
Use this to standardise the MultiChoice Africa DVB-S guide.
Definition: eitfixup.cpp:1537
QString m_seriesId
Definition: programdata.h:151
const QRegExp m_dkTxt
Definition: eitfixup.h:255
const QRegExp m_grCategFood
Definition: eitfixup.h:285
const QRegExp m_grCategNature
Definition: eitfixup.h:303
uint m_totalepisodes
Definition: programdata.h:160
const QRegExp m_grCategGameShow
Definition: eitfixup.h:294
const QRegExp m_nlCat
Definition: eitfixup.h:235
unsigned char m_videoProps
Definition: programdata.h:148
const QRegExp m_grCategReality
Definition: eitfixup.h:300
const QRegExp m_dishDescriptionNew
Definition: eitfixup.h:136
const QRegExp m_nlSub
Definition: eitfixup.h:226
static void FixPBS(DBEventEIT &event)
Use this to standardize PBS ATSC guide in the USA.
Definition: eitfixup.cpp:1131
const QRegExp m_dePremiereLength
Definition: eitfixup.h:217
const QRegExp m_bellActors
Definition: eitfixup.h:125
const QRegExp m_deSkyDescriptionSeasonEpisode
Definition: eitfixup.h:221
const QRegExp m_dkReplay
Definition: eitfixup.h:254
const QRegExp m_ukLaONoSplit
Definition: eitfixup.h:170
const QRegExp m_grCategMystery
Definition: eitfixup.h:289
ProgramInfo::CategoryType m_categoryType
Definition: programdata.h:150
const QRegExp m_nlRepeat
Definition: eitfixup.h:224
const QRegExp m_noColonSubtitle
Definition: eitfixup.h:239
const QRegExp m_nlYear2
Definition: eitfixup.h:233
const QRegExp m_ukCEPQ
Definition: eitfixup.h:146
const QRegExp m_comHemRerun1
Definition: eitfixup.h:176
const QRegExp m_ukBBC34
Definition: eitfixup.h:164
const QRegExp m_nlDirector
Definition: eitfixup.h:234
static QString GetDefaultAuthority(uint chanid)
Returns the DVB default authority for the chanid given.
const QRegExp m_rtlSubtitle3
Definition: eitfixup.h:201
const QRegExp m_grCategReligion
Definition: eitfixup.h:301
const QRegExp m_fiRerun
Definition: eitfixup.h:213
const QRegExp m_dishDescriptionFinale
Definition: eitfixup.h:137
const QRegExp m_nlYear1
Definition: eitfixup.h:232
void FixDK(DBEventEIT &event) const
Use this to clean YouSee's DVB-C guide in Denmark.
Definition: eitfixup.cpp:2331
void FixStripHTML(DBEventEIT &event) const
Use this to clean HTML Tags from EIT Data.
Definition: eitfixup.cpp:2527
const QRegExp m_grCategHistory
Definition: eitfixup.h:291
void SetUKSubtitle(DBEventEIT &event) const
Use this in the United Kingdom to standardize DVB-T guide.
Definition: eitfixup.cpp:711
const QRegExp m_bellPPVSubtitleAllDay
Definition: eitfixup.h:129
const QRegExp m_uk24ep
Definition: eitfixup.h:156
void FixATV(DBEventEIT &event) const
Use this to standardise the ATV/ATV2 guide in Germany.
Definition: eitfixup.cpp:1880
const QRegExp m_grReplay
Definition: eitfixup.h:266
const QRegExp m_comHemHost
Definition: eitfixup.h:174
const QRegExp m_dkYear
Definition: eitfixup.h:260
static void FixAUStar(DBEventEIT &event)
Use this to standardize DVB-S guide in Australia.
Definition: eitfixup.cpp:1386
const QRegExp m_dkStereo
Definition: eitfixup.h:253
const QRegExp m_ukTitleRemove
Definition: eitfixup.h:160
static void FixAUNine(DBEventEIT &event)
Use this to standardize DVB-T guide in Australia.
Definition: eitfixup.cpp:1427
const QRegExp m_grCategFantasy
Definition: eitfixup.h:290
const QRegExp m_noRerun
Definition: eitfixup.h:237
const QRegExp m_comHemPersSeparator
Definition: eitfixup.h:179
const QRegExp m_bellPPVTitleAllDayHD
Definition: eitfixup.h:126
FixupValue m_fixup
Definition: programdata.h:208
static void FixAUSeven(DBEventEIT &event)
Use this to standardize DVB-T guide in Australia.
Definition: eitfixup.cpp:1458
const QRegExp m_grFixnofullstopDirectors
Definition: eitfixup.h:270
uint32_t m_chanid
Definition: programdata.h:207
const QRegExp m_rtlSubtitle
Definition: eitfixup.h:198
const QRegExp m_grCategChildren
Definition: eitfixup.h:288
const QRegExp m_nlTxt
Definition: eitfixup.h:222
const QRegExp m_comHemTT
Definition: eitfixup.h:178
const QRegExp m_ukDotSpaceStart
Definition: eitfixup.h:148
const QRegExp m_fiFilm
Definition: eitfixup.h:216
const QString longContext
Definition: eitfixup.cpp:33
void FixPRO7(DBEventEIT &event) const
Use this to standardise the PRO7/Sat1 group guide in Germany.
Definition: eitfixup.cpp:1776
const QRegExp m_grCategTeleShop
Definition: eitfixup.h:293
const QRegExp m_nlSub2
Definition: eitfixup.h:227
const QRegExp m_grCategCulture
Definition: eitfixup.h:302
const QRegExp m_fiAgeLimit
Definition: eitfixup.h:215
const QRegExp m_nlRub
Definition: eitfixup.h:231
const QRegExp m_comHemActor
Definition: eitfixup.h:173
const QRegExp m_ukDoubleDotStart
Definition: eitfixup.h:162
uint16_t m_partnumber
Definition: programdata.h:143
const QRegExp m_ukThen
Definition: eitfixup.h:142
const QRegExp m_bellPPVDescriptionAllDay
Definition: eitfixup.h:130
const QRegExp m_dishPPVTitleHD
Definition: eitfixup.h:133
const QRegExp m_grPres
Definition: eitfixup.h:273
const QRegExp m_ukTime
Definition: eitfixup.h:163
void FixFI(DBEventEIT &event) const
Use this to clean DVB-T guide in Finland.
Definition: eitfixup.cpp:1889
const QRegExp m_nlPres
Definition: eitfixup.h:229
const QRegExp m_auFreeviewY
Definition: eitfixup.h:262
const QRegExp m_grCategNews
Definition: eitfixup.h:297
const QRegExp m_grCategBiography
Definition: eitfixup.h:296
const QRegExp m_ukAllNew
Definition: eitfixup.h:169
const QRegExp m_grCategDocumentary
Definition: eitfixup.h:295
void Fix(DBEventEIT &event) const
Definition: eitfixup.cpp:253
const QRegExp m_nlPersSeparator
Definition: eitfixup.h:230
QString m_rating
Definition: programdata.h:69
uint16_t m_parttotal
Definition: programdata.h:144
const QRegExp m_stereo
Definition: eitfixup.h:242
QString m_programId
Definition: programdata.h:152
const QRegExp m_rtlEpisodeNo2
Definition: eitfixup.h:212
const QRegExp m_grCategMusic
Definition: eitfixup.h:299
const QRegExp m_atvSubtitle
Definition: eitfixup.h:209
QMap< QString, QString > m_items
Definition: programdata.h:209
const QRegExp m_comHemPersons
Definition: eitfixup.h:180
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23