flutter_ytdlp_plugin 0.0.5
flutter_ytdlp_plugin: ^0.0.5 copied to clipboard
A Flutter plugin for YouTube video streaming using yt-dlp. Supports fetching video formats, related videos, and more.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_ytdlp_plugin/flutter_ytdlp_plugin.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'YT-DLP Plugin Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: YTDLPClass(),
);
}
}
class YTDLPClass extends StatefulWidget {
const YTDLPClass({super.key});
@override
State<YTDLPClass> createState() => _YTDLPExamplePageState();
}
class _YTDLPExamplePageState extends State<YTDLPClass> {
final ytdlp = FlutterYtdlpPlugin();
String output = 'Initializing...';
bool isInitialized = false;
@override
void initState() {
super.initState();
_initializePlugin();
}
Future<void> _initializePlugin() async {
try {
await ytdlp.initialize();
setState(() {
isInitialized = true;
output = 'YT-DLP Initialized Successfully!';
});
} catch (e) {
setState(() {
isInitialized = false;
output = 'Initialization failed: $e';
});
}
}
Future<void> testGetStreamingLinks() async {
try {
final links = await FlutterYtdlpPlugin.getStreamingLinks(
title: "Flutter Tutorial",
channelName: "Flutter",
);
setState(() {
output = 'Streaming Links:\n${links.toString()}';
});
} catch (e) {
setState(() => output = 'Error: $e');
}
}
Future<void> testGetVideoDetails() async {
try {
final details = await FlutterYtdlpPlugin.getVideoDetailsWithFormats(
videoId: "dQw4w9WgXcQ", // Example video ID
);
setState(() {
output = 'Video Details:\n${details.toString()}';
});
} catch (e) {
setState(() => output = 'Error: $e');
}
}
Future<void> testSearchVideos() async {
try {
final results = await FlutterYtdlpPlugin.searchVideos(
query: "Flutter Tutorial",
maxResults: 5,
);
setState(() {
output = 'Search Results (${results.length}):\n';
for (var video in results.take(3)) {
// output += '${video.title}\n'; Can get upto 20 video details at once
}
});
} catch (e) {
setState(() => output = 'Error: $e');
}
}
Future<void> testGetTrendingVideos() async {
try {
final videos = await FlutterYtdlpPlugin.getTrendingVideos(count: 5);
setState(() {
output = 'Trending Videos (${videos.length}):\n';
for (var video in videos.take(3)) {
// output += '${video.title}\n'; Can get upto 200 video details at once
}
});
} catch (e) {
setState(() => output = 'Error: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('YT-DLP Plugin Demo')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Expanded(child: SingleChildScrollView(child: Text(output))),
const SizedBox(height: 20),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton(
onPressed: testGetStreamingLinks,
child: const Text('Get Streaming Links'),
),
ElevatedButton(
onPressed: testGetVideoDetails,
child: const Text('Get Video Details'),
),
ElevatedButton(
onPressed: testSearchVideos,
child: const Text('Search Videos'),
),
ElevatedButton(
onPressed: testGetTrendingVideos,
child: const Text('Get Trending'),
),
],
),
],
),
),
);
}
}
// Model Classes aligned with the output of above methods
// ==================================================================================================================
// ==================================================================================================================
// ==================================================================================================================
// ==================================================================================================================
// ==================================================================================================================
/// Represents a video stream format with all technical details
/// Example: 1080p MP4 stream with H.264 codec
class VideoFormat {
final String formatId; // Unique identifier for this format (e.g., "137")
final String url; // Direct URL to the video stream
final String ext; // File extension (e.g., "mp4", "webm")
final int quality; // Quality score (higher is better)
final String resolution; // Display resolution (e.g., "1920x1080")
final int height; // Video height in pixels
final int width; // Video width in pixels
final int fps; // Frames per second
final int filesize; // File size in bytes
final int tbr; // Total bitrate (kbps)
final int vbr; // Video bitrate (kbps)
final int abr; // Audio bitrate (kbps)
final String acodec; // Audio codec (e.g., "mp4a.40.2")
final String vcodec; // Video codec (e.g., "avc1.640028")
final String formatNote; // Human-readable format description
final String protocol; // Streaming protocol (e.g., "https")
VideoFormat({
required this.formatId,
required this.url,
required this.ext,
required this.quality,
required this.resolution,
required this.height,
required this.width,
required this.fps,
required this.filesize,
required this.tbr,
required this.vbr,
required this.abr,
required this.acodec,
required this.vcodec,
required this.formatNote,
required this.protocol,
});
/// Example:
/// {
/// "formatId": "137",
/// "url": "https://example.com/video.mp4",
/// "ext": "mp4",
/// "quality": 1080,
/// "resolution": "1920x1080",
/// "height": 1080,
/// "width": 1920,
/// "fps": 30,
/// "filesize": 25678900,
/// "tbr": 1500,
/// "vbr": 1350,
/// "abr": 150,
/// "acodec": "mp4a.40.2",
/// "vcodec": "avc1.640028",
/// "formatNote": "1080p",
/// "protocol": "https"
/// }
factory VideoFormat.fromJson(Map<String, dynamic> json) => VideoFormat(
formatId: json['formatId'] ?? '',
url: json['url'] ?? '',
ext: json['ext'] ?? '',
quality: json['quality'] ?? 0,
resolution: json['resolution'] ?? '',
height: json['height'] ?? 0,
width: json['width'] ?? 0,
fps: json['fps'] ?? 0,
filesize: json['filesize'] ?? 0,
tbr: json['tbr'] ?? 0,
vbr: json['vbr'] ?? 0,
abr: json['abr'] ?? 0,
acodec: json['acodec'] ?? '',
vcodec: json['vcodec'] ?? '',
formatNote: json['formatNote'] ?? '',
protocol: json['protocol'] ?? '',
);
}
// ==================================================================================================================
/// Represents an audio-only stream format
/// Example: 256kbps AAC audio stream
class AudioFormat {
final String formatId; // Unique format identifier (e.g., "140")
final String url; // Direct URL to audio stream
final String ext; // File extension (e.g., "m4a")
final int abr; // Audio bitrate in kbps
final String acodec; // Audio codec (e.g., "mp4a.40.2")
final String formatNote; // Description (e.g., "medium quality")
final String protocol; // Protocol used (e.g., "https")
AudioFormat({
required this.formatId,
required this.url,
required this.ext,
required this.abr,
required this.acodec,
required this.formatNote,
required this.protocol,
});
/// Example:
/// {
/// "formatId": "140",
/// "url": "https://example.com/audio.m4a",
/// "ext": "m4a",
/// "abr": 256,
/// "acodec": "mp4a.40.2",
/// "formatNote": "256k",
/// "protocol": "https"
/// }
factory AudioFormat.fromJson(Map<String, dynamic> json) => AudioFormat(
formatId: json['formatId'] ?? '',
url: json['url'] ?? '',
ext: json['ext'] ?? '',
abr: json['abr'] ?? 0,
acodec: json['acodec'] ?? '',
formatNote: json['formatNote'] ?? '',
protocol: json['protocol'] ?? '',
);
}
// ==================================================================================================================
/// Contains complete information about a video including all available formats
/// Example: YouTube video metadata with 5 format options
class VideoInfo {
final String videoId; // Unique video identifier
final String title; // Video title
final String? channelName; // Uploader channel name
final String? channelId; // Uploader channel ID
final int? duration; // Duration in seconds
final int? viewCount; // Total views
final String? uploadDate; // Upload date (ISO format)
final String? thumbnail; // URL to thumbnail image
final String? description; // Video description
final String? webpageUrl; // Original page URL
final String? originalUrl; // Source URL if different
final String timestamp; // When this info was fetched
final List<VideoFormat>? videoFormats; // Available video formats
final List<AudioFormat>? audioFormats; // Available audio-only formats
VideoInfo({
required this.videoId,
required this.title,
this.channelName,
this.channelId,
this.duration,
this.viewCount,
this.uploadDate,
this.thumbnail,
this.description,
this.webpageUrl,
this.originalUrl,
required this.timestamp,
this.videoFormats,
this.audioFormats,
});
/// Example:
/// {
/// "videoId": "dQw4w9WgXcQ",
/// "title": "Never Gonna Give You Up",
/// "channelName": "Rick Astley",
/// "duration": 213,
/// "viewCount": 1500000000,
/// "thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
/// "videoFormats": [...],
/// "audioFormats": [...]
/// }
factory VideoInfo.fromJson(Map<String, dynamic> json) => VideoInfo(
videoId: json['videoId'] ?? '',
title: json['title'] ?? '',
channelName: json['channelName'],
channelId: json['channelId'],
duration: json['duration'],
viewCount: json['viewCount'],
uploadDate: json['uploadDate'],
thumbnail: json['thumbnail'],
description: json['description'],
webpageUrl: json['webpageUrl'],
originalUrl: json['originalUrl'],
timestamp: json['timestamp'] ?? DateTime.now().toIso8601String(),
videoFormats: (json['videoFormats'] as List?)
?.map((e) => VideoFormat.fromJson(e))
.toList(),
audioFormats: (json['audioFormats'] as List?)
?.map((e) => AudioFormat.fromJson(e))
.toList(),
);
}
// ==================================================================================================================
/// Pre-selected best quality URLs for quick access
/// Example: Pre-filtered 1080p video + 256k audio URLs
class BestFormatUrls {
final String videoId; // Original video ID
final String title; // Video title
final String? bestVideoUrl; // Highest quality video URL
final String? bestAudioUrl; // Highest quality audio URL
final String? bestCombinedUrl; // Best combined stream URL
final int formatsAvailable; // Total formats found
BestFormatUrls({
required this.videoId,
required this.title,
this.bestVideoUrl,
this.bestAudioUrl,
this.bestCombinedUrl,
required this.formatsAvailable,
});
/// Example:
/// {
/// "videoId": "dQw4w9WgXcQ",
/// "bestVideoUrl": "https://example.com/video_1080.mp4",
/// "bestAudioUrl": "https://example.com/audio_256k.m4a",
/// "formatsAvailable": 12
/// }
factory BestFormatUrls.fromJson(Map<String, dynamic> json) => BestFormatUrls(
videoId: json['videoId'] ?? '',
title: json['title'] ?? '',
bestVideoUrl: json['bestVideoUrl'],
bestAudioUrl: json['bestAudioUrl'],
bestCombinedUrl: json['bestCombinedUrl'],
formatsAvailable: json['formatsAvailable'] ?? 0,
);
}
// ==================================================================================================================
/// Represents a video search result
/// Example: YouTube search result item
class SearchResult {
final String videoId; // Unique video ID
final String title; // Video title
final String? channelName; // Channel name
final String? channelId; // Channel ID
final String? thumbnail; // Thumbnail URL
final int? duration; // Duration in seconds
final int? viewCount; // View count
final String? uploadDate; // Upload date (ISO)
final String? webpageUrl; // Original page URL
final String? searchQuery; // Query that found this
final int? searchRank; // Position in results
SearchResult({
required this.videoId,
required this.title,
this.channelName,
this.channelId,
this.thumbnail,
this.duration,
this.viewCount,
this.uploadDate,
this.webpageUrl,
this.searchQuery,
this.searchRank,
});
/// Example:
/// {
/// "videoId": "dQw4w9WgXcQ",
/// "title": "Never Gonna Give You Up",
/// "channelName": "Rick Astley",
/// "duration": 213,
/// "searchRank": 1
/// }
factory SearchResult.fromJson(Map<String, dynamic> json) => SearchResult(
videoId: json['videoId'] ?? '',
title: json['title'] ?? '',
channelName: json['channelName'],
channelId: json['channelId'],
thumbnail: json['thumbnail'],
duration: json['duration'],
viewCount: json['viewCount'],
uploadDate: json['uploadDate'],
webpageUrl: json['webpageUrl'],
searchQuery: json['searchQuery'],
searchRank: json['searchRank'],
);
}
// ==================================================================================================================
/// Represents a video related to another video
/// Example: "Recommended" or "Up next" videos
class RelatedVideo {
final String videoId; // Unique video ID
final String title; // Video title
final String? channelName; // Channel name
final String? channelId; // Channel ID
final String? thumbnail; // Thumbnail URL
final int? duration; // Duration in seconds
final int? viewCount; // View count
final String? uploadDate; // Upload date (ISO)
final String? webpageUrl; // Original page URL
RelatedVideo({
required this.videoId,
required this.title,
this.channelName,
this.channelId,
this.thumbnail,
this.duration,
this.viewCount,
this.uploadDate,
this.webpageUrl,
});
/// Example:
/// {
/// "videoId": "dQw4w9WgXcQ",
/// "title": "Never Gonna Give You Up",
/// "channelName": "Rick Astley"
/// }
factory RelatedVideo.fromJson(Map<String, dynamic> json) => RelatedVideo(
videoId: json['videoId'] ?? '',
title: json['title'] ?? '',
channelName: json['channelName'],
channelId: json['channelId'],
thumbnail: json['thumbnail'],
duration: json['duration'],
viewCount: json['viewCount'],
uploadDate: json['uploadDate'],
webpageUrl: json['webpageUrl'],
);
}
// ==================================================================================================================
/// Represents a randomly selected video
/// Example: Video from discovery/recommendation system
class RandomVideo {
final String videoId; // Unique video ID
final String title; // Video title
final String? channelName; // Channel name
final String? channelId; // Channel ID
final String? thumbnail; // Thumbnail URL
final int? duration; // Duration in seconds
final int? viewCount; // View count
final String? uploadDate; // Upload date (ISO)
final String? category; // Content category
final String? searchTerm; // Term used to find this
final String? webpageUrl; // Original page URL
RandomVideo({
required this.videoId,
required this.title,
this.channelName,
this.channelId,
this.thumbnail,
this.duration,
this.viewCount,
this.uploadDate,
this.category,
this.searchTerm,
this.webpageUrl,
});
/// Example:
/// {
/// "videoId": "dQw4w9WgXcQ",
/// "title": "Never Gonna Give You Up",
/// "category": "Music"
/// }
factory RandomVideo.fromJson(Map<String, dynamic> json) => RandomVideo(
videoId: json['videoId'] ?? '',
title: json['title'] ?? '',
channelName: json['channelName'],
channelId: json['channelId'],
thumbnail: json['thumbnail'],
duration: json['duration'],
viewCount: json['viewCount'],
uploadDate: json['uploadDate'],
category: json['category'],
searchTerm: json['searchTerm'],
webpageUrl: json['webpageUrl'],
);
}
// ==================================================================================================================
/// Represents a trending/popular video
/// Example: Currently viral video
class TrendingVideo {
final String videoId; // Unique video ID
final String title; // Video title
final String? channelName; // Channel name
final String? channelId; // Channel ID
final String? thumbnail; // Thumbnail URL
final int? duration; // Duration in seconds
final int? viewCount; // View count
final String? uploadDate; // Upload date (ISO)
final String? trendingQuery; // Trending category
final bool isTrending; // Currently trending flag
final String? webpageUrl; // Original page URL
TrendingVideo({
required this.videoId,
required this.title,
this.channelName,
this.channelId,
this.thumbnail,
this.duration,
this.viewCount,
this.uploadDate,
this.trendingQuery,
required this.isTrending,
this.webpageUrl,
});
/// Example:
/// {
/// "videoId": "dQw4w9WgXcQ",
/// "title": "Never Gonna Give You Up",
/// "isTrending": true,
/// "trendingQuery": "Music"
/// }
factory TrendingVideo.fromJson(Map<String, dynamic> json) => TrendingVideo(
videoId: json['videoId'] ?? '',
title: json['title'] ?? '',
channelName: json['channelName'],
channelId: json['channelId'],
thumbnail: json['thumbnail'],
duration: json['duration'],
viewCount: json['viewCount'],
uploadDate: json['uploadDate'],
trendingQuery: json['trendingQuery'],
isTrending: json['isTrending'] ?? false,
webpageUrl: json['webpageUrl'],
);
}
// ==================================================================================================================
// ==================================================================================================================
// ==================================================================================================================
// ==================================================================================================================
// ==================================================================================================================