Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/panopto.py (Python)

Code before:
    def _extract_stream(self, video_id, stream, base_info):
        formats = []
        subtitles = {}
        http_stream_url = stream.get('StreamHttpUrl')  # TODO: find test
        stream_url = stream.get('StreamUrl')
        if http_stream_url:
            formats.append({'url': http_stream_url})

        if not stream_url and not http_stream_url:
            return

        media_type = stream.get('ViewerMediaFileTypeName')
        if media_type in ('hls', ):
            m3u8_formats, subtitles = self._extract_m3u8_formats_and_subtitles(stream_url, video_id, 'mp4')
            formats.extend(m3u8_formats)
        else:
            formats.append({
                'url': stream_url
            })
        self._sort_formats(formats)
        tag, title = stream.get('Tag'), base_info.get('title')

        return {
            **base_info,
            'id': stream['PublicID'],
            'title': '{} - {}'.format(title, tag) if tag else title,
            'formats': formats,
            'subtitles': subtitles,
        }

    def _real_extract(self, url):
        mobj = self._match_valid_url(url)
        base_url, video_id = mobj.group('base_url', 'id')
        delivery_info = self._call_api(
            base_url, '/Pages/Viewer/DeliveryInfo.aspx', video_id,
            query={
                'deliveryId': video_id,
                'invocationId': '',
                'isLiveNotes': 'false',
                'refreshAuthCookie': 'true',
                'isActiveBroadcast': 'false',
                'isEditing': 'false',
                'isKollectiveAgentInstalled': 'false',
                'isEmbed': 'false',
                'responseType': 'json',
            }
        )

        delivery = delivery_info['Delivery']
        streams = []
        session_start_time = int_or_none(delivery.get('SessionStartTime'))

Review comment (suggestion):
```suggestion
            'title': join_nonempty(title, tag, delim=' - '),
```

Code after:
                        'ID': 0,
                        'InvocationID': invocation_id,
                        'PlaybackSpeed': 1,
                        'SecondsListened': duration - 1,
                        'SecondsRejected': 0,
                        'StartPosition': 0,
                        'StartReason': 2,
                        'StopReason': None,
                        'StreamID': stream_id,
                        'TimeStamp': timestamp_str,
                        'UpdatesRejected': 0
                    },
                ]}

            self._download_webpage(
                base_url + '/Services/Analytics.svc/AddStreamRequests', video_id,
                fatal=False, data=json.dumps(data).encode('utf8'), headers={'content-type': 'application/json'},
                note='Marking watched', errnote='Unable to mark watched')

    @staticmethod
    def _extract_chapters(delivery):
        chapters = []
        for timestamp in delivery.get('Timestamps', []):
            start, duration = int_or_none(timestamp.get('Time')), int_or_none(timestamp.get('Duration'))
            if start is None or duration is None:
                continue
            chapters.append({
                'start_time': start,
                'end_time': start + duration,
                'title': timestamp.get('Caption')
            })
        return chapters

    def _extract_streams_formats_and_subtitles(self, video_id, streams, **fmt_kwargs):
        formats = []
        subtitles = {}
        for stream in streams or []:
            stream_formats = []
            http_stream_url = stream.get('StreamHttpUrl')
            stream_url = stream.get('StreamUrl')

            if http_stream_url:
                stream_formats.append({'url': http_stream_url})

            if stream_url:
                media_type = stream.get('ViewerMediaFileTypeName')
                if media_type in ('hls', ):
                    m3u8_formats, stream_subtitles = self._extract_m3u8_formats_and_subtitles(stream_url, video_id)
                    stream_formats.extend(m3u8_formats)
                    subtitles = self._merge_subtitles(subtitles, stream_subtitles)
                else: