diff --git a/src/EPG.cpp b/src/EPG.cpp index ac71f8d4..16f4ddb7 100644 --- a/src/EPG.cpp +++ b/src/EPG.cpp @@ -68,8 +68,6 @@ PVR_ERROR EPG::GetEPGForChannel(int channelUid, time_t start, time_t end, kodi:: } } - broadcast.SetYear(XMLUtils::GetIntValue(pListingNode, "year")); - std::string startTime; std::string endTime; XMLUtils::GetString(pListingNode, "start", startTime); @@ -80,7 +78,6 @@ PVR_ERROR EPG::GetEPGForChannel(int channelUid, time_t start, time_t end, kodi:: const std::string oidLookup(endTime + ":" + std::to_string(channelUid)); broadcast.SetTitle(title); - broadcast.SetEpisodeName(subtitle); broadcast.SetUniqueChannelId(channelUid); broadcast.SetStartTime(stol(startTime)); broadcast.SetUniqueBroadcastId(stoi(endTime)); @@ -132,13 +129,65 @@ PVR_ERROR EPG::GetEPGForChannel(int channelUid, time_t start, time_t end, kodi:: } } - broadcast.SetSeriesNumber(XMLUtils::GetIntValue(pListingNode, "season", EPG_TAG_INVALID_SERIES_EPISODE)); - broadcast.SetEpisodeNumber(XMLUtils::GetIntValue(pListingNode, "episode", EPG_TAG_INVALID_SERIES_EPISODE)); + + int season{ EPG_TAG_INVALID_SERIES_EPISODE }; + int episode{EPG_TAG_INVALID_SERIES_EPISODE}; + XMLUtils::GetInt(pListingNode, "season", season); + XMLUtils::GetInt(pListingNode, "episode", episode); + broadcast.SetEpisodeNumber(episode); broadcast.SetEpisodePartNumber(EPG_TAG_INVALID_SERIES_EPISODE); + // Backend could send epidode only as S00 and parts are not support + if (season <= 0 || episode == EPG_TAG_INVALID_SERIES_EPISODE) + { + std::regex base_regex("^.*\\([eE][pP](\\d+)(?:/?(\\d+))?\\)"); + std::smatch base_match; + if (std::regex_search(description, base_match, base_regex)) + { + broadcast.SetEpisodeNumber(std::atoi(base_match[1].str().c_str())); + if (base_match[2].matched) + broadcast.SetEpisodePartNumber(std::atoi(base_match[2].str().c_str())); + } + else if (std::regex_search(description, base_match, std::regex("^([1-9]\\d*)/([1-9]\\d*)\\."))) + { + broadcast.SetEpisodeNumber(std::atoi(base_match[1].str().c_str())); + broadcast.SetEpisodePartNumber(std::atoi(base_match[2].str().c_str())); + } + } + if (season != EPG_TAG_INVALID_SERIES_EPISODE) + { + // clear out NextPVR formatted data, Kodi supports S/E display + if (subtitle == kodi::tools::StringUtils::Format("S%02dE%02d", season, episode)) + { + subtitle.clear(); + } + if (season == 0) + season = EPG_TAG_INVALID_SERIES_EPISODE; + } + broadcast.SetSeriesNumber(season); + broadcast.SetEpisodeName(subtitle); + + int year{-1}; + if (XMLUtils::GetInt(pListingNode, "year", year)) + { + broadcast.SetYear(year); + } std::string original; - XMLUtils::GetString(pListingNode, "original", original); - broadcast.SetFirstAired(original); + if (XMLUtils::GetString(pListingNode, "original", original)) + { + if (broadcast.GetGenreType() == 16 && broadcast.GetGenreSubType() == 0 && year == -1 && original.length() > 4) + { + const std::string originalYear = kodi::tools::StringUtils::Mid(original, 0, 4); + year = atoi(originalYear.c_str()); + if (year != 0) + broadcast.SetYear(year); + } + else + { + broadcast.SetFirstAired(original); + } + } + bool firstrun; if (XMLUtils::GetBoolean(pListingNode, "firstrun", firstrun)) diff --git a/src/Recordings.cpp b/src/Recordings.cpp index ed5c22f0..dd764305 100644 --- a/src/Recordings.cpp +++ b/src/Recordings.cpp @@ -323,20 +323,17 @@ bool Recordings::UpdatePvrRecording(const tinyxml2::XMLNode* pRecordingNode, kod tag.SetSeriesNumber(PVR_RECORDING_INVALID_SERIES_EPISODE); tag.SetEpisodeNumber(PVR_RECORDING_INVALID_SERIES_EPISODE); - - if (XMLUtils::GetString(pRecordingNode, "subtitle", buffer)) + if (ParseNextPVRSubtitle(pRecordingNode, tag)) { - if (ParseNextPVRSubtitle(pRecordingNode, tag)) + if (m_settings->m_separateSeasons && multipleSeasons && tag.GetSeriesNumber() != PVR_RECORDING_INVALID_SERIES_EPISODE) { - if (m_settings->m_separateSeasons && multipleSeasons && tag.GetSeriesNumber() != PVR_RECORDING_INVALID_SERIES_EPISODE) - { - if (status != "Failed") - tag.SetDirectory(kodi::tools::StringUtils::Format("/%s/%s %d", tag.GetTitle().c_str(), kodi::addon::GetLocalizedString(20373).c_str(), tag.GetSeriesNumber())); - else - tag.SetDirectory(kodi::tools::StringUtils::Format("/%s/%s/%s %d", kodi::addon::GetLocalizedString(30166).c_str(),tag.GetTitle().c_str(), kodi::addon::GetLocalizedString(20373).c_str(), tag.GetSeriesNumber())); - } + if (status != "Failed") + tag.SetDirectory(kodi::tools::StringUtils::Format("/%s/%s %d", tag.GetTitle().c_str(), kodi::addon::GetLocalizedString(20373).c_str(), tag.GetSeriesNumber())); + else + tag.SetDirectory(kodi::tools::StringUtils::Format("/%s/%s/%s %d", kodi::addon::GetLocalizedString(30166).c_str(),tag.GetTitle().c_str(), kodi::addon::GetLocalizedString(20373).c_str(), tag.GetSeriesNumber())); } } + tag.SetYear(XMLUtils::GetIntValue(pRecordingNode, "year")); std::string original; @@ -473,24 +470,27 @@ bool Recordings::ParseNextPVRSubtitle(const tinyxml2::XMLNode *pRecordingNode, k bool hasSeasonEpisode = false; if (XMLUtils::GetString(pRecordingNode, "subtitle", buffer)) { - std::regex base_regex("S(\\d{2,4})E(\\d+) - ?(.+)?"); + std::regex base_regex("S(\\d{2,4})E(\\d+)(?: - ?(.+)$)?"); std::smatch base_match; // note NextPVR does not support S0 for specials - if (std::regex_match(buffer, base_match, base_regex)) + if (std::regex_search(buffer, base_match, base_regex)) { if (base_match.size() == 3 || base_match.size() == 4) { - std::ssub_match base_sub_match = base_match[1]; - tag.SetSeriesNumber(std::stoi(base_sub_match.str())); + int season = std::stoi(base_sub_match.str()); + if (season != 0) + { + tag.SetSeriesNumber(season); + hasSeasonEpisode = true; + } base_sub_match = base_match[2]; tag.SetEpisodeNumber(std::stoi(base_sub_match.str())); - if (base_match.size() == 4) + if (base_match[3].matched) { base_sub_match = base_match[3]; tag.SetEpisodeName(base_sub_match.str()); } - hasSeasonEpisode = true; } } else @@ -518,6 +518,21 @@ bool Recordings::ParseNextPVRSubtitle(const tinyxml2::XMLNode *pRecordingNode, k } } } + const std::string plot = tag.GetPlot(); + if (tag.GetEpisodeNumber() == PVR_RECORDING_INVALID_SERIES_EPISODE && !plot.empty()); + { + // Kodi doesn't support episode parts on recordings + std::regex base_regex("^.*\\([eE][pP](\\d+)(?:/?(\\d+))?\\)"); + std::smatch base_match; + if (std::regex_search(plot, base_match, base_regex)) + { + tag.SetEpisodeNumber(std::atoi(base_match[1].str().c_str())); + } + else if (std::regex_search(plot, base_match, std::regex("^([1-9]\\d*)/([1-9]\\d*)\\."))) + { + tag.SetEpisodeNumber(std::atoi(base_match[1].str().c_str())); + } + } } return hasSeasonEpisode; }