download method

Stream download({
  1. required Directory directoryDownload,
  2. required Directory directoryTemporary,
  3. required String youtubeUrl,
  4. required String? output,
  5. required bool isAudioOnly,
  6. required YoutubeVideoDownloadDetail youtubeVideoDownloadDetail,
})

Implementation

Stream download({
  required Directory directoryDownload,
  required Directory directoryTemporary,
  required String youtubeUrl,
  required String? output,
  required bool isAudioOnly,
  required YoutubeVideoDownloadDetail youtubeVideoDownloadDetail,
}) async* {
  final video = await youtubeExplode.videos.get(youtubeUrl);

  final streamManifest = youtubeVideoDownloadDetail.streamManifest;
  final fileName = '${video.title}'
      .replaceAll(r'\', '')
      .replaceAll('/', '')
      .replaceAll('*', '')
      .replaceAll('?', '')
      .replaceAll('"', '')
      .replaceAll('<', '')
      .replaceAll('>', '')
      .replaceAll(':', '')
      .replaceAll('|', '');

  final File fileOutput = File(path.join(
    directoryDownload.path,
    (output ??
            "${((isAudioOnly == true) ? "${video.author}-${fileName}.mp3" : "${fileName}.mp4")}")
        .replaceAll(RegExp("([ ]+)"), "_"),
  ));
  final List<File> files = [];
  if (isAudioOnly == false) {
    {
      final streams = streamManifest.videoOnly;

      final videoStreamInfo = streams.withHighestBitrate();
      final videoStream =
          youtubeExplode.videos.streamsClient.get(videoStreamInfo);
      final file = File(path.join(directoryTemporary.path,
          '${fileName}.video.${videoStreamInfo.container.name}'));

      // Track the file download status.
      final len = videoStreamInfo.size.totalBytes;

      if (file.statSync().size != len) {
        if (file.existsSync()) {
          file.deleteSync(recursive: true);
        }
        await file.create(recursive: true);
        // Open the file in writeAppend.
        final output = file.openWrite(mode: FileMode.writeOnlyAppend);

        int count = file.statSync().size;

        // Create the message and set the cursor position.
        final msg =
            'Downloading ${video.title}.${videoStreamInfo.container.name}';
        stdout.writeln(msg);
        // Listen for data received.
        await for (final data in videoStream) {
          // Keep track of the current downloaded data.
          count += data.length;

          // Calculate the current progress.
          final progress = ((count / len) * 100).ceil();

          print(progress.toStringAsFixed(2));

          // Write to file.
          output.add(data);
        }
        await output.close();
      }
      files.add(file);
    }
  }
  {
    final streams = streamManifest.audioOnly;

    // Get the audio track with the highest bitrate.
    final audio = streams.withHighestBitrate();
    final audioStream = youtubeExplode.videos.streamsClient.get(audio);

    final file = File(path.join(directoryTemporary.path,
        '${fileName}.audio.${audio.container.name}'));
    // Track the file download status.
    final len = audio.size.totalBytes;
    if (file.statSync().size != len) {
      await file.create(recursive: true);
      // Open the file in writeAppend.
      final output = file.openWrite(mode: FileMode.writeOnlyAppend);

      var count = file.statSync().size;

      // Create the message and set the cursor position.
      final msg = 'Downloading ${video.title}.${audio.container.name}';
      stdout.writeln(msg);

      // Listen for data received.
      await for (final data in audioStream) {
        // Keep track of the current downloaded data.
        count += data.length;

        // Calculate the current progress.
        final progress = ((count / len) * 100).ceil();

        print(progress.toStringAsFixed(2));

        // Write to file.
        output.add(data);
      }
      await output.close();
    }
    files.add(file);
  }
  final Process process = await Process.start(
    "ffmpeg",
    [
      if (isAudioOnly) ...[
        "-i",
        files.first.path,
        "-vn",
        "-ar",
        "44100",
        "-ac",
        "2",
        "-b:a",
        "192k",
        fileOutput.path,
      ] else ...[
        "-i",
        files.first.path,
        "-i",
        files.last.path,
        "-c:v",
        "copy",
        "-c:a",
        "aac",
        "-map",
        "0:v:0",
        "-map",
        "1:a:0",
        fileOutput.path,
      ],
    ],
  );
  process.stdout.listen(stdout.add);
  process.stderr.listen(stderr.add);
  final exitCode = await process.exitCode;
  if (exitCode == 0) {
    for (final file in files) {
      await file.delete(recursive: true);
    }
  }
  return;
}