combineSegmentsToFile method

Future<void> combineSegmentsToFile({
  1. required List<HlsSegmentEntry> segments,
  2. required String segmentDirectoryPath,
  3. required String outputFilePath,
  4. required Map<String, String> customHeaders,
})

Implementation

Future<void> combineSegmentsToFile({
  required List<HlsSegmentEntry> segments,
  required String segmentDirectoryPath,
  required String outputFilePath,
  required Map<String, String> customHeaders,
}) async {
  if (segments.isEmpty) {
    throw const HlsDownloadException(
      code: HlsErrorCode.emptyPlaylist,
      message: 'No segments to combine',
    );
  }

  final encryptionKeys = await _fetchEncryptionKeys(
    segments: segments,
    customHeaders: customHeaders,
  );

  final outputFile = File(outputFilePath);
  if (!await outputFile.parent.exists()) {
    await outputFile.parent.create(recursive: true);
  }

  final sink = outputFile.openWrite(mode: FileMode.write);
  try {
    for (var i = 0; i < segments.length; i++) {
      final segment = segments[i];
      final segmentPath = p.join(
        segmentDirectoryPath,
        segmentFileName(i + 1),
      );
      final segmentFile = File(segmentPath);
      if (!await segmentFile.exists()) {
        throw HlsDownloadException(
          code: HlsErrorCode.segmentMissing,
          message: 'Missing downloaded segment: $segmentPath',
        );
      }

      var bytes = await segmentFile.readAsBytes();
      final keyUriString = segment.encryptionKeyUri?.toString();
      if (keyUriString != null) {
        final keyBytes = encryptionKeys[keyUriString];
        if (keyBytes == null) {
          throw HlsDownloadException(
            code: HlsErrorCode.encryptionKeyFetchFailed,
            message: 'Missing encryption key bytes for $keyUriString',
          );
        }
        bytes = _decryptSegment(
          encryptedBytes: bytes,
          keyBytes: keyBytes,
          sequenceNumber: segment.sequenceNumber,
          ivHex: segment.encryptionIvHex,
        );
      }
      sink.add(bytes);
    }
  } on HlsDownloadException {
    rethrow;
  } catch (error, stackTrace) {
    throw HlsDownloadException(
      code: HlsErrorCode.combineFailed,
      message: 'Failed while combining segments',
      cause: error,
      stackTrace: stackTrace,
    );
  } finally {
    await sink.close();
  }
}