Hi.
Yesterday I tried creating custom YoutubePlayer widget.
Since flutterflow has its own widget, which is using YouTube_player_iframe, I did not add any custom dependencies - just used custom widget.
After successful deployment at 3:03PM, I made some tweaks in the custom widget code and since then I can’t deploy successfully - even if I restore to snapshots before the successful deployment.
Test mode works completely normal.
import 'package:flutter/material.dart';
import 'package:youtube_player_iframe/youtube_player_iframe.dart';
// NAJPROSTSZA FUNKCJA DART DO EKSTRAKCJI ID (OPARTA NA SPLIT/SUBSTRING)
String? extractYoutubeId(String url) {
String trimmedUrl = url.trim();
// 1. Obsługa pełnego linku: https://www.youtube.com/watch?v=ID_FILMU
if (trimmedUrl.contains('watch?v=')) {
// Rozdzielamy na dwie części i bierzemy wszystko po '?v='
String id = trimmedUrl.split('watch?v=')[1];
// Usuwamy wszelkie dodatkowe parametry (&list=...)
if (id.contains('&')) {
id = id.substring(0, id.indexOf('&'));
}
return id.length == 11 ? id : null;
}
// 2. Obsługa skróconego linku: https://youtu.be/ID_FILMU
else if (trimmedUrl.contains('youtu.be/')) {
// Rozdzielamy URL po 'youtu.be/' i bierzemy drugą część
String id = trimmedUrl.split('youtu.be/')[1];
// Usuwamy wszelkie dodatkowe parametry
if (id.contains('?')) {
id = id.substring(0, id.indexOf('?'));
}
return id.length == 11 ? id : null;
}
// 3. Obsługa ID (jeśli podano sam ID)
else if (trimmedUrl.length == 11) {
return trimmedUrl;
}
// Zwracamy null dla nieznanych lub nieprawidłowych formatów
return null;
}
class YoutubeIframePlayer extends StatefulWidget {
const YoutubeIframePlayer({
Key? key,
this.width,
this.height,
required this.videoUrl, // Akceptuje cały URL
}) : super(key: key);
final double? width;
final double? height;
final String videoUrl;
@override
State<YoutubeIframePlayer> createState() => _YoutubeIframePlayerState();
}
class _YoutubeIframePlayerState extends State<YoutubeIframePlayer> {
late YoutubePlayerController _controller;
@override
void initState() {
super.initState();
final String? videoId = extractYoutubeId(widget.videoUrl);
_controller = YoutubePlayerController(
params: const YoutubePlayerParams(
showControls: true,
showFullscreenButton: true,
strictRelatedVideos: true,
enableCaption: false,
origin: 'https://www.youtube-nocookie.com'
),
);
if (videoId != null) {
_controller.loadVideoById(videoId: videoId);
} else {
_controller.cueVideoById(videoId: '');
}
}
@override
void didUpdateWidget(covariant YoutubeIframePlayer oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.videoUrl != oldWidget.videoUrl) {
final String? videoId = extractYoutubeId(widget.videoUrl);
if (videoId != null) {
_controller.loadVideoById(videoId: videoId);
}
}
}
@override
void dispose() {
_controller.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
width: widget.width,
height: widget.height,
child: YoutubePlayerScaffold(
controller: _controller,
aspectRatio: 16 / 9,
builder: (context, player) {
return player;
},
),
);
}
}