def _create_replay()

in source/controlplaneapi/infrastructure/lambda/Replay/shared/ReplayEngine.py [0:0]


    def _create_replay(self):

        self.__mark_replay_in_progress()

        self._replay_to_be_processed = self.__event['ReplayRequest']

        # Get Segments with Features. OptoStart and OptoEndtime of Segments will be Maps by default.
        self.get_all_segments_with_features()

        # If We are dealing with Clip Based Features, we are done with Collecting the segments having Features, just push to DDB
        if not self._is_replay_duration_based():
            self._persist_replay_metadata(self._segment_feature_maping)
        else:
            print('Duration based, calculating total duration of chosen Segments')
            debuginfo = []

            replay_request_duration = self.__event['ReplayRequest']['DurationbasedSummarization']['Duration'] * 60 # In Secs

            # For Duration based, we need to check if the Sum of Segment Clip Duration is more than the Duration asked for in the 
            # Reply Request. If yes, we calculate scores and pick the best segments. If no, we simply push the segments into DDB
            duration_result, duration = self._does_total_duration_of_all_segments_exceed_configured()
            if not duration_result:
                debuginfo.append(f"Total duration {duration} secs of chosen Segments within Replay Request duration {replay_request_duration} secs. Not calculating Scores and weights.")

                self._persist_replay_metadata(self._segment_feature_maping, debuginfo)
                print(f"Total duration {duration} secs of chosen Segments is less than Replay Request duration {replay_request_duration} secs.")
                debuginfo.append(f"Total duration {duration} secs of chosen Segments is less than Replay Request duration {replay_request_duration} secs.")
            else:
                
                # If no Equal Distribution is sought, pick segments based on High Scores, duration
                if not self.__event['ReplayRequest']['DurationbasedSummarization']['EqualDistribution']:

                    print(f'Calculate Scores based on Weights .. total duration was {duration}')
                    self._calculate_segment_scores_basedon_weights(self._segment_feature_maping)

                    print("--------")
                    print(self._segment_feature_maping)

                    # After each Segment has been scored, sort them in Desc based on Score
                    sorted_segments = sorted(self._segment_feature_maping, key=lambda x: x['Score'], reverse=True)

                    print("--------AFTER SORT----------")
                    print(sorted_segments)

                    # Find which segments needs to be Removed to meet the Duration Requirements in Replay Request
                    total_duration_all = 0
                    total_duration = 0
                    final_segments = []
                    
                    for segment in sorted_segments:
                        segment_duration = self._get_segment_duration_in_secs(segment)
                        total_duration_all += segment_duration

                        if total_duration + segment_duration <= replay_request_duration:
                            final_segments.append(segment)
                            total_duration += segment_duration
                        else:
                            print(f"Ignoring the segment - StartTime {segment['Start']}, EndTime {segment['End']} - to avoid exceeding the replay request duration limit {replay_request_duration} secs")
                            debuginfo.append(f"Ignoring segment - StartTime {segment['Start']}, EndTime {segment['End']} Segment Duration {segment_duration} secs - to avoid exceeding the replay duration limit of {replay_request_duration} secs.")


                    debuginfo.append(f"Duration if all segments considered would be {total_duration_all} secs")

                    # Finally Sort the Segments based on the Start time in Asc Order
                    sorted_final_segments = sorted(final_segments, key=lambda x: x['Start'], reverse=False)
                    self._persist_replay_metadata(sorted_final_segments, debuginfo)

                else:

                    # Because Equal Distrbution is being asked for, 
                    # We will distribute the total segment duration into Multiple TimeGroups and Group segments within them based on Segment Start time.
                    # Within each TimeGroup, we will Score the Segments based on Weights and 
                    # pick the Highest Scoring Segment by adhering to the Duration which will be the TimeGroup Duration
                    # Each Time Group will also have an Absolute time representation. 
                    # For example, first Timegroup would be from 0 - 292 secs, 2nd from 292 to 584 secs .. the last one(t6th) from 1460 to 1752 Secs
                    # We will select segments whose StartTime falls in these Absolute time ranges to get a Equal Distribution

                    
                    first_segment = self._all_segments_with_features[0]
                    last_segment = self._all_segments_with_features[len(self._all_segments_with_features) - 1]


                    start_of_first_segment_secs = first_segment['OptoStart'][self._audio_track] if self._is_segment_optimized(first_segment) else first_segment['Start']
                    end_of_last_segment_secs = last_segment['OptoEnd'][self._audio_track] if self._is_segment_optimized(last_segment) else last_segment['End']

                    debuginfo.append(f"First Seg starts at {start_of_first_segment_secs} secs")
                    debuginfo.append(f"Last Seg Ends at {end_of_last_segment_secs} secs")

                    total_segment_duration_in_secs = end_of_last_segment_secs - start_of_first_segment_secs
                    debuginfo.append(f"total_segment_duration_in_secs = {total_segment_duration_in_secs} secs")

                    total_segment_duration_in_hrs = (end_of_last_segment_secs - start_of_first_segment_secs) / 3600 # Hours
                    debuginfo.append(f"total_segment_duration_in_hrs = {total_segment_duration_in_hrs} hrs")

                    # Find how many Time Groups we need. If we have more than 1 Hr lets divide into multiple groups.
                    if total_segment_duration_in_secs > 3600:
                        no_of_time_groups = (math.ceil(total_segment_duration_in_hrs)* 2) + TIMEGROUP_MULTIPLIER
                    else:
                        no_of_time_groups = TIMEGROUP_MULTIPLIER
                    debuginfo.append(f"no_of_time_groups = {no_of_time_groups}")

                    # Calculate the TimeGroup time based on the Replay Request Duration
                    timegroup_time_in_secs = replay_request_duration / no_of_time_groups
                    debuginfo.append(f"timegroup_time_in_secs = {timegroup_time_in_secs}")

                    # This represents the absolute time that should be added up for all TimeGroups
                    time_frame_in_time_group = round(total_segment_duration_in_secs / no_of_time_groups, 2)

                    # Create a Dict of time groups with a Start and End time
                    # We will find segments which fall in them next
                    time_groups = []
                    total = 0
                    for x in range(no_of_time_groups):
                        
                        if x == 0:
                            time_groups.append({
                                "TimeGroupStartInSecs": start_of_first_segment_secs,
                                "TimeGroupEndInSecs": start_of_first_segment_secs + time_frame_in_time_group, 
                            })
                            total += start_of_first_segment_secs + time_frame_in_time_group
                        else:
                            time_groups.append({
                                "TimeGroupStartInSecs": total,
                                "TimeGroupEndInSecs": total + time_frame_in_time_group, 
                            })
                            total += time_frame_in_time_group

                    print(time_groups)

                    final_segments_across_timegroups = []
                    # TimeGroups will be Asc Order by Default based on how its Constructed above
                    for timegroup in time_groups:
                        segments_within_timegroup = self._get_segments_with_features_within_timegroup(timegroup)

                        print(f'Calculate Scores based on Weights .. ')
                        self._calculate_segment_scores_basedon_weights(segments_within_timegroup)

                        # After each Segment has been scored, sort them in Desc based on Score
                        sorted_segments = sorted(segments_within_timegroup, key=lambda x: x['Score'], reverse=True)

                        # Find which segments needs to be Removed to meet the Duration Requirements in Replay Request
                        total_duration_all = 0
                        total_duration = 0
                        final_segments = []
                        
                        for segment in sorted_segments:
                            segment_duration = self._get_segment_duration_in_secs(segment)
                            total_duration_all += segment_duration

                            if total_duration + segment_duration <= timegroup_time_in_secs:
                                final_segments.append(segment)
                                total_duration += segment_duration
                            else:
                                print(f"Ignoring the segment - StartTime {segment['Start']}, EndTime {segment['End']} - to avoid exceeding the timegroup duration limit {timegroup_time_in_secs} secs")
                                #debuginfo.append(f"Ignoring the segment - StartTime {segment['Start']}, EndTime {segment['End']} Segment Duration {segment_duration} secs - to avoid exceeding the replay duration limit of {timegroup_time_in_secs} secs.")

                        #debuginfo.append(f"Duration if all segments within this timegroup considered would be {total_duration_all} secs")

                        # Finally Sort the Segments based on the Start time in Asc Order
                        sorted_final_segments = sorted(final_segments, key=lambda x: x['Start'], reverse=False)
                        final_segments_across_timegroups.extend(sorted_final_segments)
                    
                    # Persist all segment+features across all timegroups
                    self._persist_replay_metadata(final_segments_across_timegroups, debuginfo)