diff --git a/CHANGELOG.md b/CHANGELOG.md index a28713027..146aa6f97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 0.0.56 +* Fixed empty data source notification issue. +* Fixed WebVTT subtitles parsing issue. +* Fixed memory data source issue on iOS. +* Added videoExtension parameter for memory data source (works only with memory data source). +* Added videoFormat parameter to network data source. +* Fixed controls visible all time on live stream. +* Fixed potential iOS notification crash. + ## 0.0.55 * Dart analysis fix diff --git a/README.md b/README.md index 1d2088090..cc10c3f67 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ This plugin is based on [Chewie](https://github.com/brianegan/chewie). Chewie is ```yaml dependencies: - better_player: ^0.0.55 + better_player: ^0.0.56 ``` 2. Install it @@ -640,6 +640,9 @@ Possible configuration options: ///Video format hint when data source url has not valid extension. final BetterPlayerVideoFormat videoFormat; + + ///Extension of video without dot. Used only in memory data source. + final String videoExtension; ``` diff --git a/example/assets/example_subtitles.srt b/example/assets/example_subtitles.srt index 6dd3579fe..cd05edc94 100644 --- a/example/assets/example_subtitles.srt +++ b/example/assets/example_subtitles.srt @@ -1,5 +1,3 @@ -WEBVTT - 1 00:00:00.000 --> 00:00:02.000 Welcome to Better Player diff --git a/example/lib/pages/memory_player_page.dart b/example/lib/pages/memory_player_page.dart index 975e4e08d..0799e95ac 100644 --- a/example/lib/pages/memory_player_page.dart +++ b/example/lib/pages/memory_player_page.dart @@ -31,7 +31,8 @@ class _MemoryPlayerPageState extends State { File file = File(filePath); List bytes = file.readAsBytesSync().buffer.asUint8List(); - BetterPlayerDataSource dataSource = BetterPlayerDataSource.memory(bytes); + BetterPlayerDataSource dataSource = + BetterPlayerDataSource.memory(bytes, videoExtension: "mp4"); _betterPlayerController.setupDataSource(dataSource); } diff --git a/ios/Classes/FLTBetterPlayerPlugin.m b/ios/Classes/FLTBetterPlayerPlugin.m index ee6b3d609..5b88b4835 100644 --- a/ios/Classes/FLTBetterPlayerPlugin.m +++ b/ios/Classes/FLTBetterPlayerPlugin.m @@ -982,28 +982,35 @@ - (void) setupRemoteCommandNotification:(FLTBetterPlayer*)player, NSString* titl NSString* key = [self getTextureId:player]; MPMediaItemArtwork* artworkImage = [_artworkImageDict objectForKey:key]; - if (artworkImage){ - [nowPlayingInfoDict setObject:artworkImage forKey:MPMediaItemPropertyArtwork]; - [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = nowPlayingInfoDict; - - } else { - dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - dispatch_async(queue, ^{ - UIImage * tempArtworkImage = nil; - if ([imageUrl rangeOfString:@"http"].location == NSNotFound){ - tempArtworkImage = [UIImage imageWithContentsOfFile:imageUrl]; - } else { - NSURL *nsImageUrl =[NSURL URLWithString:imageUrl]; - tempArtworkImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:nsImageUrl]]; - } - if(tempArtworkImage) - { - MPMediaItemArtwork* artworkImage = [[MPMediaItemArtwork alloc] initWithImage: tempArtworkImage]; - [_artworkImageDict setObject:artworkImage forKey:key]; - [nowPlayingInfoDict setObject:artworkImage forKey:MPMediaItemPropertyArtwork]; - } + if (key != [NSNull null]){ + if (artworkImage){ + [nowPlayingInfoDict setObject:artworkImage forKey:MPMediaItemPropertyArtwork]; [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = nowPlayingInfoDict; - }); + + } else { + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async(queue, ^{ + @try{ + UIImage * tempArtworkImage = nil; + if ([imageUrl rangeOfString:@"http"].location == NSNotFound){ + tempArtworkImage = [UIImage imageWithContentsOfFile:imageUrl]; + } else { + NSURL *nsImageUrl =[NSURL URLWithString:imageUrl]; + tempArtworkImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:nsImageUrl]]; + } + if(tempArtworkImage) + { + MPMediaItemArtwork* artworkImage = [[MPMediaItemArtwork alloc] initWithImage: tempArtworkImage]; + [_artworkImageDict setObject:artworkImage forKey:key]; + [nowPlayingInfoDict setObject:artworkImage forKey:MPMediaItemPropertyArtwork]; + } + [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = nowPlayingInfoDict; + } + @catch(NSException *exception) { + + } + }); + } } } else { [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = nowPlayingInfoDict; @@ -1011,6 +1018,7 @@ - (void) setupRemoteCommandNotification:(FLTBetterPlayer*)player, NSString* titl } + - (NSString*) getTextureId: (FLTBetterPlayer*) player{ NSArray* temp = [_players allKeysForObject: player]; NSString* key = [temp lastObject]; diff --git a/lib/src/configuration/better_player_data_source.dart b/lib/src/configuration/better_player_data_source.dart index 516184d75..d01dbb1f3 100644 --- a/lib/src/configuration/better_player_data_source.dart +++ b/lib/src/configuration/better_player_data_source.dart @@ -1,4 +1,5 @@ // Project imports: + import 'package:better_player/src/configuration/better_player_data_source_type.dart'; import 'package:better_player/src/configuration/better_player_notification_configuration.dart'; import 'package:better_player/src/configuration/better_player_video_format.dart'; @@ -58,6 +59,9 @@ class BetterPlayerDataSource { ///Video format hint when data source url has not valid extension. final BetterPlayerVideoFormat videoFormat; + ///Extension of video without dot. Used only in memory data source. + final String videoExtension; + BetterPlayerDataSource( this.type, this.url, { @@ -75,6 +79,7 @@ class BetterPlayerDataSource { const BetterPlayerNotificationConfiguration(showNotification: false), this.overriddenDuration, this.videoFormat, + this.videoExtension, }) : assert( ((type == BetterPlayerDataSourceType.network || type == BetterPlayerDataSourceType.file) && @@ -97,6 +102,7 @@ class BetterPlayerDataSource { BetterPlayerCacheConfiguration cacheConfiguration, BetterPlayerNotificationConfiguration notificationConfiguration, Duration overriddenDuration, + BetterPlayerVideoFormat videoFormat, }) { return BetterPlayerDataSource( BetterPlayerDataSourceType.network, @@ -111,6 +117,7 @@ class BetterPlayerDataSource { cacheConfiguration: cacheConfiguration, notificationConfiguration: notificationConfiguration, overriddenDuration: overriddenDuration, + videoFormat: videoFormat, ); } @@ -140,6 +147,7 @@ class BetterPlayerDataSource { ///Url parameter is not used in this data source. factory BetterPlayerDataSource.memory( List bytes, { + String videoExtension, List subtitles, bool useHlsSubtitles, bool useHlsTracks, @@ -148,15 +156,19 @@ class BetterPlayerDataSource { BetterPlayerNotificationConfiguration notificationConfiguration, Duration overriddenDuration, }) { - return BetterPlayerDataSource(BetterPlayerDataSourceType.memory, "", - bytes: bytes, - subtitles: subtitles, - useHlsSubtitles: useHlsSubtitles, - useHlsTracks: useHlsTracks, - resolutions: qualities, - cacheConfiguration: cacheConfiguration, - notificationConfiguration: notificationConfiguration, - overriddenDuration: overriddenDuration); + return BetterPlayerDataSource( + BetterPlayerDataSourceType.memory, + "", + videoExtension: videoExtension, + bytes: bytes, + subtitles: subtitles, + useHlsSubtitles: useHlsSubtitles, + useHlsTracks: useHlsTracks, + resolutions: qualities, + cacheConfiguration: cacheConfiguration, + notificationConfiguration: notificationConfiguration, + overriddenDuration: overriddenDuration, + ); } BetterPlayerDataSource copyWith({ @@ -173,6 +185,8 @@ class BetterPlayerDataSource { BetterPlayerCacheConfiguration cacheConfiguration, BetterPlayerNotificationConfiguration notificationConfiguration, Duration overriddenDuration, + BetterPlayerVideoFormat videoFormat, + String videoExtension, }) { return BetterPlayerDataSource( type ?? this.type, @@ -189,6 +203,8 @@ class BetterPlayerDataSource { notificationConfiguration: notificationConfiguration ?? this.notificationConfiguration, overriddenDuration: overriddenDuration ?? this.overriddenDuration, + videoFormat: videoFormat ?? this.videoFormat, + videoExtension: videoExtension ?? this.videoExtension, ); } } diff --git a/lib/src/controls/better_player_controls_state.dart b/lib/src/controls/better_player_controls_state.dart index eb676ca67..beaad36c6 100644 --- a/lib/src/controls/better_player_controls_state.dart +++ b/lib/src/controls/better_player_controls_state.dart @@ -29,6 +29,8 @@ abstract class BetterPlayerControlsState bool isVideoFinished(VideoPlayerValue videoPlayerValue) { return videoPlayerValue?.position != null && videoPlayerValue?.duration != null && + videoPlayerValue.position.inMilliseconds != 0 && + videoPlayerValue.duration.inMilliseconds != 0 && videoPlayerValue.position >= videoPlayerValue.duration; } diff --git a/lib/src/core/better_player_controller.dart b/lib/src/core/better_player_controller.dart index 467c5f331..9ae6851c6 100644 --- a/lib/src/core/better_player_controller.dart +++ b/lib/src/core/better_player_controller.dart @@ -243,6 +243,8 @@ class BetterPlayerController extends ChangeNotifier { ///Process data source await _setupDataSource(betterPlayerDataSource); + + notifyListeners(); } ///Configure subtitles based on subtitles source. @@ -384,7 +386,8 @@ class BetterPlayerController extends ChangeNotifier { ); break; case BetterPlayerDataSourceType.memory: - final file = await _createFile(_betterPlayerDataSource.bytes); + final file = await _createFile(_betterPlayerDataSource.bytes, + extension: _betterPlayerDataSource.videoExtension); if (file != null) { await videoPlayerController.setFileDataSource( @@ -414,9 +417,10 @@ class BetterPlayerController extends ChangeNotifier { ///Create file from provided list of bytes. File will be created in temporary ///directory. - Future _createFile(List bytes) async { + Future _createFile(List bytes, {String extension = "temp"}) async { final String dir = (await getTemporaryDirectory()).path; - final File temp = File('$dir/better_player_${DateTime.now()}.temp'); + final File temp = File( + '$dir/better_player_${DateTime.now().millisecondsSinceEpoch}.$extension'); await temp.writeAsBytes(bytes); return temp; } @@ -707,7 +711,9 @@ class BetterPlayerController extends ChangeNotifier { _postEvent( BetterPlayerEvent(BetterPlayerEventType.changedPlayerVisibility)); - if (!_betterPlayerDataSource.notificationConfiguration.showNotification && + if (!(_betterPlayerDataSource + ?.notificationConfiguration?.showNotification == + true) && betterPlayerConfiguration.handleLifecycle) { if (betterPlayerConfiguration.playerVisibilityChangedBehavior != null) { betterPlayerConfiguration diff --git a/lib/src/core/better_player_with_controls.dart b/lib/src/core/better_player_with_controls.dart index 0213b7ec5..8288a11b7 100644 --- a/lib/src/core/better_player_with_controls.dart +++ b/lib/src/core/better_player_with_controls.dart @@ -62,11 +62,11 @@ class _BetterPlayerWithControlsState extends State { } void _onControllerChanged() { - if (!_initalized) { - setState(() { + setState(() { + if (!_initalized) { _initalized = true; - }); - } + } + }); } @override diff --git a/lib/src/subtitles/better_player_subtitle.dart b/lib/src/subtitles/better_player_subtitle.dart index cdcea5bc6..6979f8c67 100644 --- a/lib/src/subtitles/better_player_subtitle.dart +++ b/lib/src/subtitles/better_player_subtitle.dart @@ -18,14 +18,14 @@ class BetterPlayerSubtitle { this.type, }); - factory BetterPlayerSubtitle(String value) { + factory BetterPlayerSubtitle(String value, bool isWebVTT) { try { final scanner = value.split('\n'); if (scanner.length == 2) { return _handle2LinesSubtitles(scanner); } if (scanner.length > 2) { - return _handle3LinesAndMoreSubtitles(scanner); + return _handle3LinesAndMoreSubtitles(scanner, isWebVTT); } return BetterPlayerSubtitle._(); } catch (exception) { @@ -50,21 +50,27 @@ class BetterPlayerSubtitle { } static BetterPlayerSubtitle _handle3LinesAndMoreSubtitles( - List scanner) { + List scanner, bool isWebVTT) { try { - if (scanner[0].isEmpty) { - scanner.removeAt(0); + if (isWebVTT) { + final timeSplit = scanner[0].split(timerSeparator); + final start = _stringToDuration(timeSplit[0]); + final end = _stringToDuration(timeSplit[1]); + final texts = scanner.sublist(1, scanner.length); + return BetterPlayerSubtitle._( + index: -1, start: start, end: end, texts: texts); + } else { + if (scanner[0].isEmpty) { + scanner.removeAt(0); + } + final index = int.tryParse(scanner[0]); + final timeSplit = scanner[1].split(timerSeparator); + final start = _stringToDuration(timeSplit[0]); + final end = _stringToDuration(timeSplit[1]); + final texts = scanner.sublist(2, scanner.length); + return BetterPlayerSubtitle._( + index: index, start: start, end: end, texts: texts); } - - final index = int.tryParse(scanner[0]); - - final timeSplit = scanner[1].split(timerSeparator); - final start = _stringToDuration(timeSplit[0]); - final end = _stringToDuration(timeSplit[1]); - final texts = scanner.sublist(2, scanner.length); - - return BetterPlayerSubtitle._( - index: index, start: start, end: end, texts: texts); } catch (exception) { BetterPlayerUtils.log("Failed to parse subtitle line: $scanner"); return BetterPlayerSubtitle._(); diff --git a/lib/src/subtitles/better_player_subtitles_factory.dart b/lib/src/subtitles/better_player_subtitles_factory.dart index 9aa6c625c..a85ab106e 100644 --- a/lib/src/subtitles/better_player_subtitles_factory.dart +++ b/lib/src/subtitles/better_player_subtitles_factory.dart @@ -90,11 +90,12 @@ class BetterPlayerSubtitlesFactory { final List subtitlesObj = []; + final bool isWebVTT = components.contains("WEBVTT"); for (final component in components) { if (component.isEmpty) { continue; } - final subtitle = BetterPlayerSubtitle(component); + final subtitle = BetterPlayerSubtitle(component, isWebVTT); if (subtitle != null && subtitle.start != null && subtitle.end != null && diff --git a/pubspec.yaml b/pubspec.yaml index 7e03af15e..8464e10a5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: better_player description: Advanced video player based on video_player and Chewie. It's solves many typical use cases and it's easy to run. -version: 0.0.55 +version: 0.0.56 authors: - Jakub Homlala homepage: https://github.com/jhomlala/betterplayer