yt_downloader 0.1.0
yt_downloader: ^0.1.0 copied to clipboard
Download YouTube videos with quality selection and automatic video+audio merging.
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:yt_downloader/yt_downloader.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: DownloadPage());
}
}
class DownloadPage extends StatefulWidget {
const DownloadPage({super.key});
@override
State<DownloadPage> createState() => _DownloadPageState();
}
class _DownloadPageState extends State<DownloadPage> {
final _yt = YtDownloader();
final _controller = TextEditingController(text: 'dQw4w9WgXcQ');
VideoInfo? _info;
double _progress = 0;
String _status = '';
Future<void> _fetchFormats() async {
setState(() => _status = 'Fetching formats...');
try {
final info = await _yt.getInfo(_controller.text);
setState(() {
_info = info;
_status = '${info.title}\n'
'${info.formats.videoWithAudio.length} video+audio, '
'${info.formats.videoOnly.length} video-only, '
'${info.formats.audioOnly.length} audio-only';
});
} catch (e) {
setState(() => _status = 'Error: $e');
}
}
Future<void> _download(DownloadFormat format) async {
final dir = await getApplicationDocumentsDirectory();
final path = '${dir.path}/${_info!.videoId}.mp4';
setState(() => _status = 'Downloading ${format.label}...');
try {
await _info!.download(
format: format,
outputPath: path,
onProgress: (p) => setState(() => _progress = p),
);
setState(() => _status = 'Done! Saved to $path');
} catch (e) {
setState(() => _status = 'Error: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('yt_downloader example')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
controller: _controller,
decoration: const InputDecoration(
labelText: 'Video ID or URL',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 8),
ElevatedButton(
onPressed: _fetchFormats,
child: const Text('Get Formats'),
),
const SizedBox(height: 8),
if (_progress > 0)
LinearProgressIndicator(value: _progress),
const SizedBox(height: 8),
Text(_status),
const SizedBox(height: 8),
if (_info != null)
Expanded(
child: ListView(
children: [
for (final f in _info!.formats.videoWithAudio)
ListTile(
title: Text(f.label),
subtitle: Text(
'${f.needsMerge ? "Needs merge" : "Muxed"} '
'${f.estimatedSize > 0 ? "• ${(f.estimatedSize / 1024 / 1024).toStringAsFixed(1)} MB" : ""}',
),
trailing: const Icon(Icons.download),
onTap: () => _download(f),
),
],
),
),
],
),
),
);
}
}