flutter_yt_dlp 0.1.0 copy "flutter_yt_dlp: ^0.1.0" to clipboard
flutter_yt_dlp: ^0.1.0 copied to clipboard

A Flutter plugin for downloading and processing media using yt-dlp and FFmpeg.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_yt_dlp/flutter_yt_dlp.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  FlutterYtDlpPlugin.initialize();
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String status = "Idle";
  double progress = 0.0;

  Future<String> _getOutputDir() async {
    final directory = await getExternalStorageDirectory();
    if (directory == null) {
      throw Exception("Unable to access external storage directory");
    }
    return directory.path;
  }

  Future<bool> _requestStoragePermission() async {
    final status = await Permission.storage.request();
    return status.isGranted;
  }

  Future<void> _downloadSmallestFormat<T>({
    required String url,
    required String originalName,
    required Future<List<T>> Function(String) fetchFormats,
    required String buttonLabel,
  }) async {
    try {
      if (!await _requestStoragePermission()) {
        setState(() => status = "Storage permission denied");
        return;
      }

      final outputDir = await _getOutputDir();
      final formats = await fetchFormats(url);
      if (formats.isEmpty) {
        setState(() => status = "No formats found for $buttonLabel");
        return;
      }

      dynamic smallestFormat;
      if (formats.first is MergeFormat) {
        final mergeFormats = formats.cast<MergeFormat>();
        final videoFormats = mergeFormats.map((f) => f.video).toSet().toList();
        final audioFormats = mergeFormats.map((f) => f.audio).toSet().toList();

        final smallestVideo = videoFormats.reduce((a, b) {
          if (a.size > 0 && b.size > 0) return a.size < b.size ? a : b;
          if (a.size > 0) return a;
          if (b.size > 0) return b;
          final resA = _parseResolution(a.resolution);
          final resB = _parseResolution(b.resolution);
          return resA != resB
              ? (resA < resB ? a : b)
              : (a.bitrate < b.bitrate ? a : b);
        });

        final smallestAudio = audioFormats.reduce((a, b) {
          if (a.size > 0 && b.size > 0) return a.size < b.size ? a : b;
          if (a.size > 0) return a;
          if (b.size > 0) return b;
          return a.bitrate < b.bitrate ? a : b;
        });

        smallestFormat =
            MergeFormat(video: smallestVideo, audio: smallestAudio);
      } else {
        smallestFormat = formats.reduce((a, b) {
          if (a is Format && b is Format) {
            if (a.size > 0 && b.size > 0) return a.size < b.size ? a : b;
            if (a.size > 0) return a;
            if (b.size > 0) return b;
            final resA = _parseResolution(a.resolution);
            final resB = _parseResolution(b.resolution);
            return resA != resB
                ? (resA < resB ? a : b)
                : (a.bitrate < b.bitrate ? a : b);
          }
          throw ArgumentError('Inconsistent format types in list');
        });
      }

      final task = await FlutterYtDlpPlugin.download(
        format: smallestFormat,
        outputDir: outputDir,
        url: url,
        originalName: originalName,
        overwrite: true,
      );

      task.progressStream.listen((p) {
        setState(() {
          progress = p.downloadedBytes / p.totalBytes;
          status =
              "$buttonLabel: ${FlutterYtDlpPlugin.formatBytes(p.downloadedBytes)} / ${FlutterYtDlpPlugin.formatBytes(p.totalBytes)}";
        });
      });

      task.stateStream.listen((s) {
        setState(() {
          status = "$buttonLabel: ${s.toString().split('.').last}";
          if (s == DownloadState.failed) {
            status += " - Download failed";
          } else if (s == DownloadState.canceled) {
            progress = 0.0;
          }
        });
      });
    } catch (e) {
      setState(() => status = "$buttonLabel: Error - $e");
    }
  }

  int _parseResolution(String resolution) {
    if (resolution == 'audio only') return 0;
    final parts = resolution.split('x');
    if (parts.length != 2) return 0;
    final width = int.tryParse(parts[0]) ?? 0;
    final height = int.tryParse(parts[1]) ?? 0;
    return width * height;
  }

  @override
  Widget build(BuildContext context) {
    const url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ";
    const originalName = "RickRoll";

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('FlutterYtDlp Plugin Test')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(status),
              const SizedBox(height: 20),
              LinearProgressIndicator(value: progress),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: () => _downloadSmallestFormat<CombinedFormat>(
                  url: url,
                  originalName: originalName,
                  fetchFormats:
                      FlutterYtDlpPlugin.getAllRawVideoWithSoundFormats,
                  buttonLabel: "Raw Video+Sound",
                ),
                child: const Text("Download Smallest Raw Video+Sound"),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () => _downloadSmallestFormat<MergeFormat>(
                  url: url,
                  originalName: originalName,
                  fetchFormats:
                      FlutterYtDlpPlugin.getRawVideoAndAudioFormatsForMerge,
                  buttonLabel: "Merge Video+Audio",
                ),
                child: const Text("Download Smallest Merge Video+Audio"),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () => _downloadSmallestFormat<CombinedFormat>(
                  url: url,
                  originalName: originalName,
                  fetchFormats: FlutterYtDlpPlugin
                      .getNonMp4VideoWithSoundFormatsForConversion,
                  buttonLabel: "Convert Video+Sound",
                ),
                child: const Text("Download Smallest Convert Video+Sound"),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () => _downloadSmallestFormat<Format>(
                  url: url,
                  originalName: originalName,
                  fetchFormats: FlutterYtDlpPlugin.getAllRawAudioOnlyFormats,
                  buttonLabel: "Raw Audio",
                ),
                child: const Text("Download Smallest Raw Audio"),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () => _downloadSmallestFormat<Format>(
                  url: url,
                  originalName: originalName,
                  fetchFormats:
                      FlutterYtDlpPlugin.getNonMp3AudioOnlyFormatsForConversion,
                  buttonLabel: "Convert Audio",
                ),
                child: const Text("Download Smallest Convert Audio"),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
6
likes
0
points
32
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin for downloading and processing media using yt-dlp and FFmpeg.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, logging, plugin_platform_interface

More

Packages that depend on flutter_yt_dlp

Packages that implement flutter_yt_dlp