A vertical youtube shorts player. You can choose what shorts will be displayed by passing a list of shorts url's or by passing a channel name. Under the hood the package is using youtube_explode_dart to get youtube video info and media_kit as the player for videos.
- ⦿ Configurations and native permissions
- ⦿ Basic how to use
- ⦿ Video manipulation
- ⦿ Player manipulation
Since the package uses media_kit as it's video player engine, the native configurations of this package are the same configurations of media_kit package. Click here to access the media_kit package native configuration. Please do the configurations for the platforms you pretend to use.
That configurations also includes calling MediaKit.ensureInitialized();
in the main function. Please check documentation.
After macking the configuration, use package:permission_handler
to request access at runtime:
if (/* Android 13 or higher. */) {
// Video permissions.
if (await Permission.videos.isDenied || await Permission.videos.isPermanentlyDenied) {
final state = await Permission.videos.request();
if (!state.isGranted) {
await SystemNavigator.pop();
}
}
// Audio permissions.
if (await Permission.audio.isDenied || await Permission.audio.isPermanentlyDenied) {
final state = await Permission.audio.request();
if (!state.isGranted) {
await SystemNavigator.pop();
}
}
} else {
if (await Permission.storage.isDenied || await Permission.storage.isPermanentlyDenied) {
final state = await Permission.storage.request();
if (!state.isGranted) {
await SystemNavigator.pop();
}
}
}
First, you will need to create a VideosSourceController
that will controll all the video source. There are two constructor of the source controller. From a list of url or from the channel name. Examples are bellow:
You can check a complete implementation of this constructor by clicking here. But bellow is a more short right to the point example:
late final ShortsController controller;
@override
void initState() {
super.initState();
controller = ShortsController(
youtubeVideoInfoService: VideosSourceController.fromUrlList(
videoIds: [
'https://www.youtube.com/shorts/PiWJWfzVwjU',
'https://www.youtube.com/shorts/AeZ3dmC676c',
'https://www.youtube.com/shorts/L1lg_lxUxfw',
'https://www.youtube.com/shorts/OWPsdhLHK7c',
...
],
),
);
}
Will display all videos of a channel with the channelName
.
not
realmadrid.
Take that in mind when using VideosSourceController.fromYoutubeChannel
constructor.
For displaying multiple channels shorts, use
You can check a complete implementation of this constructor by clicking here. But bellow is a more short right to the point example:
late final ShortsController controller;
@override
void initState() {
super.initState();
controller = ShortsController(
youtubeVideoInfoService: VideosSourceController.fromYoutubeChannel(
channelName: 'fcbarcelona',
),
);
}
Simular to VideosSourceController.fromYoutubeChannel
. Inclusive the channel name works the same as well. But instead of using only one channelName you will pass a list of channels name.
VideosSourceController.fromMultiYoutubeChannels
with a list with only one channel. It will work, but it won't be most optimized. The VideosSourceController.fromYoutubeChannel
is specialized and more perfomatic for displaying only one channel shorts.
You can check a complete implementation of this constructor by clicking here. But bellow is a more short right to the point example:
late final ShortsController controller;
@override
void initState() {
super.initState();
controller = ShortsController(
youtubeVideoSourceController: VideosSourceController.fromMultiYoutubeChannels(
channelsName: [
'fcbarcelona',
'realmadridcf',
'atleticodemadrid',
],
),
);
}
Now, we need too add the widget that shows the shorts and will use the controller we just created.
@override
Widget build(BuildContext context) {
return YoutubeShortsPage(
controller: controller,
);
}
Don't forget to dispose the controller after closing the page.
@override
void dispose() {
controller.dispose();
super.dispose();
}
Don't forget to check out the examples of "by url list" and "by channel name" implementations.
If you wan't to display ads during the user slide flow.
In controller, in the parametter named indexsWhereWillContainAds
you can pass in what indexes you wan't to contain ads. In the example bellow, the user will see ads in the third content he scrolled down. And again in the content with index 8. After that, the user will no longer more see content.
ShortsController(
indexsWhereWillContainAds: [3, 8],
youtubeVideoSourceController:
VideosSourceController.fromMultiYoutubeChannelsIds(
channelsIds: getMockedChannelIds(),
),
),
Note: It's called ads builder but you can
YoutubeShortsPage(
controller: controller,
/// Add this parameter:
adsWidgetBuilder: (index, pageController) {
return Container(
color: Colors.red,
child: Center(
child: Text(
'Ad',
style: Theme.of(context)
.textTheme
.titleLarge
?.copyWith(color: Colors.white, fontWeight: FontWeight.w900),
),
),
);
},
)
You can manipulate the player of the current video that is focused (in screen). Bellow are the methods of manipulation
final ShortsController controller = ShortsController(...);
controller.playCurrentVideo(); // Will play if paused
controller.pauseCurrentVideo(); // Will pause if playing
controller.muteCurrentVideo(); // Will mute (set volume to 0)
controller.setVolume(50); // 50% of the volume (0 - 100)
final ShortsController controller = ShortsController(
startWithAutoplay: false, // Default is true
...
);
final ShortsController controller = ShortsController(
videosWillBeInLoop: false, // Default is true
...
);
Some default controllers are in the player (time control, pause/play etc). Those are the media_kit default player controllers. If you wan't to desable/enable them you can controll that by boolean the variable willHaveDefaultShortsControllers
. This is usefull if you wan't to implement your own controllers.
@override
Widget build(BuildContext context) {
willHaveDefaultShortsControllers: false, // No more default controllers on video.
return YoutubeShortsPage(
controller: controller,
);
}
This is usefull if you want to display something like controllers or more.
@override
Widget build(BuildContext context) {
return YoutubeShortsPage(
controller: controller,
overlayWidgetBuilder: (
int index,
PageController pageController,
VideoController videoController,
Video videoData,
MuxedStreamInfo info,
) {
// Example of something you may want to return (this widget bellow does not exist)
return MyCustomDoubleTapToPauseOverlayWidget(
...
);
}
);
}
You can display a widget that will be shown while the video is loading.
@override
Widget build(BuildContext context) {
return YoutubeShortsPage(
controller: controller,
loadingWidget: Center(
child: MyCustomCoolLoadingIndicator(),
)
);
}
You can display a widget that will be shown when a error occours while fetching a video. You will have a error and probably a stacktrace also (can be null).
@override
Widget build(BuildContext context) {
return YoutubeShortsPage(
controller: controller,
errorWidget: (error, stackTrace) {
return Center(
child: MyCustomCoolError(error, stackTrace),
);
},
);
}
videoBuilder
parameter is for macking a wrapper in the player. Of if you can't to have a specific controll of the videoController of each player and wan't to make a controll of it here. child
parameter is the default video widget that is displayed when you don't pass a videoBuilder
. You can use it or not; for example, if you wan't to build your player from scratch, you won't use the child parameter. But if you just want to make a "wrapper" above the player, use this.
@override
Widget build(BuildContext context) {
return YoutubeShortsPage(
controller: controller,
videoBuilder: (
int index,
PageController pageController,
VideoController videoController,
Video videoData,
MuxedStreamInfo hostedVideoInfo,
Widget child,
) {
return Container(
padding: EdgeInsets.all(30),
child: child,
);
},
);
}
Made with ❤ by Igor Miranda
If you like the package, give a 👍