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