6#include <QRegularExpression>
20static const QRegularExpression
kStereo { R
"(\b\(?[sS]tereo\)?\b)" };
22static const QRegularExpression
kDotAtEnd {
"\\.$" };
24static const QMap<QChar,quint16>
r2v = {
25 {
'I' , 1}, {
'V' , 5}, {
'X' , 10}, {
'L' , 50},
26 {
'C' , 100}, {
'D' , 500}, {
'M' , 1000},
36 for (
int i = 0; i < roman.size() - 1; i++)
38 int v1 =
r2v[roman.at(i)];
39 int v2 =
r2v[roman.at(i+1)];
40 result += (v1 >= v2) ? v1 : -v1;
42 return result +
r2v[roman.back()];
51 event.m_subtitle = QString(
"");
55 event.m_description =
event.m_subtitle;
56 event.m_subtitle = QString(
"");
64 event.m_videoProps |= VID_HDTV;
147 static const QRegularExpression emptyParens { R
"(\(\s*\))" };
150 event.m_title.remove(QChar(
'\0')).remove(emptyParens);
151 event.m_title =
event.m_title.simplified();
156 event.m_subtitle.remove(QChar(
'\0'));
157 event.m_subtitle.remove(emptyParens);
158 event.m_subtitle =
event.m_subtitle.simplified();
163 event.m_description.remove(QChar(
'\0'));
164 event.m_description.remove(emptyParens);
165 event.m_description =
event.m_description.simplified();
178 for (
auto i = event.
m_items.begin(); i != event.
m_items.end(); ++i)
180 LOG(VB_EIT, LOG_DEBUG, QString(
"Unhandled item in EIT for"
181 " channel id \"%1\", \"%2\": %3").arg(event.
m_chanid)
182 .arg(i.key(), i.value()));
208 QString crid =
id.toLower();
211 if (crid.startsWith(
"crid://"))
215 if (crid.length() >= 1 && crid[0] !=
'/')
219 if (authority.isEmpty())
222 return authority + crid;
233 int position =
event.m_description.indexOf(
'\r');
239 event.m_subtitle =
event.m_description.left(position);
240 event.m_description =
event.m_description.right(
246 position =
event.m_description.indexOf(
".");
254 event.m_category =
"Unknown";
263 position =
event.m_description.indexOf(
".");
265 position =
event.m_description.indexOf(
". ");
268 if ((position > -1) && position < 20)
270 const QString stmp =
event.m_description;
271 event.m_description = stmp.right(stmp.length() - position - 2);
272 event.m_category = stmp.left(position);
274 int position_p =
event.m_category.indexOf(
"(");
275 if (position_p == -1)
276 event.m_description = stmp.right(stmp.length() - position - 2);
278 event.m_category =
"Unknown";
282 event.m_category =
"Unknown";
288 event.m_category =
"OffAir";
291 event.m_category =
"Unknown";
296 event.m_description =
event.m_description.replace(theme,
"");
298 event.m_description =
event.m_description.right(event.
m_description.length() - 1);
300 event.m_description =
event.m_description.right(event.
m_description.length() - 1);
304 static const QRegularExpression bellYear { R
"(\([0-9]{4}\))" };
305 position = event.m_description.indexOf(bellYear);
306 if (position != -1 && !event.
m_category.isEmpty())
310 uint y =
event.m_description.mid(position + 1, 4).toUInt(&ok);
313 event.m_originalairdate = QDate(y, 1, 1);
315 event.m_previouslyshown =
true;
321 static const QRegularExpression bellActors { R
"(\set\s|,)" };
322 QString tmp = event.m_description.left(position-3);
324 tmp.split(bellActors, Qt::SkipEmptyParts);
328 for (
const auto & actor : std::as_const(actors))
332 event.m_description =
event.m_description.right(
338 position =
event.m_description.indexOf(
"(CC)");
341 event.m_subtitleType |= SUB_HARDHEAR;
342 event.m_description =
event.m_description.replace(
"(CC)",
"");
347 if (match.hasMatch())
349 event.m_audioProps |= AUD_STEREO;
350 event.m_description.remove(match.capturedStart(0),
351 match.capturedLength(0));
355 static const QRegularExpression bellPPVTitleAllDayHD { R
"(\s*\(All Day\, HD\)\s*$)" };
356 match = bellPPVTitleAllDayHD.match(event.m_title);
357 if (match.hasMatch())
359 event.m_title.remove(match.capturedStart(), match.capturedLength());
360 event.m_videoProps |= VID_HDTV;
364 static const QRegularExpression bellPPVTitleAllDay { R
"(\s*\(All Day.*\)\s*$)" };
365 match = bellPPVTitleAllDay.match(event.m_title);
366 if (match.hasMatch())
367 event.m_title.remove(match.capturedStart(), match.capturedLength());
370 static const QRegularExpression bellPPVTitleHD { R
"(^HD\s?-\s?)" };
371 match = bellPPVTitleHD.match(event.m_title);
372 if (match.hasMatch())
374 event.m_title.remove(match.capturedStart(), match.capturedLength());
375 event.m_videoProps |= VID_HDTV;
379 position =
event.m_description.indexOf(
"(HD)");
382 event.m_description =
event.m_description.replace(
"(HD)",
"");
383 event.m_videoProps |= VID_HDTV;
387 position =
event.m_title.indexOf(
"(HD)");
390 event.m_title =
event.m_title.replace(
"(HD)",
"");
391 event.m_videoProps |= VID_HDTV;
395 static const QRegularExpression dishPPVTitleHD { R
"(\sHD\s*$)" };
396 match = dishPPVTitleHD.match(event.m_title);
397 if (match.hasMatch())
399 event.m_title.remove(match.capturedStart(), match.capturedLength());
400 event.m_videoProps |= VID_HDTV;
404 position =
event.m_description.indexOf(
"(DD)");
407 event.m_description =
event.m_description.replace(
"(DD)",
"");
408 event.m_audioProps |= AUD_DOLBY;
409 event.m_audioProps |= AUD_STEREO;
413 position =
event.m_description.indexOf(
"(SAP)");
416 event.m_description =
event.m_description.replace(
"(SAP",
"");
417 event.m_subtitleType |= SUB_HARDHEAR;
421 static const QRegularExpression dishPPVTitleColon { R
"(\:\s*$)" };
422 match = dishPPVTitleColon.match(event.m_title);
423 if (match.hasMatch())
424 event.m_title.remove(match.capturedStart(), match.capturedLength());
427 static const QRegularExpression dishDescriptionNew { R
"(\s*New\.\s*)" };
429 if (match.hasMatch())
431 event.m_previouslyshown =
false;
432 event.m_description.remove(match.capturedStart(), match.capturedLength());
436 static const QRegularExpression dishDescriptionFinale { R
"(\s*(Series|Season)\sFinale\.\s*)" };
438 if (match.hasMatch())
440 event.m_previouslyshown =
false;
441 event.m_description.remove(match.capturedStart(), match.capturedLength());
445 static const QRegularExpression dishDescriptionFinale2 { R
"(\s*Finale\.\s*)" };
447 if (match.hasMatch())
449 event.m_previouslyshown =
false;
450 event.m_description.remove(match.capturedStart(), match.capturedLength());
454 static const QRegularExpression dishDescriptionPremiere { R
"(\s*(Series|Season)\s(Premier|Premiere)\.\s*)" };
456 if (match.hasMatch())
458 event.m_previouslyshown =
false;
459 event.m_description.remove(match.capturedStart(), match.capturedLength());
463 static const QRegularExpression dishDescriptionPremiere2 { R
"(\s*(Premier|Premiere)\.\s*)" };
465 if (match.hasMatch())
467 event.m_previouslyshown =
false;
468 event.m_description.remove(match.capturedStart(), match.capturedLength());
472 static const QRegularExpression ppvcode { R
"(\s*\(([A-Z]|[0-9]){5}\)\s*$)",
473 QRegularExpression::CaseInsensitiveOption };
475 if (match.hasMatch())
476 event.m_description.remove(match.capturedStart(), match.capturedLength());
479 static const QRegularExpression dishPPVSpacePerenEnd { R
"(\s\)\s*$)" };
481 if (match.hasMatch())
482 event.m_description.remove(match.capturedStart(), match.capturedLength());
485 static const QRegularExpression bellPPVSubtitleAllDay { R
"(^All Day \(.*\sEastern\)\s*$)" };
486 match = bellPPVSubtitleAllDay.match(event.m_subtitle);
487 if (match.hasMatch())
488 event.m_subtitle.remove(match.capturedStart(), match.capturedLength());
491 static const QRegularExpression bellPPVDescriptionAllDay { R
"(^\(.*\sEastern\))" };
493 if (match.hasMatch())
494 event.m_description.remove(match.capturedStart(), match.capturedLength());
497 static const QRegularExpression bellPPVDescriptionAllDay2 { R
"(^\([0-9].*am-[0-9].*am\sET\))" };
498 match = bellPPVDescriptionAllDay2.match(event.m_description);
499 if (match.hasMatch())
500 event.m_description.remove(match.capturedStart(), match.capturedLength());
503 static const QRegularExpression bellPPVDescriptionEventId { R
"(\([0-9]{5}\))" };
504 match = bellPPVDescriptionEventId.match(event.m_description);
505 if (match.hasMatch())
506 event.m_description.remove(match.capturedStart(), match.capturedLength());
514 QStringList strListColon =
event.m_description.split(
":");
515 QStringList strListEnd;
518 bool fQuotedSubtitle =
false;
520 if (strListColon.count()>1)
522 bool fDoubleDot =
false;
523 bool fSingleDot =
true;
524 int nLength = strListColon[0].length();
526 int nPosition1 =
event.m_description.indexOf(
"..");
527 if ((nPosition1 < nLength) && (nPosition1 >= 0))
529 nPosition1 =
event.m_description.indexOf(
".");
532 if (nPosition1 > nLength)
538 QString strTmp =
event.m_description.mid(nPosition1+1,
541 QStringList tmp = strTmp.split(
" ");
548 strListEnd = strListColon;
551 else if (!fSingleDot)
553 QStringList strListTmp;
556 for (
int i =0; (i<strListColon.count()) && (nTitleMax==-1);i++)
558 const QStringList tmp = strListColon[i].split(
" ");
560 nTitle += tmp.size();
563 strListTmp.push_back(strListColon[i]);
568 for (
int i=0;i<(nTitleMax-1);i++)
569 strPartial+=strListTmp[i]+
":";
572 strPartial+=strListTmp[nTitleMax-1];
573 strListEnd.push_back(strPartial);
575 for (
int i=nTitleMax+1;i<strListColon.count();i++)
576 strListEnd.push_back(strListColon[i]);
580 static const QRegularExpression ukQuotedSubtitle { R
"(^'([\w\s\-,]+?)\.' )" };
582 if (match.hasMatch())
584 event.m_subtitle = match.captured(1);
585 event.m_description.remove(match.capturedStart(0),
586 match.capturedLength(0));
587 fQuotedSubtitle =
true;
589 QStringList strListPeriod;
590 QStringList strListQuestion;
591 QStringList strListExcl;
592 if (!(fColon || fQuotedSubtitle))
594 strListPeriod =
event.m_description.split(
".");
595 if (strListPeriod.count() >1)
597 int nPosition1 =
event.m_description.indexOf(
".");
598 int nPosition2 =
event.m_description.indexOf(
"..");
599 if ((nPosition1 < nPosition2) || (nPosition2==-1))
600 strListEnd = strListPeriod;
603 strListQuestion =
event.m_description.split(
"?");
604 strListExcl =
event.m_description.split(
"!");
605 if ((strListQuestion.size() > 1) &&
608 strListEnd = strListQuestion;
611 else if ((strListExcl.size() > 1) &&
614 strListEnd = strListExcl;
623 if (!strListEnd.empty())
625 QStringList strListSpace = strListEnd[0].split(
626 " ", Qt::SkipEmptyParts);
631 static const QRegularExpression ukExclusionFromSubtitle {
632 "(starring|stars\\s|drama|seres|sitcom)",
633 QRegularExpression::CaseInsensitiveOption };
634 if (strListSpace.filter(ukExclusionFromSubtitle).empty())
636 event.m_subtitle = strListEnd[0]+strEnd;
639 event.m_description.mid(strListEnd[0].length()+1);
651 static const QRegularExpression uk24ep { R
"(^\d{1,2}:00[ap]m to \d{1,2}:00[ap]m: )" };
652 static const QRegularExpression ukTime { R
"(\d{1,2}[\.:]\d{1,2}\s*(am|pm|))" };
655 bool isMovie =
event.m_category.startsWith(
"Movie",Qt::CaseInsensitive) ||
656 event.m_category.startsWith(
"Film",Qt::CaseInsensitive);
658 static const QRegularExpression ukThen { R
"(\s*?(Then|Followed by) 60 Seconds\.)",
659 QRegularExpression::CaseInsensitiveOption };
660 static const QRegularExpression ukNew { R
"((New\.|\s*?(Brand New|New)\s*?(Series|Episode)\s*?[:\.\-]))",
661 QRegularExpression::CaseInsensitiveOption };
662 static const QRegularExpression ukNewTitle { R
"(^(Brand New|New:)\s*)",
663 QRegularExpression::CaseInsensitiveOption };
664 event.m_description =
event.m_description.remove(ukThen);
665 event.m_description =
event.m_description.remove(ukNew);
666 event.m_title =
event.m_title.remove(ukNewTitle);
669 static const QRegularExpression ukTitleRemove {
"^(?:[tT]4:|Schools\\s*?:)" };
670 static const QRegularExpression ukDescriptionRemove { R
"(^(?:CBBC\s*?\.|CBeebies\s*?\.|Class TV\s*?:|BBC Switch\.))" };
671 event.m_title =
event.m_title.remove(ukTitleRemove);
672 event.m_description =
event.m_description.remove(ukDescriptionRemove);
675 static const QRegularExpression ukBBC34 { R
"(BBC (?:THREE|FOUR) on BBC (?:ONE|TWO)\.)",
676 QRegularExpression::CaseInsensitiveOption };
677 event.m_description =
event.m_description.remove(ukBBC34);
680 static const QRegularExpression ukBBC7rpt { R
"(\[Rptd?[^]]+?\d{1,2}\.\d{1,2}[ap]m\]\.)" };
681 event.m_description =
event.m_description.remove(ukBBC7rpt);
684 static const QRegularExpression ukAllNew { R
"(All New To 4Music!\s?)" };
685 event.m_description =
event.m_description.remove(ukAllNew);
688 static const QRegularExpression ukAlsoInHD { R
"(\s*Also in HD\.)",
689 QRegularExpression::CaseInsensitiveOption };
690 event.m_description =
event.m_description.remove(ukAlsoInHD);
693 static const QRegularExpression ukCC { R
"(\[(?:(AD|SL|S|W|HD),?)+\])" };
695 while (match.hasMatch())
697 QStringList tmpCCitems = match.captured(0).remove(
"[").remove(
"]").split(
",");
698 if (tmpCCitems.contains(
"AD"))
699 event.m_audioProps |= AUD_VISUALIMPAIR;
700 if (tmpCCitems.contains(
"HD"))
701 event.m_videoProps |= VID_HDTV;
702 if (tmpCCitems.contains(
"S"))
703 event.m_subtitleType |= SUB_NORMAL;
704 if (tmpCCitems.contains(
"SL"))
705 event.m_subtitleType |= SUB_SIGNED;
706 if (tmpCCitems.contains(
"W"))
707 event.m_videoProps |= VID_WIDESCREEN;
708 event.m_description.remove(match.capturedStart(0),
709 match.capturedLength(0));
710 match = ukCC.match(event.
m_description, match.capturedStart(0));
713 event.m_title =
event.m_title.trimmed();
714 event.m_description =
event.m_description.trimmed();
720 static const QString seasonStr = R
"(\b(?:Season|Series|S)\s*(\d+)\s*,?)";
727 static const QString longEp = R
"(\b(?:Ep|Episode)\s*(\d+)\s*(?:(?:/|of)\s*(\d*))?)";
731 static const QString longSeasEp = QString(
"\\(?(?:%1)?\\s*%2").arg(seasonStr, longEp);
735 static const QString longContext = QString(R
"(\(*%1\s*\)?\s*\.?)").arg(longSeasEp);
739 static const QString shortEp = R
"((\d+)\s*(?:/|of)\s*(\d+))";
746 static const QString shortContext =
747 QString(R
"((?:^|\.)(\s*\(*\s*%1[\s)]*(?:[).:]|$)))").arg(shortEp);
752 static const QRegularExpression ukSeries {
"(?:" + longContext +
"|" + shortContext +
")",
753 QRegularExpression::CaseInsensitiveOption };
756 bool fromTitle =
true;
757 match = ukSeries.match(event.
m_title);
758 if (!match.hasMatch())
763 if (match.hasMatch())
765 if (!match.captured(1).isEmpty())
767 event.m_season = match.captured(1).toUInt();
771 if (!match.captured(2).isEmpty())
773 event.m_episode = match.captured(2).toUInt();
776 else if (!match.captured(5).isEmpty())
778 event.m_episode = match.captured(5).toUInt();
782 if (!match.captured(3).isEmpty())
784 event.m_totalepisodes = match.captured(3).toUInt();
787 else if (!match.captured(6).isEmpty())
789 event.m_totalepisodes = match.captured(6).toUInt();
794 int form = match.captured(4).isEmpty() ? 0 : 4;
798 LOG(VB_EIT, LOG_DEBUG, QString(
"Extracted S%1E%2/%3 from title (%4) \"%5\"")
802 event.m_title.remove(match.capturedStart(form),
803 match.capturedLength(form));
807 LOG(VB_EIT, LOG_DEBUG, QString(
"Extracted S%1E%2/%3 from description (%4) \"%5\"")
811 if (match.capturedStart(form) == 0)
815 event.m_description.remove(match.capturedStart(form),
816 match.capturedLength(form));
828 static const QRegularExpression ukPart { R
"([-(\:,.]\s*(?:Part|Pt)\s*(\d+)\s*(?:(?:of|/)\s*(\d+))?\s*[-):,.])",
829 QRegularExpression::CaseInsensitiveOption };
830 match = ukPart.match(event.m_title);
832 if (match.hasMatch())
834 event.m_partnumber = match.captured(1).toUInt();
835 event.m_parttotal = match.captured(2).toUInt();
837 LOG(VB_EIT, LOG_DEBUG, QString(
"Extracted Part %1/%2 from title (%3)")
841 event.m_title.remove(match.capturedStart(0),
842 match.capturedLength(0));
844 else if (match2.hasMatch())
846 event.m_partnumber = match2.captured(1).toUInt();
847 event.m_parttotal = match2.captured(2).toUInt();
849 LOG(VB_EIT, LOG_DEBUG, QString(
"Extracted Part %1/%2 from description (%3) \"%4\"")
855 if (match2.capturedStart(0) == 0)
858 QString sub = match2.captured(0).contains(
":") ?
":" :
"";
859 event.m_description =
event.m_description.replace(match2.captured(0), sub);
863 static const QRegularExpression ukStarring { R
"((?:Western\s)?[Ss]tarring ([\w\s\-']+?)[Aa]nd\s([\w\s\-']+?)[\.|,]\s*(\d{4})?(?:\.\s)?)" };
865 if (match.hasMatch())
872 if (match.captured(3).length() > 0)
875 uint y = match.captured(3).toUInt(&ok);
879 event.m_originalairdate = QDate(y, 1, 1);
884 static const QRegularExpression ukLaONoSplit {
"^Law & Order: (?:Criminal Intent|LA|"
885 "Special Victims Unit|Trial by Jury|UK|You the Jury)" };
886 if (!event.
m_title.startsWith(
"CSI:") && !event.
m_title.startsWith(
"CD:") &&
887 !event.
m_title.contains(ukLaONoSplit) &&
888 !event.
m_title.startsWith(
"Mission: Impossible"))
890 static const QRegularExpression ukDoubleDotStart { R
"(^\.\.+)" };
891 static const QRegularExpression ukDoubleDotEnd { R
"(\.\.+$)" };
892 if ((event.
m_title.indexOf(ukDoubleDotEnd) != -1) &&
895 QString strPart=
event.m_title.remove(ukDoubleDotEnd)+
" ";
896 strFull = strPart +
event.m_description.remove(ukDoubleDotStart);
897 static const QRegularExpression ukCEPQ { R
"([:\!\.\?]\s)" };
898 static const QRegularExpression ukSpaceStart {
"^ " };
899 int position1 = strFull.indexOf(ukCEPQ,strPart.length());
900 if (isMovie && (position1 != -1))
902 if (strFull[position1] ==
'!' || strFull[position1] ==
'?'
903 || (position1>2 && strFull[position1] ==
'.' && strFull[position1-2] ==
'.'))
905 event.m_title = strFull.left(position1);
906 event.m_description = strFull.mid(position1 + 1);
907 event.m_description.remove(ukSpaceStart);
911 position1 = strFull.indexOf(ukCEPQ);
914 if (strFull[position1] ==
'!' || strFull[position1] ==
'?'
915 || (position1>2 && strFull[position1] ==
'.' && strFull[position1-2] ==
'.'))
917 event.m_title = strFull.left(position1);
918 event.m_description = strFull.mid(position1 + 1);
919 event.m_description.remove(ukSpaceStart);
927 if (match24.hasMatch())
931 event.m_subtitle =
event.m_description.mid(match24.capturedStart(0),
932 match24.captured(0).length() - 2);
933 event.m_description =
event.m_description.remove(match24.captured(0));
938 static const QRegularExpression ukYearColon { R
"(^[\d]{4}:)" };
939 if (!isMovie && (event.
m_title.indexOf(ukYearColon) < 0))
941 int position1 =
event.m_title.indexOf(
":");
942 if ((position1 != -1) &&
945 static const QRegularExpression ukCompleteDots { R
"(^\.\.+$)" };
946 if (event.
m_title.mid(position1+1).indexOf(ukCompleteDots)==0)
949 QString strTmp =
event.m_title.mid(position1+1);
950 event.m_title.resize(position1);
951 event.m_subtitle = strTmp+
event.m_subtitle;
955 event.m_subtitle =
event.m_title.mid(position1 + 1);
956 event.m_title =
event.m_title.left(position1);
968 !event.
m_title.startsWith(
"The X-Files"))
970 int position1 =
event.m_description.indexOf(ukTime);
973 static const QRegularExpression ukColonPeriod { R
"([:\.])" };
974 int position2 =
event.m_description.indexOf(ukColonPeriod);
975 if ((position2>=0) && (position2 < (position1-2)))
980 position1 =
event.m_title.indexOf(
"-");
985 event.m_subtitle =
event.m_title.mid(position1 + 1);
987 event.m_title =
event.m_title.left(position1);
998 static const QRegularExpression ukYear { R
"([\[\(]([\d]{4})[\)\]])" };
1000 if (match.hasMatch())
1002 event.m_description.remove(match.capturedStart(0),
1003 match.capturedLength(0));
1005 uint y = match.captured(1).toUInt(&ok);
1008 event.m_airdate = y;
1009 event.m_originalairdate = QDate(y, 1, 1);
1014 static const QRegularExpression ukDotSpaceStart { R
"(^\. )" };
1015 static const QRegularExpression ukDotEnd { R
"(\.$)" };
1016 event.m_subtitle.remove(ukDotSpaceStart);
1018 event.m_subtitle.remove(ukDotEnd);
1023 event.m_description=
event.m_subtitle;
1024 event.m_subtitle.clear();
1034 int position =
event.m_description.indexOf(
':');
1037 const QString stmp =
event.m_description;
1038 event.m_subtitle = stmp.left(position);
1039 event.m_description = stmp.right(stmp.length() - position - 2);
1048 static const QRegularExpression comHemPersSeparator { R
"((, |\soch\s))" };
1053 event.m_subtitle =
event.m_description;
1054 event.m_description =
"";
1058 event.m_subtitle =
"";
1060 bool isSeries =
false;
1062 static const QRegularExpression comHemSeries1
1063 { R
"(\s?(?:[dD]el|[eE]pisode)\s([0-9]+)(?:\s?(?:/|:|av)\s?([0-9]+))?\.)" };
1064 static const QRegularExpression comHemSeries2 { R
"(\s?-?\s?([Dd]el\s+([0-9]+)))" };
1066 auto match2 = comHemSeries2.match(event.
m_title);
1067 if (match2.hasMatch())
1069 event.m_partnumber = match2.capturedView(2).toUInt();
1070 event.m_title.remove(match2.capturedStart(), match2.capturedLength());
1072 else if (match.hasMatch())
1074 if (match.capturedStart(1) != -1)
1075 event.m_partnumber = match.capturedView(1).toUInt();
1076 if (match.capturedStart(2) != -1)
1077 event.m_parttotal = match.capturedView(2).toUInt();
1081 if (match.capturedStart() > 0)
1082 event.m_description.remove(match.capturedStart(),
1083 match.capturedLength());
1091 event.m_subtitle = QString(
"Del %1").arg(event.
m_partnumber);
1093 event.m_subtitle += QString(
" av %1").arg(event.
m_parttotal);
1097 static const QRegularExpression comHemTSub { R
"(\s+-\s+([^\-]+))" };
1098 match = comHemTSub.match(event.m_title);
1099 if (match.hasMatch())
1101 event.m_subtitle = match.captured(1);
1102 event.m_title.remove(match.capturedStart(), match.capturedLength());
1111 static const QRegularExpression comHemCountry
1112 { R
"(^(\(.+\))?\s?([^ ]+)\s([^\.0-9]+)\sfrån\s([0-9]{4})(?:\smed\s([^\.]+))?\.?)" };
1114 if (match.hasMatch())
1116 QString replacement;
1120 if (!match.capturedView(1).isEmpty())
1122 replacement = match.captured(1) +
" ";
1127 if (!match.capturedView(2).isEmpty())
1129 replacement += match.captured(2) +
" ";
1134 if (!match.capturedView(3).isEmpty())
1136 replacement += match.captured(3) +
".";
1139 event.m_category = match.captured(3);
1142 if(match.captured(3).indexOf(
"serie")!=-1)
1149 if (!match.capturedView(4).isEmpty())
1152 uint y = match.capturedView(4).trimmed().toUInt(&ok);
1154 event.m_airdate = y;
1158 if (!match.capturedView(5).isEmpty())
1160 const QStringList actors =
1161 match.captured(5).split(comHemPersSeparator, Qt::SkipEmptyParts);
1164 for (
const auto & actor : std::as_const(actors))
1171 event.m_description =
event.m_description.replace(match.captured(0),replacement);
1178 static const QRegularExpression comHemPersons
1179 { R
"(\s?([Rr]egi|[Ss]kådespelare|[Pp]rogramledare|[Ii] rollerna):\s([^\.]+)\.)" };
1181 while (iter.hasNext())
1183 auto pmatch = iter.next();
1186 static const QRegularExpression comHemDirector {
"[Rr]egi" };
1187 static const QRegularExpression comHemActor {
"[Ss]kådespelare|[Ii] rollerna" };
1188 static const QRegularExpression comHemHost {
"[Pp]rogramledare" };
1189#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
1190 auto dmatch = comHemDirector.match(pmatch.capturedView(1));
1191 auto amatch = comHemActor.match(pmatch.capturedView(1));
1192 auto hmatch = comHemHost.match(pmatch.capturedView(1));
1194 auto dmatch = comHemDirector.matchView(pmatch.capturedView(1));
1195 auto amatch = comHemActor.matchView(pmatch.capturedView(1));
1196 auto hmatch = comHemHost.matchView(pmatch.capturedView(1));
1198 if (dmatch.hasMatch())
1202 else if (amatch.hasMatch())
1206 else if (hmatch.hasMatch())
1212 event.m_description.remove(pmatch.capturedStart(), pmatch.capturedLength());
1216 const QStringList actors =
1217 pmatch.captured(2).split(comHemPersSeparator, Qt::SkipEmptyParts);
1220 for (
const auto & actor : std::as_const(actors))
1221 event.AddPerson(role, actor);
1224 event.m_description=
event.m_description.replace(pmatch.captured(0),
"");
1231 if (process_subtitle)
1233 static const QRegularExpression comHemSub { R
"([.\?\!] )" };
1234 int pos2 =
event.m_description.indexOf(comHemSub);
1235 bool pvalid = pos2 != -1 && pos2 <= 55;
1236 if (pvalid && (event.
m_description.length() - (pos2 + 2)) > 0)
1238 event.m_subtitle =
event.m_description.left(
1240 event.m_description =
event.m_description.mid(pos2 + 2);
1245 static const QRegularExpression comHemTT {
"[Tt]ext-[Tt][Vv]" };
1247 event.m_subtitleType |= SUB_NORMAL;
1250 static const QRegularExpression comHemRerun1 { R
"([Rr]epris\sfrån\s([^\.]+)(?:\.|$))" };
1251 static const QRegularExpression comHemRerun2 { R
"(([0-9]+)/([0-9]+)(?:\s-\s([0-9]{4}))?)" };
1253 if (!match.hasMatch())
1257 if (match.captured(1) ==
"i dag")
1259 event.m_originalairdate =
event.m_starttime.date();
1264 if (match.captured(1) ==
"eftermiddagen")
1266 event.m_originalairdate =
event.m_starttime.date().addDays(-1);
1271#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
1272 match2 = comHemRerun2.match(match.capturedView(1));
1274 match2 = comHemRerun2.matchView(match.capturedView(1));
1276 if (match2.hasMatch())
1278 int day = match2.capturedView(1).toInt();
1279 int month = match2.capturedView(2).toInt();
1286 if (day > 0 && month > 0)
1288 QDate date(event.
m_starttime.date().year(), month, day);
1291 date = date.addYears(-1);
1292 event.m_originalairdate = date;
1303 event.m_category =
event.m_subtitle;
1305 int position =
event.m_description.indexOf(
':');
1308 const QString stmp =
event.m_description;
1309 event.m_subtitle = stmp.left(position);
1310 event.m_description = stmp.right(stmp.length() - position - 2);
1321 event.m_description =
"";
1323 if (event.
m_description.endsWith(
"Copyright West TV Ltd. 2011)"))
1324 event.m_description.resize(event.
m_description.length()-40);
1328 event.m_description =
event.m_subtitle;
1329 event.m_subtitle.clear();
1332 event.m_description.remove(0,event.
m_title.length()+3);
1333 if (event.
m_title.startsWith(
"LIVE: ", Qt::CaseInsensitive))
1335 event.m_title.remove(0, 6);
1336 event.m_description.prepend(
"(Live) ");
1345 static const QRegularExpression
rating {
"\\((G|PG|M|MA)\\)" };
1347 if (match.hasMatch())
1351 event.m_ratings.push_back(prograting);
1352 event.m_description.remove(0,match.capturedLength()+1);
1356 event.m_videoProps |= VID_HDTV;
1357 event.m_description.remove(0,5);
1361 event.m_subtitleType |= SUB_NORMAL;
1362 event.m_description.remove(0,5);
1366 event.m_subtitle.clear();
1370 event.m_description.remove(0,event.
m_title.length()+1);
1380 event.m_previouslyshown =
true;
1383 static const QRegularExpression year {
"(\\d{4})$" };
1385 if (match.hasMatch())
1387 event.m_airdate = match.capturedView(1).toUInt();
1392 event.m_subtitleType |= SUB_NORMAL;
1396 static const QRegularExpression adv {
"(\\([A-Z,]+\\))$" };
1398 if (match.hasMatch())
1400 advisories = match.captured(1);
1401 event.m_description.remove(match.capturedStart()-1, match.capturedLength()+1);
1403 static const QRegularExpression
rating {
"(C|G|PG|M|MA)$" };
1405 if (match.hasMatch())
1409 if (!advisories.isEmpty())
1410 prograting.
m_rating.append(
" ").append(advisories);
1411 event.m_ratings.push_back(prograting);
1412 event.m_description.remove(match.capturedStart()-1, match.capturedLength()+1);
1424 event.m_description =
event.m_description.trimmed();
1426 static const QRegularExpression auFreeviewSY { R
"((.*) \((.+)\) \(([12][0-9][0-9][0-9])\)$)" };
1428 if (match.hasMatch())
1431 event.m_subtitle = match.captured(2);
1432 event.m_airdate = match.capturedView(3).toUInt();
1433 event.m_description = match.captured(1);
1436 static const QRegularExpression auFreeviewY {
"(.*) \\(([12][0-9][0-9][0-9])\\)$" };
1438 if (match.hasMatch())
1440 event.m_airdate = match.capturedView(2).toUInt();
1441 event.m_description = match.captured(1);
1444 static const QRegularExpression auFreeviewSYC { R
"((.*) \((.+)\) \(([12][0-9][0-9][0-9])\) \((.+)\)$)" };
1446 if (match.hasMatch())
1449 event.m_subtitle = match.captured(2);
1450 event.m_airdate = match.capturedView(3).toUInt();
1451 QStringList actors = match.captured(4).split(
"/");
1454 for (
const QString& actor : std::as_const(actors))
1456 event.m_description = match.captured(1);
1459 static const QRegularExpression auFreeviewYC { R
"((.*) \(([12][0-9][0-9][0-9])\) \((.+)\)$)" };
1461 if (match.hasMatch())
1463 event.m_airdate = match.capturedView(2).toUInt();
1464 QStringList actors = match.captured(3).split(
"/");
1467 for (
const QString& actor : std::as_const(actors))
1469 event.m_description = match.captured(1);
1478 const uint SUBTITLE_PCT = 60;
1479 const uint lSUBTITLE_MAX_LEN = 128;
1482 event.m_subtitle = QString(
"");
1489 static const QRegularExpression mcaIncompleteTitle { R
"((.*).\.\.\.$)" };
1490 auto match = mcaIncompleteTitle.match(event.
m_title);
1491 if (match.hasMatch())
1493 static const QString mcaCompleteTitlea {
"^'?(" };
1494 static const QString mcaCompleteTitleb { R
"([^\.\?]+[^\'])'?[\.\?]\s+(.+))" };
1495 static const QRegularExpression mcaCompleteTitle
1496 { mcaCompleteTitlea + match.captured(1) + mcaCompleteTitleb,
1497 QRegularExpression::CaseInsensitiveOption};
1499 if (match.hasMatch())
1501 event.m_title = match.captured(1).trimmed();
1502 event.m_description = match.captured(2).trimmed();
1507 static const QRegularExpression mcaSubtitle { R
"(^'([^\.]+)'\.\s+(.+))" };
1509 if (match.hasMatch())
1511 uint matchLen = match.capturedLength(1);
1512#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1515 uint evDescLen = std::max(event.
m_description.length(),
static_cast<qsizetype
>(1));
1518 if ((matchLen < lSUBTITLE_MAX_LEN) &&
1519 ((matchLen * 100 / evDescLen) < SUBTITLE_PCT))
1521 event.m_subtitle = match.captured(1);
1522 event.m_description = match.captured(2);
1527 static const QRegularExpression mcaSeries { R
"(^S?(\d+)\/E?(\d+)\s-\s(.*)$)" };
1529 if (match.hasMatch())
1531 uint season = match.capturedView(1).toUInt();
1532 uint episode = match.capturedView(2).toUInt();
1533 event.m_subtitle = match.captured(3).trimmed();
1534 event.m_syndicatedepisodenumber =
1535 QString(
"S%1E%2").arg(season).arg(episode);
1536 event.m_season = season;
1537 event.m_episode = episode;
1542 static const QRegularExpression mcaCC { R
"(,?\s(HI|English) Subtitles\.?)" };
1543 int position =
event.m_description.indexOf(mcaCC);
1546 event.m_subtitleType |= SUB_HARDHEAR;
1547 event.m_description.remove(mcaCC);
1551 static const QRegularExpression mcaDD { R
"(,?\sDD\.?)" };
1552 position = event.m_description.indexOf(mcaDD);
1553 if ((position > 0) && (position > event.
m_description.length() - 7))
1555 event.m_audioProps |= AUD_DOLBY;
1556 event.m_description.remove(mcaDD);
1560 static const QRegularExpression mcaAvail { R
"(\s(Only available on [^\.]*bouquet|Not available in RSA [^\.]*)\.?)" };
1561 event.m_description.remove(mcaAvail);
1564 bool isMovie =
false;
1565 static const QRegularExpression mcaCredits { R
"((.*)\s\((\d{4})\)\s*([^\.]+)\.?\s*$)" };
1567 if (match.hasMatch())
1570 event.m_description = match.captured(1).trimmed();
1572 uint y = match.captured(2).trimmed().toUInt(&ok);
1574 event.m_airdate = y;
1580 static const QRegularExpression mcaYear { R
"((.*)\s\((\d{4})\)\s*$)" };
1582 if (match.hasMatch())
1585 event.m_description = match.captured(1).trimmed();
1587 uint y = match.captured(2).trimmed().toUInt(&ok);
1589 event.m_airdate = y;
1595 static const QRegularExpression mcaActors { R
"((.*\.)\s+([^\.]+\s[A-Z][^\.]+)\.\s*)" };
1597 if (match.hasMatch())
1599 static const QRegularExpression mcaActorsSeparator {
"(,\\s+)" };
1600 const QStringList actors = match.captured(2).split(
1601 mcaActorsSeparator, Qt::SkipEmptyParts);
1604 for (
const auto & actor : std::as_const(actors))
1606 event.m_description = match.captured(1).trimmed();
1618 static const QRegularExpression superRTLSubtitle { R
"(^Folge\s(\d{1,3}):\s'(.*)')" };
1619 auto match = superRTLSubtitle.match(event.
m_subtitle);
1620 if (match.hasMatch())
1623 event.m_episode = match.capturedView(1).toUInt();
1624 event.m_subtitle = match.captured(2);
1632 static const QRegularExpression rtlRepeat
1633 { R
"([\s\(]?Wiederholung.+vo[m|n].+(\d{2}\.\d{2}\.\d{4}|\d{2}[:\.]\d{2}\sUhr)\)?)" };
1635 if (match.hasMatch())
1638 int pos = match.capturedStart(0);
1639 int length = match.capturedLength(0) + (pos ? 0 : 1);
1640 event.m_description =
event.m_description.remove(pos, length).trimmed();
1644 static const QRegularExpression rtlSubtitle1 { R
"(^Folge\s(\d{1,4})\s*:\s+'(.*)'(?:\s|\.\s*|$))" };
1645 static const QRegularExpression rtlSubtitle2 { R
"(^Folge\s(\d{1,4})\s+(.{0,5}[^\?!\.]{0,120})[\?!\.]\s*)" };
1646 static const QRegularExpression rtlSubtitle3 { R
"(^(?:Folge\s)?(\d{1,4}(?:\/[IVX]+)?)\s+(.{0,5}[^\?!\.]{0,120})[\?!\.]\s*)" };
1647 static const QRegularExpression rtlSubtitle4 { R
"(^Thema.{0,5}:\s([^\.]+)\.\s*)" };
1648 static const QRegularExpression rtlSubtitle5 {
"^'(.+)'\\.\\s*" };
1649 static const QRegularExpression rtlEpisodeNo1 { R
"(^(Folge\s\d{1,4})\.*\s*)" };
1650 static const QRegularExpression rtlEpisodeNo2 { R
"(^(\d{1,2}\/[IVX]+)\.*\s*)" };
1661 if (match1.hasMatch())
1663 event.m_syndicatedepisodenumber = match1.captured(1);
1664 event.m_subtitle = match1.captured(2);
1665 event.m_description =
1666 event.m_description.remove(0, match1.capturedLength());
1669 else if (match2.hasMatch())
1671 event.m_syndicatedepisodenumber = match2.captured(1);
1672 event.m_subtitle = match2.captured(2);
1673 event.m_description =
1674 event.m_description.remove(0, match2.capturedLength());
1677 else if (match3.hasMatch())
1679 event.m_syndicatedepisodenumber = match3.captured(1);
1680 event.m_subtitle = match3.captured(2);
1681 event.m_description =
1682 event.m_description.remove(0, match3.capturedLength());
1685 else if (match4.hasMatch())
1687 event.m_subtitle = match4.captured(1);
1688 event.m_description =
1689 event.m_description.remove(0, match4.capturedLength());
1692 else if (match5.hasMatch())
1694 event.m_subtitle = match5.captured(1);
1695 event.m_description =
1696 event.m_description.remove(0, match5.capturedLength());
1699 else if (match6.hasMatch())
1701 event.m_syndicatedepisodenumber = match6.captured(2);
1702 event.m_subtitle = match6.captured(1);
1703 event.m_description =
1704 event.m_description.remove(0, match6.capturedLength());
1707 else if (match7.hasMatch())
1709 event.m_syndicatedepisodenumber = match7.captured(2);
1710 event.m_subtitle = match7.captured(1);
1711 event.m_description =
1712 event.m_description.remove(0, match7.capturedLength());
1722 const uint SUBTITLE_PCT = 35;
1723 const uint lSUBTITLE_MAX_LEN = 50;
1725 static const QRegularExpression rtlSubtitle { R
"(^([^\.]{3,})\.\s+(.+))" };
1727 if (match.hasMatch())
1729 uint matchLen = match.capturedLength(1);
1730#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1733 uint evDescLen = std::max(event.
m_description.length(),
static_cast<qsizetype
>(1));
1736 if ((matchLen < lSUBTITLE_MAX_LEN) &&
1737 (matchLen * 100 / evDescLen < SUBTITLE_PCT))
1739 event.m_subtitle = match.captured(1);
1740 event.m_description = match.captured(2);
1759 static const QRegularExpression pro7Repeat
1760 { R
"((?<=\s|^)\(WH vom \w+, \d{2}\.\d{2}\.\d{4}, \d{2}:\d{2} Uhr\)$)" };
1761 auto match = pro7Repeat.match(event.
m_subtitle);
1762 if (match.hasMatch())
1764 event.m_previouslyshown =
true;
1765 event.m_subtitle.remove(match.capturedStart(0),
1766 match.capturedLength(0));
1767 event.m_subtitle =
event.m_subtitle.trimmed();
1771 static const QRegularExpression pro7signLanguage
1772 { R
"((?<=\s|^)Mit Gebärdensprache \(Online\-Stream\)$)" };
1773 match = pro7signLanguage.match(event.m_subtitle);
1774 if (match.hasMatch())
1776 event.m_subtitle.remove(match.capturedStart(0),
1777 match.capturedLength(0));
1778 event.m_subtitle =
event.m_subtitle.trimmed();
1782 static const QRegularExpression pro7ratingAllAges
1783 { R
"((?<=\s|^)Altersfreigabe: Ohne Altersbeschränkung$)" };
1784 match = pro7ratingAllAges.match(event.m_subtitle);
1785 if (match.hasMatch())
1790 event.m_ratings.push_back(prograting);
1792 event.m_subtitle.remove(match.capturedStart(0),
1793 match.capturedLength(0));
1794 event.m_subtitle =
event.m_subtitle.trimmed();
1796 static const QRegularExpression pro7rating
1797 { R
"((?<=\s|^)Altersfreigabe: ab (\d+)$)" };
1799 if (match.hasMatch())
1803 prograting.
m_rating = match.captured(1);
1804 event.m_ratings.push_back(prograting);
1806 event.m_subtitle.remove(match.capturedStart(0),
1807 match.capturedLength(0));
1808 event.m_subtitle =
event.m_subtitle.trimmed();
1812 static const QRegularExpression pro7CategoryOriginalairdate
1813 { R
"((?<=\s|^)(Late Night Show|Live Shopping|Real Crime|Real Life Doku|Romantic Comedy|Scripted Reality|\S+), ([A-Z]+(?:\/[A-Z]+)*) (\d{4})$)" };
1814 match = pro7CategoryOriginalairdate.match(event.m_subtitle);
1815 if (match.hasMatch())
1817 event.m_category = match.captured(1);
1819 event.m_description.append(
" (").append(match.captured(2)).append(
" ").append(match.captured(3)).append(
")");
1821 uint y = match.captured(3).toUInt();
1822 event.m_originalairdate = QDate(y, 1, 1);
1825 event.m_airdate = y;
1828 event.m_subtitle.remove(match.capturedStart(0),
1829 match.capturedLength(0));
1830 event.m_subtitle =
event.m_subtitle.trimmed();
1835 event.m_subtitle =
"";
1844 static const QRegularExpression deDisneyChannelSubtitle { R
"(,([^,]+?)\s{0,1}(\d{4})$)" };
1845 auto match = deDisneyChannelSubtitle.match(event.
m_subtitle);
1846 if (match.hasMatch())
1850 event.m_airdate = match.captured(3).toUInt();
1852 event.m_subtitle.remove(match.capturedStart(0),
1853 match.capturedLength(0));
1855 static const QRegularExpression tmp { R
"(\s[^\s]+?-(Serie))" };
1857 if (match.hasMatch())
1860 event.m_category=match.captured(0).trimmed();
1861 event.m_subtitle.remove(match.capturedStart(0),
1862 match.capturedLength(0));
1871 static const QRegularExpression atvSubtitle { R
"(,{0,1}\sFolge\s(\d{1,3})$)" };
1872 event.m_subtitle.replace(atvSubtitle,
"");
1881 static const QRegularExpression fiRerun { R
"(\s?Uusinta[a-zA-Z\s]*\.?)" };
1883 if (match.hasMatch())
1885 event.m_previouslyshown =
true;
1886 event.m_description.remove(match.capturedStart(), match.capturedLength());
1889 static const QRegularExpression fiRerun2 { R
"(\([Uu]\))" };
1891 if (match.hasMatch())
1893 event.m_previouslyshown =
true;
1894 event.m_description.remove(match.capturedStart(), match.capturedLength());
1899 if (match.hasMatch())
1901 event.m_audioProps |= AUD_STEREO;
1902 event.m_description.remove(match.capturedStart(), match.capturedLength());
1906 static const QRegularExpression fiAgeLimit { R
"(\((\d{1,2}|[ST])\)$)" };
1907 match = fiAgeLimit.match(event.m_title);
1908 if (match.hasMatch())
1912 event.m_ratings.push_back(prograting);
1913 event.m_title.remove(match.capturedStart(), match.capturedLength());
1917 static const QRegularExpression fiFilm {
"^(Film|Elokuva): " };
1918 match = fiFilm.match(event.
m_title);
1919 if (match.hasMatch())
1921 event.m_category =
"Film";
1923 event.m_title.remove(match.capturedStart(), match.capturedLength());
1933 QString country =
"";
1935 static const QRegularExpression dePremiereLength { R
"(\s?[0-9]+\sMin\.)" };
1936 event.m_description =
event.m_description.replace(dePremiereLength,
"");
1938 static const QRegularExpression dePremiereAirdate { R
"(\s?([^\s^\.]+)\s((?:1|2)[0-9]{3})\.)" };
1940 if ( match.hasMatch())
1942 country = match.captured(1).trimmed();
1944 uint y = match.captured(2).toUInt(&ok);
1946 event.m_airdate = y;
1947 event.m_description.remove(match.capturedStart(0),
1948 match.capturedLength(0));
1951 static const QRegularExpression dePremiereCredits { R
"(\sVon\s([^,]+)(?:,|\su\.\sa\.)\smit\s([^\.]*)\.)" };
1953 if (match.hasMatch())
1956 const QStringList actors = match.captured(2).split(
1957 ", ", Qt::SkipEmptyParts);
1960 for (
const auto & actor : std::as_const(actors))
1962 event.m_description.remove(match.capturedStart(0),
1963 match.capturedLength(0));
1966 event.m_description =
event.m_description.replace(
"\u000A$",
"");
1967 event.m_description =
event.m_description.replace(
"\u000A",
" ");
1970 static const QRegularExpression dePremiereOTitle { R
"(\s*\(([^\)]*)\)$)" };
1971 match = dePremiereOTitle.match(event.m_title);
1972 if (match.hasMatch())
1974 event.m_subtitle = QString(
"%1, %2").arg(match.captured(1), country);
1975 event.m_title.remove(match.capturedStart(0),
1976 match.capturedLength(0));
1980 static const QRegularExpression deSkyDescriptionSeasonEpisode { R
"(^(\d{1,2}).\sStaffel,\sFolge\s(\d{1,2}):\s)" };
1981 match = deSkyDescriptionSeasonEpisode.match(event.m_description);
1982 if (match.hasMatch())
1984 event.m_season = match.captured(1).trimmed().toUInt();
1985 event.m_episode = match.captured(2).trimmed().toUInt();
1986 event.m_description.remove(match.capturedStart(0),
1987 match.capturedLength(0));
2008 {
"Movie - Soap/melodrama/folkloric",
2023 QString fullinfo =
event.m_subtitle +
event.m_description;
2024 event.m_subtitle =
"";
2032 event.m_category = name;
2033 event.m_categoryType =
type;
2041 auto match =
kStereo.match(fullinfo);
2042 if (match.hasMatch())
2044 event.m_audioProps |= AUD_STEREO;
2045 fullinfo.remove(match.capturedStart(), match.capturedLength());
2049 static const QRegularExpression nlWide {
"breedbeeld" };
2050 match = nlWide.match(fullinfo);
2051 if (match.hasMatch())
2053 event.m_videoProps |= VID_WIDESCREEN;
2054 fullinfo = fullinfo.replace(
"breedbeeld",
".");
2058 static const QRegularExpression nlRepeat {
"herh." };
2059 match = nlRepeat.match(fullinfo);
2060 if (match.hasMatch())
2061 fullinfo = fullinfo.replace(
"herh.",
".");
2064 static const QRegularExpression nlTxt {
"txt" };
2065 match = nlTxt.match(fullinfo);
2066 if (match.hasMatch())
2068 event.m_subtitleType |= SUB_NORMAL;
2069 fullinfo = fullinfo.replace(
"txt",
".");
2073 static const QRegularExpression nlHD { R
"(\sHD$)" };
2074 match = nlHD.match(event.m_title);
2075 if (match.hasMatch())
2077 event.m_videoProps |= VID_HDTV;
2078 event.m_title.remove(match.capturedStart(), match.capturedLength());
2082 static const QRegularExpression nlSub { R
"(\sAfl\.:\s([^\.]+)\.)" };
2083 match = nlSub.match(fullinfo);
2084 if (match.hasMatch())
2086 QString tmpSubString = match.captured(0);
2087 tmpSubString = tmpSubString.right(match.capturedLength() - 7);
2088 event.m_subtitle = tmpSubString.left(tmpSubString.length() -1);
2089 fullinfo.remove(match.capturedStart(), match.capturedLength());
2093 static const QRegularExpression nlSub2 { R
"(\s\"([^\"]+)\")" };
2094 match = nlSub2.match(fullinfo);
2095 if (match.hasMatch())
2097 QString tmpSubString = match.captured(0);
2098 tmpSubString = tmpSubString.right(match.capturedLength() - 2);
2099 event.m_subtitle = tmpSubString.left(tmpSubString.length() -1);
2100 fullinfo.remove(match.capturedStart(), match.capturedLength());
2106 int position =
event.m_title.indexOf(
":");
2107 if ((position != -1) && ((position + 1) < event.
m_title.size()) &&
2108 (event.
m_title[position + 1].toUpper() == event.
m_title[position + 1]) &&
2111 event.m_subtitle =
event.m_title.mid(position + 1);
2112 event.m_title =
event.m_title.left(position);
2117 static const QRegularExpression nlActors { R
"(\sMet:\s.+e\.a\.)" };
2118 static const QRegularExpression nlPersSeparator { R
"((, |\sen\s))" };
2119 match = nlActors.match(fullinfo);
2120 if (match.hasMatch())
2122 QString tmpActorsString = match.captured(0);
2123 tmpActorsString = tmpActorsString.right(tmpActorsString.length() - 6);
2124 tmpActorsString = tmpActorsString.left(tmpActorsString.length() - 5);
2125 const QStringList actors =
2126 tmpActorsString.split(nlPersSeparator, Qt::SkipEmptyParts);
2129 for (
const auto & actor : std::as_const(actors))
2131 fullinfo.remove(match.capturedStart(), match.capturedLength());
2135 static const QRegularExpression nlPres { R
"(\sPresentatie:\s([^\.]+)\.)" };
2136 match = nlPres.match(fullinfo);
2137 if (match.hasMatch())
2139 QString tmpPresString = match.captured(0);
2140 tmpPresString = tmpPresString.right(tmpPresString.length() - 14);
2141 tmpPresString = tmpPresString.left(tmpPresString.length() -1);
2142 const QStringList presenters =
2143 tmpPresString.split(nlPersSeparator, Qt::SkipEmptyParts);
2144 for (
const auto & presenter : std::as_const(presenters))
2146 fullinfo.remove(match.capturedStart(), match.capturedLength());
2150 static const QRegularExpression nlYear1 { R
"(\suit\s([1-2][0-9]{3}))" };
2151 static const QRegularExpression nlYear2 { R
"((\s\([A-Z]{0,3}/?)([1-2][0-9]{3})\))",
2152 QRegularExpression::CaseInsensitiveOption };
2153 match = nlYear1.match(fullinfo);
2154 if (match.hasMatch())
2157 uint y = match.capturedView(1).toUInt(&ok);
2159 event.m_originalairdate = QDate(y, 1, 1);
2162 match = nlYear2.match(fullinfo);
2163 if (match.hasMatch())
2166 uint y = match.capturedView(2).toUInt(&ok);
2168 event.m_originalairdate = QDate(y, 1, 1);
2172 static const QRegularExpression nlDirector { R
"(\svan\s(([A-Z][a-z]+\s)|([A-Z]\.\s)))" };
2173 match = nlDirector.match(fullinfo);
2174 if (match.hasMatch())
2178 static const QRegularExpression nlRub { R
"(\s?\(\W+\)\s?)" };
2179 fullinfo.remove(nlRub);
2182 static const QRegularExpression nlCat {
"^(Amusement|Muziek|Informatief|Nieuws/actualiteiten|Jeugd|Animatie|Sport|Serie/soap|Kunst/Cultuur|Documentaire|Film|Natuur|Erotiek|Comedy|Misdaad|Religieus)\\.\\s" };
2183 fullinfo.remove(nlCat);
2186 static const QRegularExpression nlOmroep { R
"(\s\(([A-Z]+/?)+\)$)" };
2187 event.m_title.remove(nlOmroep);
2191 event.m_description = fullinfo;
2211 static const QRegularExpression noRerun {
"\\(R\\)" };
2212 auto match = noRerun.match(event.
m_title);
2213 if (match.hasMatch())
2215 event.m_previouslyshown =
true;
2216 event.m_title.remove(match.capturedStart(), match.capturedLength());
2219 static const QRegularExpression noHD { R
"([\(\[]HD[\)\]])" };
2221 if (match.hasMatch())
2223 event.m_videoProps |= VID_HDTV;
2224 event.m_subtitle.remove(match.capturedStart(), match.capturedLength());
2228 if (match.hasMatch())
2230 event.m_videoProps |= VID_HDTV;
2231 event.m_description.remove(match.capturedStart(), match.capturedLength());
2241 static const QRegularExpression noRerun {
"\\(R\\)" };
2242 auto match = noRerun.match(event.
m_title);
2243 if (match.hasMatch())
2245 event.m_previouslyshown =
true;
2246 event.m_title.remove(match.capturedStart(), match.capturedLength());
2250 if (match.hasMatch())
2252 event.m_previouslyshown =
true;
2257 static const QRegularExpression noNRKCategories
2258 {
"^(Superstrek[ea]r|Supersomm[ea]r|Superjul|Barne-tv|Fantorangen|Kuraffen|Supermorg[eo]n|Julemorg[eo]n|Sommermorg[eo]n|"
2259 "Kuraffen-TV|Sport i dag|NRKs sportsl.rdag|NRKs sportss.ndag|Dagens dokumentar|"
2260 "NRK2s historiekveld|Detektimen|Nattkino|Filmklassiker|Film|Kortfilm|P.skemorg[eo]n|"
2261 "Radioteatret|Opera|P2-Akademiet|Nyhetsmorg[eo]n i P2 og Alltid Nyheter:): (.+)" };
2262 match = noNRKCategories.match(event.
m_title);
2263 if (match.hasMatch() && (match.capturedLength(2) > 1))
2265 event.m_title = match.captured(2);
2266 event.m_description =
"(" + match.captured(1) +
") " +
event.m_description;
2270 static const QRegularExpression noPremiere {
"\\s+-\\s+(Sesongpremiere|Premiere|premiere)!?$" };
2271 match = noPremiere.match(event.
m_title);
2272 if (match.hasMatch() && (match.capturedStart() >= 3))
2273 event.m_title.remove(match.capturedStart(), match.capturedLength());
2276 if (!event.
m_title.startsWith(
"CSI:") &&
2277 !event.
m_title.startsWith(
"CD:") &&
2278 !event.
m_title.startsWith(
"Distriktsnyheter: fra"))
2280 static const QRegularExpression noColonSubtitle {
"^([^:]+): (.+)" };
2281 match = noColonSubtitle.match(event.
m_title);
2282 if (match.hasMatch())
2286 event.m_title = match.captured(1);
2287 event.m_subtitle = match.captured(2);
2289 else if (event.
m_subtitle == match.captured(2))
2291 event.m_title = match.captured(1);
2309 static const QRegularExpression dkEpisode { R
"(\(([0-9]+)\))" };
2310 auto match = dkEpisode.match(event.
m_title);
2311 if (match.hasMatch())
2313 episode = match.capturedView(1).toInt();
2314 event.m_partnumber = match.capturedView(1).toInt();
2315 event.m_title.remove(match.capturedStart(), match.capturedLength());
2318 static const QRegularExpression dkPart { R
"(\(([0-9]+):([0-9]+)\))" };
2319 match = dkPart.match(event.m_title);
2320 if (match.hasMatch())
2322 episode = match.capturedView(1).toInt();
2323 event.m_partnumber = match.capturedView(1).toInt();
2324 event.m_parttotal = match.capturedView(2).toInt();
2325 event.m_title.remove(match.capturedStart(), match.capturedLength());
2329 static const QRegularExpression dkSubtitle1 {
"^([^:]+): (.+)" };
2330 match = dkSubtitle1.match(event.
m_title);
2331 if (match.hasMatch())
2333 event.m_title = match.captured(1);
2334 event.m_subtitle = match.captured(2);
2338 static const QRegularExpression dkSubtitle2 {
"^([^:]+) - (.+)" };
2339 match = dkSubtitle2.match(event.
m_title);
2340 if (match.hasMatch())
2342 event.m_title = match.captured(1);
2343 event.m_subtitle = match.captured(2);
2350 static const QRegularExpression dkSeason1 {
"Sæson ([0-9]+)\\." };
2352 if (match.hasMatch())
2354 season = match.capturedView(1).toInt();
2358 static const QRegularExpression dkSeason2 {
"- år ([0-9]+) :" };
2360 if (match.hasMatch())
2362 season = match.capturedView(1).toInt();
2367 event.m_episode = episode;
2370 event.m_season = season;
2373 static const QRegularExpression dkFeatures {
"Features:(.+)" };
2375 if (match.hasMatch())
2377 QString features = match.captured(1);
2378 event.m_description.remove(match.capturedStart(),
2379 match.capturedLength());
2381 static const QRegularExpression dkWidescreen {
" 16:9" };
2382 if (features.indexOf(dkWidescreen) != -1)
2383 event.m_videoProps |= VID_WIDESCREEN;
2385 static const QRegularExpression dkHD {
" HD" };
2386 if (features.indexOf(dkHD) != -1)
2387 event.m_videoProps |= VID_HDTV;
2389 static const QRegularExpression dkDolby {
" 5:1" };
2390 if (features.indexOf(dkDolby) != -1)
2391 event.m_audioProps |= AUD_DOLBY;
2393 static const QRegularExpression dkSurround { R
"( \(\(S\)\))" };
2394 if (features.indexOf(dkSurround) != -1)
2395 event.m_audioProps |= AUD_SURROUND;
2397 static const QRegularExpression dkStereo {
" S" };
2398 if (features.indexOf(dkStereo) != -1)
2399 event.m_audioProps |= AUD_STEREO;
2401 static const QRegularExpression dkReplay {
" \\(G\\)" };
2402 if (features.indexOf(dkReplay) != -1)
2403 event.m_previouslyshown =
true;
2405 static const QRegularExpression dkTxt {
" TTV" };
2406 if (features.indexOf(dkTxt) != -1)
2407 event.m_subtitleType |= SUB_NORMAL;
2420 newid = QString(
"%1%2").arg(event.
m_chanid).
2425 newid =
event.m_seriesId.mid(2,8);
2427 event.m_seriesId = newid;
2431 event.m_programId[0]=
'_';
2436 event.m_subtitle = QString(
"%1 (%2").arg(event.
m_subtitle).arg(episode);
2438 event.m_subtitle = QString(
"%1:%2").arg(event.
m_subtitle).
2442 event.m_season = season;
2443 event.m_episode = episode;
2444 event.m_syndicatedepisodenumber =
2445 QString(
"S%1E%2").arg(season).arg(episode);
2446 event.m_subtitle = QString(
"%1 Sæson %2").arg(event.
m_subtitle).
2449 event.m_subtitle = QString(
"%1)").arg(event.
m_subtitle);
2453 static const QRegularExpression dkDirector {
"(?:Instr.: |Instrukt.r: )(.+)$" };
2454 static const QRegularExpression dkPersonsSeparator {
"(, )|(og )" };
2455 QStringList directors {};
2457 if (match.hasMatch())
2459 QString tmpDirectorsString = match.captured(1);
2460 directors = tmpDirectorsString.split(dkPersonsSeparator, Qt::SkipEmptyParts);
2461 for (
const auto & director : std::as_const(directors))
2463 tmpDirectorsString = director.split(
":").last().trimmed().
2465 if (tmpDirectorsString !=
"")
2471 static const QRegularExpression dkActors {
"(?:Medvirkende: |Medv\\.: )(.+)" };
2473 if (match.hasMatch())
2475 QString tmpActorsString = match.captured(1);
2476 const QStringList actors =
2477 tmpActorsString.split(dkPersonsSeparator, Qt::SkipEmptyParts);
2478 for (
const auto & actor : std::as_const(actors))
2480 tmpActorsString = actor.split(
":").last().trimmed().remove(
kDotAtEnd);
2481 if (!tmpActorsString.isEmpty() && !directors.contains(tmpActorsString))
2488 static const QRegularExpression dkYear {
" fra ([0-9]{4})[ \\.]" };
2490 if (match.hasMatch())
2493 uint y = match.capturedView(1).toUInt(&ok);
2495 event.m_originalairdate = QDate(y, 1, 1);
2504 LOG(VB_EIT, LOG_INFO, QString(
"Applying html strip to %1").arg(event.
m_title));
2505 static const QRegularExpression html {
"</?EM>", QRegularExpression::CaseInsensitiveOption };
2506 event.m_title.remove(html);
2517 event.m_description = QString(
"");
2521 if (event.
m_subtitle.trimmed().right(1) !=
".'" )
2522 event.m_subtitle =
event.m_subtitle.trimmed() +
".";
2523 event.m_description =
event.m_subtitle.trimmed() + QString(
" ") +
event.m_description;
2524 event.m_subtitle = QString(
"");
2531 static const QRegularExpression grRating { R
"(\[(K|Κ|8|12|16|18)\]\s*)",
2532 QRegularExpression::CaseInsensitiveOption };
2533 auto match = grRating.match(event.
m_title);
2534 if (match.hasMatch())
2538 event.m_ratings.push_back(prograting);
2539 event.m_title.remove(match.capturedStart(), match.capturedLength());
2540 event.m_title =
event.m_title.trimmed();
2544 int position =
event.m_title.indexOf(
"(Ζ)");
2547 event.m_title =
event.m_title.replace(
"(Ζ)",
"");
2548 event.m_description.prepend(
"Ζωντανή Μετάδοση. ");
2552 static const QRegularExpression grNotPreviouslyShown {
2553 R
"(\W?(?:-\s*)*(?:\b[Α1]['΄η]?\s*(?:τηλεοπτικ[ηή]\s*)?(?:μετ[αά]δοση|προβολ[ηή]))\W?)",
2554 QRegularExpression::CaseInsensitiveOption|QRegularExpression::UseUnicodePropertiesOption };
2555 match = grNotPreviouslyShown.match(event.m_title);
2556 if (match.hasMatch())
2558 event.m_previouslyshown =
false;
2559 event.m_title.remove(match.capturedStart(), match.capturedLength());
2565 static const QRegularExpression grReplay { R
"(\([ΕE]\))" };
2566 match = grReplay.match(event.m_title);
2567 if (match.hasMatch())
2569 event.m_previouslyshown =
true;
2570 event.m_title.remove(match.capturedStart(), match.capturedLength());
2574 position =
event.m_description.indexOf(
"(HD)");
2577 event.m_description =
event.m_description.replace(
"(HD)",
"");
2578 event.m_videoProps |= VID_HDTV;
2582 position =
event.m_description.indexOf(
"(Full HD)");
2585 event.m_description =
event.m_description.replace(
"(Full HD)",
"");
2586 event.m_videoProps |= VID_HDTV;
2589 static const QRegularExpression grFixnofullstopActors { R
"(\w\s(Παίζουν:|Πρωταγων))" };
2591 if (match.hasMatch())
2592 event.m_description.insert(match.capturedStart() + 1,
".");
2595 static const QRegularExpression grFixnofullstopDirectors { R
"(\w\s(Σκηνοθ[εέ]))" };
2596 match = grFixnofullstopDirectors.match(event.m_description);
2597 if (match.hasMatch())
2598 event.m_description.insert(match.capturedStart() + 1,
".");
2606 static const QRegularExpression grActors { R
"((?:[Ππ]α[ιί]ζουν:|[ΜMμ]ε τους:|Πρωταγωνιστο[υύ]ν:|Πρωταγωνιστε[ιί]:?)(?:\s+στο ρόλο(?: του| της)?\s(?:\w+\s[οη]\s))?([-\w\s']+(?:,[-\w\s']+)*)(?:κ\.[αά])?\W?)" };
2608 static const QRegularExpression grPeopleSeparator { R
"(([,-]\s+))" };
2610 if (match.hasMatch())
2612 QString tmpActorsString = match.captured(1);
2613 const QStringList actors =
2614 tmpActorsString.split(grPeopleSeparator, Qt::SkipEmptyParts);
2615 for (
const auto & actor : std::as_const(actors))
2617 tmpActorsString = actor.split(
":").last().trimmed().remove(
kDotAtEnd);
2618 if (tmpActorsString !=
"")
2621 event.m_description.remove(match.capturedStart(), match.capturedLength());
2625 static const QRegularExpression grDirector { R
"((?:Σκηνοθεσία: |Σκηνοθέτης: |Σκηνοθέτης - Επιμέλεια: )(\w+\s\w+\s?)(?:\W?))" };
2627 if (match.hasMatch())
2629 QString tmpDirectorsString = match.captured(1);
2630 const QStringList directors =
2631 tmpDirectorsString.split(grPeopleSeparator, Qt::SkipEmptyParts);
2632 for (
const auto & director : std::as_const(directors))
2634 tmpDirectorsString = director.split(
":").last().trimmed().
2636 if (tmpDirectorsString !=
"")
2641 event.m_description.remove(match.capturedStart(), match.capturedLength());
2645 static const QRegularExpression grPres { R
"((?:Παρουσ[ιί]αση:(?:\b)*|Παρουσι[αά]ζ(?:ουν|ει)(?::|\sο|\sη)|Παρουσι[αά]στ(?:[ηή]ς|ρια|ριες|[εέ]ς)(?::|\sο|\sη)|Με τ(?:ον |ην )(?:[\s|:|ο|η])*(?:\b)*)([-\w\s]+(?:,[-\w\s]+)*)\W?)",
2646 QRegularExpression::CaseInsensitiveOption|QRegularExpression::UseUnicodePropertiesOption };
2648 if (match.hasMatch())
2650 QString tmpPresentersString = match.captured(1);
2651 const QStringList presenters =
2652 tmpPresentersString.split(grPeopleSeparator, Qt::SkipEmptyParts);
2653 for (
const auto & presenter : std::as_const(presenters))
2655 tmpPresentersString = presenter.split(
":").last().trimmed().
2657 if (tmpPresentersString !=
"")
2662 event.m_description.remove(match.capturedStart(), match.capturedLength());
2667 static const QRegularExpression grYear { R
"(\W?(?:\s?παραγωγ[ηή]ς|\s?-|,)\s*([1-2][0-9]{3})(?:-\d{1,4})?)",
2668 QRegularExpression::CaseInsensitiveOption };
2670 if (match.hasMatch())
2673 uint y = match.capturedView(1).toUInt(&ok);
2676 event.m_originalairdate = QDate(y, 1, 1);
2677 event.m_description.remove(match.capturedStart(), match.capturedLength());
2681 event.m_description =
event.m_description.replace(
" .",
".").trimmed();
2684 static const QRegularExpression grCountry {
2685 R
"((?:\W|\b)(?:(ελλην|τουρκ|αμερικ[αά]ν|γαλλ|αγγλ|βρεττ?αν|γερμαν|ρωσσ?|ιταλ|ελβετ|σουηδ|ισπαν|πορτογαλ|μεξικ[αά]ν|κιν[εέ]ζικ|ιαπων|καναδ|βραζιλι[αά]ν)(ικ[ηή][ςσ])))",
2686 QRegularExpression::CaseInsensitiveOption|QRegularExpression::UseUnicodePropertiesOption };
2688 if (match.hasMatch())
2689 event.m_description.remove(match.capturedStart(), match.capturedLength());
2693 bool series =
false;
2694 static const QRegularExpression grSeason {
2695 R
"((?:\W-?)*(?:\(-\s*)?\b(([Α-Ω|A|B|E|Z|H|I|K|M|N]{1,2})(?:'|΄)?|(\d{1,2})(?:ος|ου|oς|os)?)(?:\s*[ΚκKk][υύ]κλο(?:[σς]|υ))\s?)",
2696 QRegularExpression::CaseInsensitiveOption|QRegularExpression::UseUnicodePropertiesOption };
2699 match = grSeason.match(event.
m_title);
2700 if (match.hasMatch())
2702 if (!match.capturedView(2).isEmpty())
2706 int tmpinteger = match.capturedView(2).toUInt();
2709 if (match.captured(2) ==
"ΣΤ")
2715 static const QString LettToNumber =
"0ΑΒΓΔΕ6ΖΗΘΙΚΛΜΝ";
2716 tmpinteger = LettToNumber.indexOf(match.capturedView(2));
2717 if (tmpinteger != -1)
2719 event.m_season = tmpinteger;
2724 static const QString LettToNumber2 =
"0ABΓΔE6ZHΘIKΛMN";
2725 tmpinteger = LettToNumber2.indexOf(match.capturedView(2));
2726 if (tmpinteger != -1)
2727 event.m_season = tmpinteger;
2732 else if (!match.capturedView(3).isEmpty())
2734 event.m_season = match.capturedView(3).toUInt();
2737 event.m_title.remove(match.capturedStart(), match.capturedLength());
2742 if (match.hasMatch())
2744 if (!match.capturedView(2).isEmpty())
2748 int tmpinteger = match.capturedView(2).toUInt();
2751 if (match.captured(2) ==
"ΣΤ")
2757 static const QString LettToNumber =
"0ΑΒΓΔΕ6ΖΗΘΙΚΛΜΝ";
2758 tmpinteger = LettToNumber.indexOf(match.capturedView(2));
2759 if (tmpinteger != -1)
2760 event.m_season = tmpinteger;
2764 else if (!match.capturedView(3).isEmpty())
2766 event.m_season = match.capturedView(3).toUInt();
2769 event.m_description.remove(match.capturedStart(), match.capturedLength());
2774 static const QRegularExpression grSeasonAsRomanNumerals {
",\\s*([MDCLXVIΙΧ]+)$",
2775 QRegularExpression::CaseInsensitiveOption };
2776 match = grSeasonAsRomanNumerals.match(event.
m_title);
2777 auto match2 = grSeasonAsRomanNumerals.match(event.
m_description);
2778 if (match.hasMatch())
2780 if (!match.capturedView(1).isEmpty())
2781 event.m_season =
parseRoman(match.captured(1).toUpper());
2783 event.m_title.remove(match.capturedStart(), match.capturedLength());
2784 event.m_title =
event.m_title.trimmed();
2785 if (event.
m_title.right(1) ==
",")
2786 event.m_title.chop(1);
2788 else if (match2.hasMatch())
2790 if (!match2.capturedView(1).isEmpty())
2791 event.m_season =
parseRoman(match2.captured(1).toUpper());
2793 event.m_description.remove(match2.capturedStart(), match2.capturedLength());
2794 event.m_description =
event.m_description.trimmed();
2796 event.m_description.chop(1);
2799 static const QRegularExpression grlongEp { R
"(\b(?:Επ.|επεισ[οό]διο:?)\s*(\d+)\W?)",
2800 QRegularExpression::CaseInsensitiveOption|QRegularExpression::UseUnicodePropertiesOption };
2802 match = grlongEp.match(event.
m_title);
2804 if (match.hasMatch() || match2.hasMatch())
2806 if (!match.capturedView(1).isEmpty())
2808 event.m_episode = match.capturedView(1).toUInt();
2810 event.m_title.remove(match.capturedStart(), match.capturedLength());
2812 else if (!match2.capturedView(1).isEmpty())
2814 event.m_episode = match2.capturedView(1).toUInt();
2816 event.m_description.remove(match2.capturedStart(), match2.capturedLength());
2827 static const QRegularExpression grCommentsinTitle { R
"(\(([Α-Ωα-ω\s\d-]+)\)(?:\s*$)*)" };
2830 match = grCommentsinTitle.match(event.
m_title);
2831 if (match.hasMatch())
2832 event.m_title.remove(match.capturedStart(), match.capturedLength());
2840 static const QRegularExpression grRealTitleInDescription { R
"(^\(([A-Za-z\s\d-]+)\)\s*)" };
2843 match = grRealTitleInDescription.match(event.
m_description);
2844 if (match.hasMatch())
2846 event.m_description.remove(0, match.capturedLength());
2847 if (match.captured(0) != event.
m_title.trimmed())
2849 event.m_description =
"(" +
event.m_title.trimmed() +
"). " +
event.m_description;
2851 event.m_title = match.captured(1);
2856 static const QRegularExpression grRealTitleInTitle { R
"(\(([A-Za-z\s\d-]+)\)(?:\s*$)?)" };
2859 match = grRealTitleInTitle.match(event.
m_title);
2860 if (match.hasMatch())
2862 event.m_title.remove(match.capturedStart(), match.capturedLength());
2863 QString tmpTranslTitle =
event.m_title;
2865 event.m_title = match.captured(1);
2866 event.m_description =
"(" + tmpTranslTitle.trimmed() +
"). " +
event.m_description;
2871 static const QRegularExpression grEpisodeAsSubtitle { R
"(^Επεισ[οό]διο:\s?([\w\s\-,']+)\.\s?)" };
2873 if (match.hasMatch())
2875 event.m_subtitle = match.captured(1).trimmed();
2876 event.m_description.remove(match.capturedStart(), match.capturedLength());
2878 static const QRegularExpression grMovie { R
"(\bταιν[ιί]α\b)",
2879 QRegularExpression::CaseInsensitiveOption|QRegularExpression::UseUnicodePropertiesOption };
2880 bool isMovie = (
event.m_description.indexOf(grMovie) !=-1) ;
2886 event.m_description.replace(
",,",
",");
2893 struct grCategoryEntry {
2894 QRegularExpression expr;
2897 static const QRegularExpression grCategFood {
"\\W?(?:εκπομπ[ηή]\\W)?(Γαστρονομ[ιί]α[σς]?|μαγειρικ[ηή][σς]?|chef|συνταγ[εέηή]|διατροφ|wine|μ[αά]γειρα[σς]?)\\W?",
2898 QRegularExpression::CaseInsensitiveOption };
2899 static const QRegularExpression grCategDrama {
"\\W?(κοινωνικ[ηήό]|δραματικ[ηή]|δρ[αά]μα)\\W(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?",
2900 QRegularExpression::CaseInsensitiveOption};
2901 static const QRegularExpression grCategComedy {
"\\W?(κωμικ[ηήοό]|χιουμοριστικ[ηήοό]|κωμωδ[ιί]α)\\W(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?",
2902 QRegularExpression::CaseInsensitiveOption};
2903 static const QRegularExpression grCategChildren {
"\\W?(παιδικ[ηήοό]|κινο[υύ]μ[εέ]ν(ων|α)\\sσχ[εέ]δ[ιί](ων|α))\\W(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?",
2904 QRegularExpression::CaseInsensitiveOption};
2905 static const QRegularExpression grCategMystery {
"(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?\\W?(μυστηρ[ιί]ου)\\W?",
2906 QRegularExpression::CaseInsensitiveOption};
2907 static const QRegularExpression grCategFantasy {
"(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?\\W?(φαντασ[ιί]ας)\\W?",
2908 QRegularExpression::CaseInsensitiveOption};
2909 static const QRegularExpression grCategHistory {
"\\W?(ιστορικ[ηήοό])\\W?(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?",
2910 QRegularExpression::CaseInsensitiveOption};
2911 static const QRegularExpression grCategTeleMag {
"\\W?(ενημερωτικ[ηή]|ψυχαγωγικ[ηή]|τηλεπεριοδικ[οό]|μαγκαζ[ιί]νο)\\W?(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?",
2912 QRegularExpression::CaseInsensitiveOption};
2913 static const QRegularExpression grCategTeleShop {
"\\W?(οδηγ[οό][σς]?\\sαγορ[ωώ]ν|τηλεπ[ωώ]λ[ηή]σ|τηλεαγορ|τηλεμ[αά]ρκετ|telemarket)\\W?(?:(?:εκπομπ[ηή]|σειρ[αά]|ταιν[ιί]α)\\W)?",
2914 QRegularExpression::CaseInsensitiveOption};
2915 static const QRegularExpression grCategGameShow {
"\\W?(τηλεπαιχν[ιί]δι|quiz)\\W?",
2916 QRegularExpression::CaseInsensitiveOption};
2917 static const QRegularExpression grCategDocumentary {
"\\W?(ντοκ[ιυ]μαντ[εέ]ρ)\\W?",
2918 QRegularExpression::CaseInsensitiveOption};
2919 static const QRegularExpression grCategBiography {
"\\W?(βιογραφ[ιί]α|βιογραφικ[οό][σς]?)\\W?",
2920 QRegularExpression::CaseInsensitiveOption};
2921 static const QRegularExpression grCategNews {
"\\W?(δελτ[ιί]ο\\W?|ειδ[ηή]σε(ι[σς]|ων))\\W?",
2922 QRegularExpression::CaseInsensitiveOption};
2923 static const QRegularExpression grCategSports {
"\\W?(champion|αθλητικ[αάοόηή]|πρωτ[αά]θλημα|ποδ[οό]σφαιρο(ου)?|κολ[υύ]μβηση|πατιν[αά]ζ|formula|μπ[αά]σκετ|β[οό]λε[ιϊ])\\W?",
2924 QRegularExpression::CaseInsensitiveOption};
2925 static const QRegularExpression grCategMusic {
"\\W?(μουσικ[οόηή]|eurovision|τραγο[υύ]δι)\\W?",
2926 QRegularExpression::CaseInsensitiveOption};
2927 static const QRegularExpression grCategReality {
"\\W?(ρι[αά]λιτι|reality)\\W?",
2928 QRegularExpression::CaseInsensitiveOption};
2929 static const QRegularExpression grCategReligion {
"\\W?(θρησκε[ιί]α|θρησκευτικ|να[οό][σς]?|θε[ιί]α λειτουργ[ιί]α)\\W?",
2930 QRegularExpression::CaseInsensitiveOption};
2931 static const QRegularExpression grCategCulture {
"\\W?(τ[εέ]χν(η|ε[σς])|πολιτισμ)\\W?",
2932 QRegularExpression::CaseInsensitiveOption};
2933 static const QRegularExpression grCategNature {
"\\W?(φ[υύ]ση|περιβ[αά]λλο|κατασκευ|επιστ[ηή]μ(?!ονικ[ηή]ς φαντασ[ιί]ας))\\W?",
2934 QRegularExpression::CaseInsensitiveOption};
2935 static const QRegularExpression grCategSciFi {
"\\W?(επιστ(.|ημονικ[ηή]ς)\\s?φαντασ[ιί]ας)\\W?",
2936 QRegularExpression::CaseInsensitiveOption};
2937 static const QRegularExpression grCategHealth {
"\\W?(υγε[ιί]α|υγειιν|ιατρικ|διατροφ)\\W?",
2938 QRegularExpression::CaseInsensitiveOption};
2939 static const QRegularExpression grCategSpecial {
"\\W?(αφι[εέ]ρωμα)\\W?",
2940 QRegularExpression::CaseInsensitiveOption};
2941 static const QList<grCategoryEntry> grCategoryDescData = {
2942 { .expr=grCategComedy, .category=
"Κωμωδία" },
2943 { .expr=grCategTeleMag, .category=
"Τηλεπεριοδικό" },
2944 { .expr=grCategNature, .category=
"Επιστήμη/Φύση" },
2945 { .expr=grCategHealth, .category=
"Υγεία" },
2946 { .expr=grCategReality, .category=
"Ριάλιτι" },
2947 { .expr=grCategDrama, .category=
"Κοινωνικό" },
2948 { .expr=grCategChildren, .category=
"Παιδικό" },
2949 { .expr=grCategSciFi, .category=
"Επιστ.Φαντασίας" },
2950 { .expr=grCategMystery, .category=
"Μυστηρίου" },
2951 { .expr=grCategFantasy, .category=
"Φαντασίας" },
2952 { .expr=grCategHistory, .category=
"Ιστορικό" },
2953 { .expr=grCategTeleShop, .category=
"Τηλεπωλήσεις" },
2954 { .expr=grCategFood, .category=
"Γαστρονομία" },
2955 { .expr=grCategGameShow, .category=
"Τηλεπαιχνίδι" },
2956 { .expr=grCategBiography, .category=
"Βιογραφία" },
2957 { .expr=grCategSports, .category=
"Αθλητικά" },
2958 { .expr=grCategMusic, .category=
"Μουσική" },
2959 { .expr=grCategDocumentary, .category=
"Ντοκιμαντέρ" },
2960 { .expr=grCategReligion, .category=
"Θρησκεία" },
2961 { .expr=grCategCulture, .category=
"Τέχνες/Πολιτισμός" },
2962 { .expr=grCategSpecial, .category=
"Αφιέρωμα" },
2964 static const QList<grCategoryEntry> grCategoryTitleData = {
2965 { .expr=grCategTeleShop, .category=
"Τηλεπωλήσεις" },
2966 { .expr=grCategGameShow, .category=
"Τηλεπαιχνίδι" },
2967 { .expr=grCategMusic, .category=
"Μουσική" },
2968 { .expr=grCategNews, .category=
"Ειδήσεις" },
2975 event.m_category =
"Φαντασίας/Μυστηρίου";
2980 for (
const auto& [expression, category] : grCategoryDescData)
2983 event.m_category = category;
2989 for (
const auto& [expression, category] : grCategoryTitleData)
2991 if (event.
m_title.indexOf(expression) != -1) {
2992 event.m_category = category;
3006 event.m_subtitle =
"";
3011 auto i =
event.m_items.begin();
3012 while (i != event.
m_items.end())
3016 if ((QString::compare (i.key(),
"Role Player") == 0) ||
3017 (QString::compare (i.key(),
"Performing Artist") == 0))
3020 i =
event.m_items.erase (i);
3022 else if (QString::compare (i.key(),
"Director") == 0)
3025 i =
event.m_items.erase (i);
3027 else if (QString::compare (i.key(),
"Commentary or Commentator") == 0)
3030 i =
event.m_items.erase (i);
3032 else if (QString::compare (i.key(),
"Presenter") == 0)
3035 i =
event.m_items.erase (i);
3037 else if (QString::compare (i.key(),
"Producer") == 0)
3040 i =
event.m_items.erase (i);
3042 else if (QString::compare (i.key(),
"Scriptwriter") == 0)
3045 i =
event.m_items.erase (i);
3054 static const QRegularExpression unitymediaImdbrating { R
"(\s*IMDb Rating: (\d\.\d)\s?/10$)" };
3055 auto match = unitymediaImdbrating.match(event.
m_description);
3056 if (match.hasMatch())
3058 float stars = match.captured(1).toFloat();
3059 event.m_stars = stars / 10.0F;
3060 event.m_description.remove(match.capturedStart(0),
3061 match.capturedLength(0));
static QString GetDefaultAuthority(uint chanid)
Returns the DVB default authority for the chanid given.
QMultiMap< QString, QString > m_items
ProgramInfo::CategoryType m_categoryType
uint16_t m_airdate
movie year / production year
static void FixUK(DBEventEIT &event)
Use this in the United Kingdom to standardize DVB-T guide.
static void FixAUFreeview(DBEventEIT &event)
Use this to standardize DVB-T guide in Australia.
static const uint kSubtitleMaxLen
static void FixStripHTML(DBEventEIT &event)
Use this to clean HTML Tags from EIT Data.
static void FixNO(DBEventEIT &event)
Use this to clean DVB-S guide in Norway.
static void FixAUNine(DBEventEIT &event)
Use this to standardize DVB-T guide in Australia.
static void FixGreekSubtitle(DBEventEIT &event)
static void FixAUStar(DBEventEIT &event)
Use this to standardize DVB-S guide in Australia.
static void SetUKSubtitle(DBEventEIT &event)
Use this in the United Kingdom to standardize DVB-T guide.
static const uint kDotToTitle
static const uint kMaxToTitle
static void FixComHem(DBEventEIT &event, bool process_subtitle)
Use this to standardize ComHem DVB-C service in Sweden.
static void FixRTL(DBEventEIT &event)
Use this to standardise the RTL group guide in Germany.
static void FixMCA(DBEventEIT &event)
Use this to standardise the MultiChoice Africa DVB-S guide.
static void FixATV(DBEventEIT &event)
Use this to standardise the ATV/ATV2 guide in Germany.
static const int kMinMovieDuration
static void FixAUSeven(DBEventEIT &event)
Use this to standardize DVB-T guide in Australia.
static void FixDisneyChannel(DBEventEIT &event)
Use this to standardise the Disney Channel guide in Germany.
static void FixAUDescription(DBEventEIT &event)
Use this to standardize DVB-T guide in Australia.
static void FixDK(DBEventEIT &event)
Use this to clean YouSee's DVB-C guide in Denmark.
static const uint kMaxDotToColon
static void Fix(DBEventEIT &event)
static void FixPBS(DBEventEIT &event)
Use this to standardize PBS ATSC guide in the USA.
static const uint kMaxQuestionExclamation
static void FixPRO7(DBEventEIT &event)
Use this to standardise the PRO7/Sat1 group guide in Germany.
static QString AddDVBEITAuthority(uint chanid, const QString &id)
This adds a DVB EIT default authority to series id or program id if one exists in the DB for that cha...
static void FixCategory(DBEventEIT &event)
static void FixGreekCategories(DBEventEIT &event)
static int parseRoman(QString roman)
static void FixFI(DBEventEIT &event)
Use this to clean DVB-T guide in Finland.
static void FixPremiere(DBEventEIT &event)
Use this to standardize DVB-C guide in Germany for the providers Kabel Deutschland and Premiere.
static void FixNRK_DVBT(DBEventEIT &event)
Use this to clean DVB-T guide in Norway (NRK)
static void FixBellExpressVu(DBEventEIT &event)
Use this for the Canadian BellExpressVu to standardize DVB-S guide.
static void FixGreekEIT(DBEventEIT &event)
static void FixUnitymedia(DBEventEIT &event)
static void FixNL(DBEventEIT &event)
Use this to standardize @Home DVB-C guide in the Netherlands.
QString dish_theme_type_to_string(uint theme_type)
static const QMap< QChar, quint16 > r2v
static const QRegularExpression kDotAtEnd
static const QMap< QString, NLMapResult > categoryTrans
static const QMap< QString, DBPerson::Role > deCrewTitle
static const QRegularExpression kStereo
static const QRegularExpression kUKSpaceColonStart
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
def rating(profile, smoonURL, gate)
ProgramInfo::CategoryType type