Repository: xbmc/xbmc
File: xbmc/filesystem/DiscDirectoryHelper.cpp (C++)

Code before:
  for (unsigned int i = 0; i < m_numEpisodes; ++i)
  {
    if (m_allEpisodes != AllEpisodes::ALL &&
        i != episodeIndex - m_numSpecials) // Specials before episodes in episodesOnDisc
      continue;

    m_candidatePlaylists.emplace(group[i].playlist,
                                 CandidatePlaylistInformation{.playlist = group[i].playlist,
                                                              .index = i + m_numSpecials,
                                                              .duration = group[i].duration,
                                                              .clips = group[i].clips,
                                                              .languages = group[i].languages});
    CLog::LogF(LOGDEBUG, "Candidate playlist {}", group[i].playlist);
  }
}

void CDiscDirectoryHelper::UseGroupMethod(unsigned int episodeIndex,
                                          const std::vector<CVideoInfoTag>& episodesOnDisc)
{
  // Method 2a - More than one episode on disc

  // Use groups and find nth playlist (or all for all episodes) in group
  // Groups are already contain at least numEpisodes playlists of minimum duration
  // Firstly look just at groups that contain exactly numEpisodes playlists
  CLog::LogF(LOGDEBUG, "Using group method - exact number of playlists");
  std::vector groups{GetGroupsWithoutDuplicates(m_groups)};
  for (const auto& group : groups)
  {
    if (group.size() != m_numEpisodes)
      continue;

    GetPlaylistsFromGroup(episodeIndex, group);
  }

  if (m_candidatePlaylists.empty())
  {
    // Now look for groups that contain more than numEpisodes playlists
    // Check that the first numEpisodes playlists have a duration within 20% of the desired episode
    CLog::LogF(LOGDEBUG, "Using group method - relaxed number of playlists");
    const std::chrono::milliseconds duration{episodesOnDisc[episodeIndex].GetDuration() * 1000ms};
    for (const auto& group : groups)
    {
      if (group.size() <= m_numEpisodes)
        continue;

      // Check duration
      constexpr double WITHIN_PERCENT{20.0};
      if (!std::ranges::all_of(group | std::views::take(m_numEpisodes) |
                                   std::views::transform(&CandidatePlaylistInformation::duration),
                               [duration](std::chrono::milliseconds d)
                               { return abs(d - duration) < (WITHIN_PERCENT / 100.0 * duration); }))

Review comment (refactor):
```suggestion
  const std::vector groups{GetGroupsWithoutDuplicates(m_groups)};
```

Code after:
    if (m_allEpisodes != AllEpisodes::ALL &&
        i != episodeIndex - m_numSpecials) // Specials before episodes in episodesOnDisc
      continue;

    m_candidatePlaylists.emplace(group[i].playlist,
                                 CandidatePlaylistInformation{.playlist = group[i].playlist,
                                                              .index = i + m_numSpecials,
                                                              .duration = group[i].duration,
                                                              .clips = group[i].clips,
                                                              .languages = group[i].languages});
    CLog::LogF(LOGDEBUG, "Candidate playlist {}", group[i].playlist);
  }
}

void CDiscDirectoryHelper::UseGroupMethod(unsigned int episodeIndex,
                                          const std::vector<CVideoInfoTag>& episodesOnDisc)
{
  // Method 2a - More than one episode on disc

  // Use groups and find nth playlist (or all for all episodes) in group
  // Groups are already contain at least numEpisodes playlists of minimum duration
  // Firstly look just at groups that contain exactly numEpisodes playlists
  CLog::LogF(LOGDEBUG, "Using group method - exact number of playlists");
  const std::vector groups{GetGroupsWithoutDuplicates(m_groups)};
  for (const auto& group : groups)
  {
    if (group.size() != m_numEpisodes)
      continue;

    GetPlaylistsFromGroup(episodeIndex, group);
  }

  if (m_candidatePlaylists.empty())
  {
    // Now look for groups that contain more than numEpisodes playlists
    // Check that the first numEpisodes playlists have a duration within 20% of the desired episode
    CLog::LogF(LOGDEBUG, "Using group method - relaxed number of playlists");
    const std::chrono::milliseconds duration{episodesOnDisc[episodeIndex].GetDuration() * 1000ms};
    for (const auto& group : groups)
    {
      if (group.size() <= m_numEpisodes)
        continue;

      // Check duration
      constexpr double WITHIN_PERCENT{20.0};
      if (!std::ranges::all_of(group | std::views::take(m_numEpisodes) |
                                   std::views::transform(&CandidatePlaylistInformation::duration),
                               [duration](std::chrono::milliseconds d)
                               { return abs(d - duration) < (WITHIN_PERCENT / 100.0 * duration); }))
        continue;