diff --git a/lib/src/playlists/playlist_id.dart b/lib/src/playlists/playlist_id.dart index 8f58c00..15b2063 100644 --- a/lib/src/playlists/playlist_id.dart +++ b/lib/src/playlists/playlist_id.dart @@ -6,8 +6,8 @@ import '../extensions/helpers_extension.dart'; class PlaylistId with EquatableMixin { static final _regMatchExp = RegExp(r'youtube\..+?/playlist.*?list=(.*?)(?:&|/|$)'); - static final _compositeMatchExp = RegExp( - 'https://www.youtube.com/watch?v=b8m9zhNAgKs&list=PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr'); + static final _compositeMatchExp = + RegExp(r'youtube\..+?/watch.*?list=(.*?)(?:&|/|$)'); static final _shortCompositeMatchExp = RegExp(r'youtu\.be/.*?/.*?list=(.*?)(?:&|/|$)'); static final _embedCompositeMatchExp = diff --git a/lib/src/reverse_engineering/responses/embed_page.dart b/lib/src/reverse_engineering/responses/embed_page.dart index e4e79d7..8f94350 100644 --- a/lib/src/reverse_engineering/responses/embed_page.dart +++ b/lib/src/reverse_engineering/responses/embed_page.dart @@ -9,8 +9,7 @@ import '../youtube_http_client.dart'; /// class EmbedPage { - static final _playerConfigExp = - RegExp(r"'PLAYER_CONFIG':\s*(\{.*\})\}"); + static final _playerConfigExp = RegExp(r"'PLAYER_CONFIG':\s*(\{.*\})\}"); final Document _root; _PlayerConfig _playerConfig; diff --git a/lib/src/reverse_engineering/responses/search_page.dart b/lib/src/reverse_engineering/responses/search_page.dart index c4db305..10aa5f8 100644 --- a/lib/src/reverse_engineering/responses/search_page.dart +++ b/lib/src/reverse_engineering/responses/search_page.dart @@ -34,18 +34,32 @@ class SearchPage { _InitialData _initialData; /// - _InitialData get initialData => - _initialData ??= _InitialData(SearchPageId.fromRawJson(_extractJson( - _root - .querySelectorAll('script') - .map((e) => e.text) - .toList() - .firstWhere((e) => e.contains('window["ytInitialData"] =')), - 'window["ytInitialData"] ='))); + _InitialData get initialData { + if (_initialData != null) { + return _initialData; + } + var scriptTag = _extractJson( + _root.querySelectorAll('script').map((e) => e.text).toList().firstWhere( + (e) => e.contains('window["ytInitialData"] ='), + orElse: () => null), + 'window["ytInitialData"] ='); + scriptTag ??= _extractJson( + _root.querySelectorAll('script').map((e) => e.text).toList().firstWhere( + (e) => e.contains('var ytInitialData ='), + orElse: () => '{}'), + 'var ytInitialData ='); + return _initialData ??= _InitialData(SearchPageId.fromRawJson(scriptTag)); + } String _extractJson(String html, String separator) { - return _matchJson( - html.substring(html.indexOf(separator) + separator.length)); + if (html == null || separator == null) { + return null; + } + var index = html.indexOf(separator) + separator.length; + if (index > html.length) { + return null; + } + return _matchJson(html.substring(index)); } String _matchJson(String str) { @@ -143,7 +157,7 @@ class _InitialData { return root.onResponseReceivedCommands.first.appendContinuationItemsAction .continuationItems[0].itemSectionRenderer.contents; } - throw FatalFailureException('Failed to get initial data context.'); + return null; } String _getContinuationToken() { diff --git a/lib/src/reverse_engineering/responses/watch_page.dart b/lib/src/reverse_engineering/responses/watch_page.dart index 918981a..f6f826f 100644 --- a/lib/src/reverse_engineering/responses/watch_page.dart +++ b/lib/src/reverse_engineering/responses/watch_page.dart @@ -89,8 +89,8 @@ class WatchPage { static final _playerConfigExp = RegExp(r'ytplayer\.config\s*=\s*(\{.*\}\});'); /// - _PlayerConfig get playerConfig => - _playerConfig ??= _PlayerConfig(json.decode(_playerConfigExp + _PlayerConfig get playerConfig => _playerConfig ??= _PlayerConfig( + PlayerConfigJson.fromRawJson(_playerConfigExp .firstMatch(_root.getElementsByTagName('html').first.text) ?.group(1))); diff --git a/lib/src/search/search_client.dart b/lib/src/search/search_client.dart index 892306c..1c10b5e 100644 --- a/lib/src/search/search_client.dart +++ b/lib/src/search/search_client.dart @@ -71,7 +71,8 @@ class SearchClient { } /// Queries to YouTube to get the results. - @Deprecated('Use getVideosFromPage instead') + @Deprecated('Use getVideosFromPage instead - ' + 'Should be used only to get related videos') Future queryFromPage(String searchQuery) => SearchQuery.search(_httpClient, searchQuery); } diff --git a/test/channel_about_test.dart b/test/channel_about_test.dart index 03c0364..7e315e3 100644 --- a/test/channel_about_test.dart +++ b/test/channel_about_test.dart @@ -2,28 +2,24 @@ import 'package:test/test.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { - group('Channel About', () { - YoutubeExplode yt; - setUp(() { - yt = YoutubeExplode(); - }); + YoutubeExplode yt; + setUp(() { + yt = YoutubeExplode(); + }); - tearDown(() { - yt.close(); - }); + tearDown(() { + yt.close(); + }); - test('GetAboutPageOfChannel', () async { - var channelUrl = - 'https://www.youtube.com/user/FavijTV'; - var channel = await yt.channels.getAboutPageByUsername(channelUrl); - expect(channel.country, 'Italy'); - expect(channel.thumbnails, isNotEmpty); - expect(channel.channelLinks, isNotEmpty); - expect(channel.description, isNotEmpty); - expect(channel.joinDate, isNotEmpty); - expect(channel.title, 'FavijTV'); - expect(channel.viewCount, greaterThanOrEqualTo(3631224938)); - - }); + test('Get a channel about page', () async { + var channelUrl = 'https://www.youtube.com/user/FavijTV'; + var channel = await yt.channels.getAboutPageByUsername(channelUrl); + expect(channel.country, 'Italy'); + expect(channel.thumbnails, isNotEmpty); + expect(channel.channelLinks, isNotEmpty); + expect(channel.description, isNotEmpty); + expect(channel.joinDate, isNotEmpty); + expect(channel.title, 'FavijTV'); + expect(channel.viewCount, greaterThanOrEqualTo(3631224938)); }); } diff --git a/test/channel_id_test.dart b/test/channel_id_test.dart index 67d5941..1ad2bf0 100644 --- a/test/channel_id_test.dart +++ b/test/channel_id_test.dart @@ -2,34 +2,58 @@ import 'package:test/test.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { - group('ChannelId', () { - test('ValidChannelId', () { - var channel1 = ChannelId('UCEnBXANsKmyj2r9xVyKoDiQ'); - var channel2 = ChannelId('UC46807r_RiRjH8IU-h_DrDQ'); + group('These are valid channel ids', () { + for (var val in { + [ChannelId('UCEnBXANsKmyj2r9xVyKoDiQ'), 'UCEnBXANsKmyj2r9xVyKoDiQ'], + [ChannelId('UC46807r_RiRjH8IU-h_DrDQ'), 'UC46807r_RiRjH8IU-h_DrDQ'], + }) { + test('ChannelID - ${val[0]}', () { + expect(val[0].value, val[1]); + }); + } + }); + group('These are valid channel urls', () { + for (var val in { + [ + ChannelId('youtube.com/channel/UC3xnGqlcL3y-GXz5N3wiTJQ'), + 'UC3xnGqlcL3y-GXz5N3wiTJQ' + ], + [ + ChannelId('youtube.com/channel/UCkQO3QsgTpNTsOw6ujimT5Q'), + 'UCkQO3QsgTpNTsOw6ujimT5Q' + ], + [ + ChannelId('youtube.com/channel/UCQtjJDOYluum87LA4sI6xcg'), + 'UCQtjJDOYluum87LA4sI6xcg' + ] + }) { + test('ChannelURL - ${val[0]}', () { + expect(val[0].value, val[1]); + }); + } + }); - expect(channel1.value, 'UCEnBXANsKmyj2r9xVyKoDiQ'); - expect(channel2.value, 'UC46807r_RiRjH8IU-h_DrDQ'); - }); - test('ValidChannelUrl', () { - var channel1 = ChannelId('youtube.com/channel/UC3xnGqlcL3y-GXz5N3wiTJQ'); - var channel2 = ChannelId('youtube.com/channel/UCkQO3QsgTpNTsOw6ujimT5Q'); - var channel3 = ChannelId('youtube.com/channel/UCQtjJDOYluum87LA4sI6xcg'); + group('These are not valid channel ids', () { + for (var val in { + '', + 'UC3xnGqlcL3y-GXz5N3wiTJ', + 'UC3xnGqlcL y-GXz5N3wiTJQ' + }) { + test('ChannelID - $val', () { + expect(() => ChannelId(val), throwsArgumentError); + }); + } + }); - expect(channel1.value, 'UC3xnGqlcL3y-GXz5N3wiTJQ'); - expect(channel2.value, 'UCkQO3QsgTpNTsOw6ujimT5Q'); - expect(channel3.value, 'UCQtjJDOYluum87LA4sI6xcg'); - }); - test('InvalidChannelId', () { - expect(() => ChannelId(''), throwsArgumentError); - expect(() => ChannelId('UC3xnGqlcL3y-GXz5N3wiTJ'), throwsArgumentError); - expect(() => ChannelId('UC3xnGqlcL y-GXz5N3wiTJQ'), throwsArgumentError); - }); - - test('InvalidChannelUrl', () { - expect(() => ChannelId('youtube.com/?channel=UCUC3xnGqlcL3y-GXz5N3wiTJQ'), - throwsArgumentError); - expect(() => ChannelId('youtube.com/channel/asd'), throwsArgumentError); - expect(() => ChannelId('youtube.com/'), throwsArgumentError); - }); + group('These are not valid channel urls', () { + for (var val in { + 'youtube.com/?channel=UCUC3xnGqlcL3y-GXz5N3wiTJQ', + 'youtube.com/channel/asd', + 'youtube.com/' + }) { + test('ChannelURL - $val', () { + expect(() => ChannelId(val), throwsArgumentError); + }); + } }); } diff --git a/test/channel_test.dart b/test/channel_test.dart index c4328c3..516a77b 100644 --- a/test/channel_test.dart +++ b/test/channel_test.dart @@ -2,81 +2,74 @@ import 'package:test/test.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { - group('Channel', () { - YoutubeExplode yt; - setUp(() { - yt = YoutubeExplode(); - }); + YoutubeExplode yt; + setUp(() { + yt = YoutubeExplode(); + }); - tearDown(() { - yt.close(); - }); + tearDown(() { + yt.close(); + }); - test('GetMetadataOfChannel', () async { - var channelUrl = - 'https://www.youtube.com/channel/UCEnBXANsKmyj2r9xVyKoDiQ'; - var channel = await yt.channels.get(ChannelId(channelUrl)); - expect(channel.url, channelUrl); - expect(channel.title, 'Tyrrrz'); - expect(channel.logoUrl, isNotEmpty); - expect(channel.logoUrl, isNot(equalsIgnoringWhitespace(''))); - }); + test('Get metadata of a channel', () async { + var channelUrl = 'https://www.youtube.com/channel/UCEnBXANsKmyj2r9xVyKoDiQ'; + var channel = await yt.channels.get(ChannelId(channelUrl)); + expect(channel.url, channelUrl); + expect(channel.title, 'Tyrrrz'); + expect(channel.logoUrl, isNotEmpty); + expect(channel.logoUrl, isNot(equalsIgnoringWhitespace(''))); + }); - test('GetMetadataOfAnyChannel', () async { - var channelId = ChannelId('UC46807r_RiRjH8IU-h_DrDQ'); - var channel = await yt.channels.get(channelId); - expect(channel.id, channelId); + group('Get metadata of any channel', () { + for (var val in { + 'UC46807r_RiRjH8IU-h_DrDQ', + 'UCJ6td3C9QlPO9O_J5dF4ZzA', + 'UCiGm_E4ZwYSHV3bcW1pnSeQ' + }) { + test('Channel - $val', () async { + var channelId = ChannelId(val); + var channel = await yt.channels.get(channelId); + expect(channel.id, channelId); + }); + } + }); - channelId = ChannelId('UCJ6td3C9QlPO9O_J5dF4ZzA'); - channel = await yt.channels.get(channelId); - expect(channel.id, channelId); + test('Get metadata of a channel by username', () async { + var channel = await yt.channels.getByUsername(Username('TheTyrrr')); + expect(channel.id.value, 'UCEnBXANsKmyj2r9xVyKoDiQ'); + }); - channelId = ChannelId('UCiGm_E4ZwYSHV3bcW1pnSeQ'); - channel = await yt.channels.get(channelId); - expect(channel.id, channelId); - }); + test('Get metadata of a channel by a video', () async { + var channel = await yt.channels.getByVideo(VideoId('5NmxuoNyDss')); + expect(channel.id.value, 'UCEnBXANsKmyj2r9xVyKoDiQ'); + }); - test('GetMetadataOfAnyChannelByUser', () async { - var channel = await yt.channels.getByUsername(Username('TheTyrrr')); - expect(channel.id.value, 'UCEnBXANsKmyj2r9xVyKoDiQ'); - }); + test('Get the videos of a youtube channel', () async { + var videos = await yt.channels + .getUploads(ChannelId( + 'https://www.youtube.com/channel/UCEnBXANsKmyj2r9xVyKoDiQ')) + .toList(); + expect(videos.length, greaterThanOrEqualTo(80)); + }); - test('GetMetadataOfAnyChannelByVideo', () async { - var channel = await yt.channels.getByVideo(VideoId('5NmxuoNyDss')); - expect(channel.id.value, 'UCEnBXANsKmyj2r9xVyKoDiQ'); - }); + group('Get the videos of any youtube channel', () { + for (var val in { + 'UC46807r_RiRjH8IU-h_DrDQ', + 'UCJ6td3C9QlPO9O_J5dF4ZzA', + 'UCiGm_E4ZwYSHV3bcW1pnSeQ' + }) { + test('Channel - $val', () async { + var videos = await yt.channels.getUploads(ChannelId(val)).toList(); + expect(videos, isNotEmpty); + }); + } + }); - test('GetVideosOfYoutubeChannel', () async { - var videos = await yt.channels - .getUploads(ChannelId( - 'https://www.youtube.com/channel/UCEnBXANsKmyj2r9xVyKoDiQ')) - .toList(); - expect(videos.length, greaterThanOrEqualTo(80)); - }); - - test('GetVideosOfAnyYoutubeChannel', () async { - var videos = await yt.channels - .getUploads(ChannelId('UC46807r_RiRjH8IU-h_DrDQ')) - .toList(); - expect(videos, isNotEmpty); - - videos = await yt.channels - .getUploads(ChannelId('UCJ6td3C9QlPO9O_J5dF4ZzA')) - .toList(); - expect(videos, isNotEmpty); - - videos = await yt.channels - .getUploads(ChannelId('UCiGm_E4ZwYSHV3bcW1pnSeQ')) - .toList(); - expect(videos, isNotEmpty); - }); - - test('GetVideosOfYoutubeChannelFromUploadPage', () async { - var videos = await yt.channels - .getUploadsFromPage('UCEnBXANsKmyj2r9xVyKoDiQ') - .take(30) - .toList(); - expect(videos, hasLength(30)); - }); + test('Get videos of a youtube channel from the uploads page', () async { + var videos = await yt.channels + .getUploadsFromPage('UCEnBXANsKmyj2r9xVyKoDiQ') + .take(30) + .toList(); + expect(videos, hasLength(30)); }); } diff --git a/test/closed_caption_test.dart b/test/closed_caption_test.dart index 1d6e148..d490664 100644 --- a/test/closed_caption_test.dart +++ b/test/closed_caption_test.dart @@ -2,41 +2,38 @@ import 'package:test/test.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { - group('Search', () { - YoutubeExplode yt; - setUp(() { - yt = YoutubeExplode(); - }); + YoutubeExplode yt; + setUp(() { + yt = YoutubeExplode(); + }); - tearDown(() { - yt.close(); - }); + tearDown(() { + yt.close(); + }); - test('GetClosedCaptionTracksOfAnyVideo', () async { - var manifest = await yt.videos.closedCaptions.getManifest('WOxr2dmLHLo'); - expect(manifest.tracks, isNotEmpty); - }); - test('GetClosedCaptionTrackOfAnyVideoSpecific', () async { - var manifest = await yt.videos.closedCaptions.getManifest('WOxr2dmLHLo'); - var trackInfo = manifest.tracks.first; - var track = await yt.videos.closedCaptions.get(trackInfo); + test('Get closed captions of a video', () async { + var manifest = await yt.videos.closedCaptions.getManifest('WOxr2dmLHLo'); + expect(manifest.tracks, isNotEmpty); + }); + test('Get closed caption track of a video', () async { + var manifest = await yt.videos.closedCaptions.getManifest('WOxr2dmLHLo'); + var trackInfo = manifest.tracks.first; + var track = await yt.videos.closedCaptions.get(trackInfo); - expect(track.captions, isNotEmpty); - }); - test('GetClosedCaptionTrackAtSpecificTime', () async { - var manifest = await yt.videos.closedCaptions - .getManifest('https://www.youtube.com/watch?v=ppJy5uGZLi4'); - var trackInfo = manifest.getByLanguage('en'); - var track = await yt.videos.closedCaptions.get(trackInfo); - var caption = - track.getByTime(const Duration(hours: 0, minutes: 13, seconds: 22)); - var captionPart = - caption.getPartByTime(const Duration(milliseconds: 200)); + expect(track.captions, isNotEmpty); + }); + test('Get closed caption track at a specific time', () async { + var manifest = await yt.videos.closedCaptions + .getManifest('https://www.youtube.com/watch?v=ppJy5uGZLi4'); + var trackInfo = manifest.getByLanguage('en'); + var track = await yt.videos.closedCaptions.get(trackInfo); + var caption = + track.getByTime(const Duration(hours: 0, minutes: 13, seconds: 22)); + var captionPart = caption.getPartByTime(const Duration(milliseconds: 200)); - expect(caption, isNotNull); - expect(captionPart, isNotNull); - expect(caption.text, 'how about this black there are some'); - expect(captionPart.text, ' about'); - }); + expect(caption, isNotNull); + expect(captionPart, isNotNull); + expect(caption.text, 'how about this black there are some'); + expect(captionPart.text, ' about'); }); } diff --git a/test/comments_client_test.dart b/test/comments_client_test.dart index 138d68e..548aee3 100644 --- a/test/comments_client_test.dart +++ b/test/comments_client_test.dart @@ -2,21 +2,19 @@ import 'package:test/test.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { - group('Comments', () { - YoutubeExplode yt; - setUp(() { - yt = YoutubeExplode(); - }); - - tearDown(() { - yt.close(); - }); - - test('GetCommentOfVideo', () async { - var videoUrl = 'https://www.youtube.com/watch?v=AI7ULzgf8RU'; - var video = await yt.videos.get(VideoId(videoUrl), forceWatchPage: true); - var comments = await yt.videos.commentsClient.getComments(video).toList(); - expect(comments.length, greaterThanOrEqualTo(1)); - }, skip: 'This may fail on some environments'); + YoutubeExplode yt; + setUp(() { + yt = YoutubeExplode(); }); + + tearDown(() { + yt.close(); + }); + + test('Get comments of a video', () async { + var videoUrl = 'https://www.youtube.com/watch?v=AI7ULzgf8RU'; + var video = await yt.videos.get(VideoId(videoUrl), forceWatchPage: true); + var comments = await yt.videos.commentsClient.getComments(video).toList(); + expect(comments.length, greaterThanOrEqualTo(1)); + }, skip: 'This may fail on some environments'); } diff --git a/test/playlist_id_test.dart b/test/playlist_id_test.dart index 038b7f4..9f709f7 100644 --- a/test/playlist_id_test.dart +++ b/test/playlist_id_test.dart @@ -2,59 +2,85 @@ import 'package:test/test.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { - group('PlaylistId', () { - test('ValidPlaylistId', () { - var data = const { - 'PL601B2E69B03FAB9D', - 'PLI5YfMzCfRtZ8eV576YoY3vIYrHjyVm_e', - 'PLWwAypAcFRgKFlxtLbn_u14zddtDJj3mk', - 'OLAK5uy_mtOdjCW76nDvf5yOzgcAVMYpJ5gcW5uKU', - 'RD1hu8-y6fKg0', - 'RDMMU-ty-2B02VY', - 'RDCLAK5uy_lf8okgl2ygD075nhnJVjlfhwp8NsUgEbs', - 'ULl6WWX-BgIiE', - 'UUTMt7iMWa7jy0fNXIktwyLA', - 'OLAK5uy_lLeonUugocG5J0EUAEDmbskX4emejKwcM', - 'FLEnBXANsKmyj2r9xVyKoDiQ' - }; - // ignore: avoid_function_literals_in_foreach_calls - data.forEach((playlistId) { - var playlist = PlaylistId(playlistId); - expect(playlist.value, playlistId); + group('These are valid playlist ids', () { + for (var val in { + 'PL601B2E69B03FAB9D', + 'PLI5YfMzCfRtZ8eV576YoY3vIYrHjyVm_e', + 'PLWwAypAcFRgKFlxtLbn_u14zddtDJj3mk', + 'OLAK5uy_mtOdjCW76nDvf5yOzgcAVMYpJ5gcW5uKU', + 'RD1hu8-y6fKg0', + 'RDMMU-ty-2B02VY', + 'RDCLAK5uy_lf8okgl2ygD075nhnJVjlfhwp8NsUgEbs', + 'ULl6WWX-BgIiE', + 'UUTMt7iMWa7jy0fNXIktwyLA', + 'FLEnBXANsKmyj2r9xVyKoDiQ' + }) { + test('PlaylistID - $val', () { + var playlist = PlaylistId(val); + expect(playlist.value, val); }); - }); - test('ValidPlaylistUrl', () { - var data = const { - 'youtube.com/playlist?list=PLOU2XLYxmsIJGErt5rrCqaSGTMyyqNt2H': - 'PLOU2XLYxmsIJGErt5rrCqaSGTMyyqNt2H', - 'youtube.com/watch?v=b8m9zhNAgKs&list=PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr': - 'PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr', - 'youtu.be/b8m9zhNAgKs/?list=PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr': - 'PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr', - 'youtube.com/embed/b8m9zhNAgKs/?list=PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr': - 'PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr', - 'youtube.com/watch?v=x2ZRoWQ0grU&list=RDEMNJhLy4rECJ_fG8NL-joqsg': - 'RDEMNJhLy4rECJ_fG8NL-joqsg' - }; - data.forEach((url, playlistId) { - var playlist = PlaylistId(playlistId); - expect(playlist.value, playlistId); + } + }); + + group('These are valid playlist urls', () { + for (var val in { + [ + PlaylistId( + 'youtube.com/playlist?list=PLOU2XLYxmsIJGErt5rrCqaSGTMyyqNt2H'), + 'PLOU2XLYxmsIJGErt5rrCqaSGTMyyqNt2H' + ], + [ + PlaylistId( + 'youtube.com/watch?v=b8m9zhNAgKs&list=PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr'), + 'PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr' + ], + [ + PlaylistId( + 'youtu.be/b8m9zhNAgKs/?list=PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr'), + 'PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr' + ], + [ + PlaylistId( + 'youtube.com/embed/b8m9zhNAgKs/?list=PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr'), + 'PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr' + ], + [ + PlaylistId( + 'youtube.com/watch?v=x2ZRoWQ0grU&list=RDEMNJhLy4rECJ_fG8NL-joqsg'), + 'RDEMNJhLy4rECJ_fG8NL-joqsg' + ], + [ + PlaylistId( + 'youtube.com/watch?v=b8m9zhNAgKs&list=PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr'), + 'PL9tY0BWXOZFuFEG_GtOBZ8-8wbkH-NVAr' + ], + }) { + test('PlaylistID - ${val[0]}', () { + expect(val[0].value, val[1]); }); - }); - test('InvalidPlaylistId', () { - expect(() => PlaylistId('PLm_3vnTS-pvmZFuF L1Pyhqf8kTTYVKjW'), - throwsArgumentError); - expect(() => PlaylistId('PLm_3vnTS-pvmZFuF3L=Pyhqf8kTTYVKjW'), - throwsArgumentError); - }); - test('InvalidPlaylistUrl', () { - expect( - () => PlaylistId( - 'youtube.com/playlist?lisp=PLOU2XLYxmsIJGErt5rrCqaSGTMyyqNt2H'), - throwsArgumentError); - expect(() => PlaylistId('youtube.com/playlist?list=asd'), - throwsArgumentError); - expect(() => PlaylistId('youtube.com/'), throwsArgumentError); - }); + } + }); + + group('These are not valid playlist ids', () { + for (var val in { + 'PLm_3vnTS-pvmZFuF L1Pyhqf8kTTYVKjW', + 'PLm_3vnTS-pvmZFuF3L=Pyhqf8kTTYVKjW' + }) { + test('PlaylistID - $val', () { + expect(() => PlaylistId(val), throwsArgumentError); + }); + } + }); + + group('These are not valid playlist urls', () { + for (var val in { + 'youtube.com/playlist?lisp=PLOU2XLYxmsIJGErt5rrCqaSGTMyyqNt2H', + 'youtube.com/playlist?list=asd' + 'youtube.com/' + }) { + test('PlaylistURL - $val', () { + expect(() => PlaylistId(val), throwsArgumentError); + }); + } }); } diff --git a/test/playlist_test.dart b/test/playlist_test.dart index c5d8a43..c4f93aa 100644 --- a/test/playlist_test.dart +++ b/test/playlist_test.dart @@ -2,84 +2,82 @@ import 'package:test/test.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { - group('Playlist', () { - YoutubeExplode yt; - setUp(() { - yt = YoutubeExplode(); - }); + YoutubeExplode yt; + setUp(() { + yt = YoutubeExplode(); + }); - tearDown(() { - yt.close(); - }); + tearDown(() { + yt.close(); + }); - test('GetMetadataOfPlaylist', () async { - var playlistUrl = - 'https://www.youtube.com/playlist?list=PLr-IftNTIujSF-8tlGbZBQyGIT6TCF6Yd'; - var playlist = await yt.playlists.get(PlaylistId(playlistUrl)); - expect(playlist.id.value, 'PLr-IftNTIujSF-8tlGbZBQyGIT6TCF6Yd'); - expect(playlist.url, playlistUrl); - expect(playlist.title, 'osu! Highlights'); - expect(playlist.author, 'Tyrrrz'); - expect(playlist.description, 'My best osu! plays'); - expect(playlist.engagement.viewCount, greaterThanOrEqualTo(133)); - expect(playlist.engagement.likeCount, greaterThanOrEqualTo(0)); - expect(playlist.engagement.dislikeCount, greaterThanOrEqualTo(0)); - expect(playlist.thumbnails.lowResUrl, isNotEmpty); - expect(playlist.thumbnails.mediumResUrl, isNotEmpty); - expect(playlist.thumbnails.highResUrl, isNotEmpty); - expect(playlist.thumbnails.standardResUrl, isNotEmpty); - expect(playlist.thumbnails.maxResUrl, isNotEmpty); - }); - test('GetMetadataOfAnyPlaylist', () async { - var data = { - 'PLI5YfMzCfRtZ8eV576YoY3vIYrHjyVm_e', - 'RD1hu8-y6fKg0', - 'RDMMU-ty-2B02VY', - 'RDCLAK5uy_lf8okgl2ygD075nhnJVjlfhwp8NsUgEbs', - 'OLAK5uy_lLeonUugocG5J0EUAEDmbskX4emejKwcM', - 'PL601B2E69B03FAB9D' - }; - for (var playlistId in data) { - var playlist = await yt.playlists.get(PlaylistId(playlistId)); - expect(playlist.id.value, playlistId); - } - }); - test('GetVideosInPlaylist', () async { - var videos = await yt.playlists - .getVideos(PlaylistId( - 'https://www.youtube.com/playlist?list=PLr-IftNTIujSF-8tlGbZBQyGIT6TCF6Yd')) - .toList(); - expect(videos.length, greaterThanOrEqualTo(19)); - expect( - videos.map((e) => e.id.value).toList(), - containsAll([ - 'B6N8-_rBTh8', - 'F1bvjgTckMc', - 'kMBzljXOb9g', - 'LsNPjFXIPT8', - 'fXYPMPglYTs', - 'AI7ULzgf8RU', - 'Qzu-fTdjeFY' - ])); - }); - var data = const { - 'PL601B2E69B03FAB9D', - 'PLI5YfMzCfRtZ8eV576YoY3vIYrHjyVm_e', - 'PLWwAypAcFRgKFlxtLbn_u14zddtDJj3mk', - 'OLAK5uy_mtOdjCW76nDvf5yOzgcAVMYpJ5gcW5uKU', - 'RD1hu8-y6fKg0', - 'RDMMU-ty-2B02VY', - 'RDCLAK5uy_lf8okgl2ygD075nhnJVjlfhwp8NsUgEbs', - 'ULl6WWX-BgIiE', - 'UUTMt7iMWa7jy0fNXIktwyLA', - 'OLAK5uy_lLeonUugocG5J0EUAEDmbskX4emejKwcM', - 'FLEnBXANsKmyj2r9xVyKoDiQ' - }; - for (var playlistId in data) { - test('GetVideosInAnyPlaylist - $playlistId', () async { - var videos = - await yt.playlists.getVideos(PlaylistId(playlistId)).toList(); - expect(videos, isNotEmpty); + test('Get metadata of a playlist', () async { + var playlistUrl = + 'https://www.youtube.com/playlist?list=PLr-IftNTIujSF-8tlGbZBQyGIT6TCF6Yd'; + var playlist = await yt.playlists.get(PlaylistId(playlistUrl)); + expect(playlist.id.value, 'PLr-IftNTIujSF-8tlGbZBQyGIT6TCF6Yd'); + expect(playlist.url, playlistUrl); + expect(playlist.title, 'osu! Highlights'); + expect(playlist.author, 'Tyrrrz'); + expect(playlist.description, 'My best osu! plays'); + expect(playlist.engagement.viewCount, greaterThanOrEqualTo(133)); + expect(playlist.engagement.likeCount, greaterThanOrEqualTo(0)); + expect(playlist.engagement.dislikeCount, greaterThanOrEqualTo(0)); + expect(playlist.thumbnails.lowResUrl, isNotEmpty); + expect(playlist.thumbnails.mediumResUrl, isNotEmpty); + expect(playlist.thumbnails.highResUrl, isNotEmpty); + expect(playlist.thumbnails.standardResUrl, isNotEmpty); + expect(playlist.thumbnails.maxResUrl, isNotEmpty); + }); + group('Get metadata of any playlist', () { + for (var val in { + PlaylistId('PLI5YfMzCfRtZ8eV576YoY3vIYrHjyVm_e'), + PlaylistId('RD1hu8-y6fKg0'), + PlaylistId('RDMMU-ty-2B02VY'), + PlaylistId('RDCLAK5uy_lf8okgl2ygD075nhnJVjlfhwp8NsUgEbs'), + PlaylistId('PL601B2E69B03FAB9D') + }) { + test('PlaylistID - ${val.value}', () async { + var playlist = await yt.playlists.get(val); + expect(playlist.id.value, val.value); + }); + } + }); + + test('Get videos in a playlist', () async { + var videos = await yt.playlists + .getVideos(PlaylistId( + 'https://www.youtube.com/playlist?list=PLr-IftNTIujSF-8tlGbZBQyGIT6TCF6Yd')) + .toList(); + expect(videos.length, greaterThanOrEqualTo(19)); + expect( + videos.map((e) => e.id.value).toList(), + containsAll([ + 'B6N8-_rBTh8', + 'F1bvjgTckMc', + 'kMBzljXOb9g', + 'LsNPjFXIPT8', + 'fXYPMPglYTs', + 'AI7ULzgf8RU', + 'Qzu-fTdjeFY' + ])); + }); + + group('Get videos in any playlist', () { + for (var val in { + PlaylistId('PL601B2E69B03FAB9D'), + PlaylistId('PLI5YfMzCfRtZ8eV576YoY3vIYrHjyVm_e'), + PlaylistId('PLWwAypAcFRgKFlxtLbn_u14zddtDJj3mk'), + PlaylistId('OLAK5uy_mtOdjCW76nDvf5yOzgcAVMYpJ5gcW5uKU'), + PlaylistId('RD1hu8-y6fKg0'), + PlaylistId('RDMMU-ty-2B02VY'), + PlaylistId('RDCLAK5uy_lf8okgl2ygD075nhnJVjlfhwp8NsUgEbs'), + PlaylistId('ULl6WWX-BgIiE'), + PlaylistId('UUTMt7iMWa7jy0fNXIktwyLA'), + PlaylistId('FLEnBXANsKmyj2r9xVyKoDiQ') + }) { + test('PlaylistID - ${val.value}', () async { + expect(yt.playlists.getVideos(val), emits(isNotNull)); }); } }); diff --git a/test/search_test.dart b/test/search_test.dart index 72eb754..b8cc328 100644 --- a/test/search_test.dart +++ b/test/search_test.dart @@ -2,43 +2,40 @@ import 'package:test/test.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { - group('Search', () { - YoutubeExplode yt; - setUp(() { - yt = YoutubeExplode(); - }); + YoutubeExplode yt; + setUp(() { + yt = YoutubeExplode(); + }); - tearDown(() { - yt.close(); - }); + tearDown(() { + yt.close(); + }); - test('SearchYouTubeVideosFromApi', () async { - var videos = - await yt.search.getVideos('undead corporation megalomania').toList(); - expect(videos, isNotEmpty); - }, skip: 'Endpoint removed from YouTube'); + test('Search a youtube video from the api', () async { + var videos = + await yt.search.getVideos('undead corporation megalomania').toList(); + expect(videos, isNotEmpty); + }); - //TODO: Find out why this fails - test('SearchYouTubeVideosFromPage', () async { - var searchQuery = await yt.search.queryFromPage('hello'); - expect(searchQuery.content, isNotEmpty); - expect(searchQuery.relatedVideos, isNotEmpty); - expect(searchQuery.relatedQueries, isNotEmpty); - }, skip: 'This may fail on some environments'); + test('Search a youtube videos from the search page', () async { + var searchQuery = await yt.search.queryFromPage('hello'); + expect(searchQuery.content, isNotEmpty); + expect(searchQuery.relatedVideos, isNotEmpty); + expect(searchQuery.relatedQueries, isNotEmpty); + }); - test('SearchNoResults', () async { - var query = - await yt.search.queryFromPage('g;jghEOGHJeguEPOUIhjegoUEHGOGHPSASG'); - expect(query.content, isEmpty); - expect(query.relatedQueries, isEmpty); - expect(query.relatedVideos, isEmpty); - var nextPage = await query.nextPage(); - expect(nextPage, isNull); - }); + test('Search with no results', () async { + var query = + await yt.search.queryFromPage('g;jghEOGHJeguEPOUIhjegoUEHGOGHPSASG'); + expect(query.content, isEmpty); + expect(query.relatedQueries, isEmpty); + expect(query.relatedVideos, isEmpty); + var nextPage = await query.nextPage(); + expect(nextPage, isNull); + }); - test('SearchYouTubeVideosFromPageStream', () async { - var query = await yt.search.getVideosFromPage('hello').take(30).toList(); - expect(query, hasLength(30)); - }); + test('Search youtube videos from search page (stream)', () async { + var query = await yt.search.getVideosFromPage('hello').take(30).toList(); + expect(query, hasLength(30)); }); } diff --git a/test/streams_test.dart b/test/streams_test.dart index 0dda6b6..389f68c 100644 --- a/test/streams_test.dart +++ b/test/streams_test.dart @@ -2,69 +2,65 @@ import 'package:test/test.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { - group('Streams', () { - YoutubeExplode yt; - setUp(() { - yt = YoutubeExplode(); - }); + YoutubeExplode yt; + setUp(() { + yt = YoutubeExplode(); + }); - tearDown(() { - yt.close(); - }); + tearDown(() { + yt.close(); + }); - var data = { - '9bZkp7q19f0', - 'SkRSXFQerZs', - 'hySoCSoH-g8', - '_kmeFXjjGfk', - 'MeJVWBSsPAY', - '5VGm0dczmHc', - 'ZGdLIwrGHG8', - 'rsAAeyAr-9Y', - 'AI7ULzgf8RU' - }; - for (var videoId in data) { - test('GetStreamsOfAnyVideo - $videoId', () async { - var manifest = - await yt.videos.streamsClient.getManifest(VideoId(videoId)); + group('Get streams of any video', () { + for (var val in { + VideoId('9bZkp7q19f0'), // very popular + VideoId('SkRSXFQerZs'), // age-restricted + VideoId('hySoCSoH-g8'), + VideoId('_kmeFXjjGfk'), + VideoId('MeJVWBSsPAY'), + VideoId('5VGm0dczmHc'), // rating is not allowed + VideoId('ZGdLIwrGHG8'), // unlisted + VideoId('rsAAeyAr-9Y'), + VideoId('AI7ULzgf8RU') + }) { + test('VideoId - ${val.value}', () async { + var manifest = await yt.videos.streamsClient.getManifest(val); expect(manifest.streams, isNotEmpty); }); } - - test('GetStreamOfUnplayableVideo', () async { - expect(yt.videos.streamsClient.getManifest(VideoId('5qap5aO4i9A')), - throwsA(const TypeMatcher())); - }); - test('GetStreamOfPurchaseVideo', () async { - expect(yt.videos.streamsClient.getManifest(VideoId('p3dDcKOFXQg')), - throwsA(const TypeMatcher())); - }); - //TODO: Fix this with VideoRequiresPurchaseException. - test('GetStreamOfPurchaseVideo', () async { - expect(yt.videos.streamsClient.getManifest(VideoId('qld9w0b-1ao')), - throwsA(const TypeMatcher())); - expect(yt.videos.streamsClient.getManifest(VideoId('pb_hHv3fByo')), - throwsA(const TypeMatcher())); - }); - test('GetStreamOfAnyPlayableVideo', () async { - var data = { - '9bZkp7q19f0', - 'SkRSXFQerZs', - 'hySoCSoH-g8', - '_kmeFXjjGfk', - 'MeJVWBSsPAY', - '5VGm0dczmHc', - 'ZGdLIwrGHG8', - 'rsAAeyAr-9Y', - }; - for (var videoId in data) { - var manifest = - await yt.videos.streamsClient.getManifest(VideoId(videoId)); - for (var streamInfo in manifest.streams) { - var stream = await yt.videos.streamsClient.get(streamInfo).toList(); - expect(stream, isNotEmpty); - } - } - }, timeout: const Timeout(Duration(minutes: 10)), skip: 'Takes too long.'); }); + + test('Stream of paid videos throw VideoRequiresPurchaseException', () { + expect(yt.videos.streamsClient.getManifest(VideoId('p3dDcKOFXQg')), + throwsA(const TypeMatcher())); + }); + + group('Stream of unavailable videos throws VideoUnavailableException', () { + for (var val in {VideoId('qld9w0b-1ao'), VideoId('pb_hHv3fByo')}) { + test('VideoId - ${val.value}', () { + expect(yt.videos.streamsClient.getManifest(val), + throwsA(const TypeMatcher())); + }); + } + }); + + group('Get stream of any playable video', () { + for (var val in { + VideoId('9bZkp7q19f0'), + VideoId('SkRSXFQerZs'), + VideoId('hySoCSoH-g8'), + VideoId('_kmeFXjjGfk'), + VideoId('MeJVWBSsPAY'), + VideoId('5VGm0dczmHc'), + VideoId('ZGdLIwrGHG8'), + VideoId('rsAAeyAr-9Y'), + }) { + test('VideoId - ${val.value}', () async { + var manifest = await yt.videos.streamsClient.getManifest(val); + for (var streamInfo in manifest.streams) { + expect( yt.videos.streamsClient.get(streamInfo), emits(isNotNull)); + } + }); + } + }, skip: 'Occasionally may fail with certain videos'); } diff --git a/test/user_name_test.dart b/test/user_name_test.dart index 9f986b2..f413740 100644 --- a/test/user_name_test.dart +++ b/test/user_name_test.dart @@ -2,34 +2,44 @@ import 'package:test/test.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { - group('Username', () { - test('ValidUsername', () { - var data = const {'TheTyrrr', 'KannibalenRecords', 'JClayton1994'}; - // ignore: avoid_function_literals_in_foreach_calls - data.forEach((usernameStr) { - var username = Username(usernameStr); - expect(username.value, usernameStr); + group('These are valid usernames', () { + for (var val in {'TheTyrrr', 'KannibalenRecords', 'JClayton1994'}) { + test('Username - $val', () { + expect(Username(val).value, val); }); - }); - test('ValidUsernameUrl', () { - var data = const { - 'youtube.com/user/ProZD': 'ProZD', - 'youtube.com/user/TheTyrrr': 'TheTyrrr', - }; - data.forEach((url, usernameStr) { - var username = Username(url); - expect(username.value, usernameStr); + } + }); + group('These are valid username urls', () { + for (var val in { + ['youtube.com/user/ProZD', 'ProZD'], + ['youtube.com/user/TheTyrrr', 'TheTyrrr'], + }) { + test('UsernameURL - $val', () { + expect(Username(val[0]).value, val[1]); }); - }); - test('InvalidUsername', () { - expect(() => Username('The_Tyrrr'), throwsArgumentError); - expect(() => Username('0123456789ABCDEFGHIJK'), throwsArgumentError); - expect(() => Username('A1B2C3-'), throwsArgumentError); - expect(() => Username('=0123456789ABCDEF'), throwsArgumentError); - }); - test('InvalidUsernameUrl', () { - expect(() => Username('youtube.com/user/P_roZD'), throwsArgumentError); - expect(() => Username('youtube.com/user/P_roZD'), throwsArgumentError); - }); + } + }); + group('These are invalid usernames', () { + for (var val in { + 'The_Tyrrr', + '0123456789ABCDEFGHIJK', + 'A1B2C3-', + '=0123456789ABCDEF' + }) { + test('Username - $val', () { + expect(() => Username(val), throwsArgumentError); + }); + } + }); + + group('These are not valid username urls', () { + for (var val in { + 'youtube.com/user/P_roZD', + 'example.com/user/ProZD', + }) { + test('UsernameURL - $val', () { + expect(() => Username(val), throwsArgumentError); + }); + } }); } diff --git a/test/video_id_test.dart b/test/video_id_test.dart index 0b46ab6..3a7af98 100644 --- a/test/video_id_test.dart +++ b/test/video_id_test.dart @@ -2,40 +2,36 @@ import 'package:test/test.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { - group('VideoId', () { - test('ValidVideoId', () { - var data = const { - '9bZkp7q19f0', - '_kmeFXjjGfk', - 'AI7ULzgf8RU', - }; - // ignore: avoid_function_literals_in_foreach_calls - data.forEach((videoId) { - var video = VideoId(videoId); - expect(video.value, videoId); + group('These are valid video ids', () { + for (var val in {'9bZkp7q19f0', '_kmeFXjjGfk', 'AI7ULzgf8RU'}) { + test('VideoID - $val', () { + expect(VideoId(val).value, val); }); - }); - test('ValidVideoUrl', () { - var data = const { - 'youtube.com/watch?v=yIVRs6YSbOM': 'yIVRs6YSbOM', - 'youtu.be/yIVRs6YSbOM': 'yIVRs6YSbOM', - 'youtube.com/embed/yIVRs6YSbOM': 'yIVRs6YSbOM', - }; - data.forEach((url, videoId) { - var video = VideoId(url); - expect(video.value, videoId); + } + }); + group('These are valid video urls', () { + for (var val in { + ['youtube.com/watch?v=yIVRs6YSbOM', 'yIVRs6YSbOM'], + ['youtu.be/yIVRs6YSbOM', 'yIVRs6YSbOM'], + ['youtube.com/embed/yIVRs6YSbOM', 'yIVRs6YSbOM'], + }) { + test('Video - $val', () { + expect(VideoId(val[0]).value, val[1]); }); - }); - test('InvalidVideoId', () { - expect(() => VideoId(''), throwsArgumentError); - expect(() => VideoId('pI2I2zqzeK'), throwsArgumentError); - expect(() => VideoId('pI2I2z zeKg'), throwsArgumentError); - }); - test('InvalidVideoUrl', () { - expect( - () => VideoId('youtube.com/xxx?v=pI2I2zqzeKg'), throwsArgumentError); - expect(() => VideoId('youtu.be/watch?v=xxx'), throwsArgumentError); - expect(() => VideoId('youtube.com/embed/'), throwsArgumentError); - }); + } + }); + group('These are not valid video ids', () { + for (var val in {'', 'pI2I2zqzeK', 'pI2I2z zeKg'}) { + test('VideoID - $val', () { + expect(() => VideoId(val), throwsArgumentError); + }); + } + }); + group('These are not valid video urls', () { + for (var val in {'youtube.com/xxx?v=pI2I2zqzeKg', 'youtu.be/watch?v=xxx', 'youtube.com/embed'}) { + test('VideoURL - $val', () { + expect(() => VideoId(val), throwsArgumentError); + }); + } }); } diff --git a/test/video_test.dart b/test/video_test.dart index 6646592..e26a9d0 100644 --- a/test/video_test.dart +++ b/test/video_test.dart @@ -2,60 +2,61 @@ import 'package:test/test.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { - group('Video', () { - YoutubeExplode yt; - setUp(() { - yt = YoutubeExplode(); - }); + YoutubeExplode yt; + setUp(() { + yt = YoutubeExplode(); + }); - tearDown(() { - yt.close(); - }); + tearDown(() { + yt.close(); + }); - test('GetMetadataOfVideo', () async { - var videoUrl = 'https://www.youtube.com/watch?v=AI7ULzgf8RU'; - var video = await yt.videos.get(VideoId(videoUrl)); - expect(video.id.value, 'AI7ULzgf8RU'); - expect(video.url, videoUrl); - expect(video.title, 'Aka no Ha [Another] +HDHR'); - expect(video.channelId.value, 'UCEnBXANsKmyj2r9xVyKoDiQ'); - expect(video.author, 'Tyrrrz'); - var rangeMs = DateTime(2017, 09, 30, 17, 15, 26).millisecondsSinceEpoch; - // 1day margin since the uploadDate could differ from timezones - expect(video.uploadDate.millisecondsSinceEpoch, - inInclusiveRange(rangeMs - 86400000, rangeMs + 86400000)); - expect(video.description, contains('246pp')); - expect(video.duration, const Duration(minutes: 1, seconds: 48)); - expect(video.thumbnails.lowResUrl, isNotEmpty); - expect(video.thumbnails.mediumResUrl, isNotEmpty); - expect(video.thumbnails.highResUrl, isNotEmpty); - expect(video.thumbnails.standardResUrl, isNotEmpty); - expect(video.thumbnails.maxResUrl, isNotEmpty); - expect(video.keywords, orderedEquals(['osu', 'mouse', 'rhythm game'])); - expect(video.engagement.viewCount, greaterThanOrEqualTo(134)); - expect(video.engagement.likeCount, greaterThanOrEqualTo(5)); - expect(video.engagement.dislikeCount, greaterThanOrEqualTo(0)); - }); + test('Get metadata of a video', () async { + var videoUrl = 'https://www.youtube.com/watch?v=AI7ULzgf8RU'; + var video = await yt.videos.get(VideoId(videoUrl)); + expect(video.id.value, 'AI7ULzgf8RU'); + expect(video.url, videoUrl); + expect(video.title, 'Aka no Ha [Another] +HDHR'); + expect(video.channelId.value, 'UCEnBXANsKmyj2r9xVyKoDiQ'); + expect(video.author, 'Tyrrrz'); + var rangeMs = DateTime(2017, 09, 30, 17, 15, 26).millisecondsSinceEpoch; + // 1day margin since the uploadDate could differ from timezones + expect(video.uploadDate.millisecondsSinceEpoch, + inInclusiveRange(rangeMs - 86400000, rangeMs + 86400000)); + expect(video.description, contains('246pp')); + expect(video.duration, const Duration(minutes: 1, seconds: 48)); + expect(video.thumbnails.lowResUrl, isNotEmpty); + expect(video.thumbnails.mediumResUrl, isNotEmpty); + expect(video.thumbnails.highResUrl, isNotEmpty); + expect(video.thumbnails.standardResUrl, isNotEmpty); + expect(video.thumbnails.maxResUrl, isNotEmpty); + expect(video.keywords, orderedEquals(['osu', 'mouse', 'rhythm game'])); + expect(video.engagement.viewCount, greaterThanOrEqualTo(134)); + expect(video.engagement.likeCount, greaterThanOrEqualTo(5)); + expect(video.engagement.dislikeCount, greaterThanOrEqualTo(0)); + }); - test('GetMetadataOfAnyVideo', () async { - var data = { - '9bZkp7q19f0', - 'SkRSXFQerZs', - '5VGm0dczmHc', - 'ZGdLIwrGHG8', - '5qap5aO4i9A' - }; - for (var videoId in data) { - var video = await yt.videos.get(VideoId(videoId)); - expect(video.id.value, videoId); - } - }); + group('Get metadata of any video', () { + for (var val in { + VideoId('9bZkp7q19f0'), + VideoId('SkRSXFQerZs'), + VideoId('5VGm0dczmHc'), + VideoId('ZGdLIwrGHG8'), + VideoId('5qap5aO4i9A') + }) { + test('VideoId - ${val.value}', () async { + var video = await yt.videos.get(val); + expect(video.id.value, val.value); + }); + } + }); - test('GetMetadataOfInvalidVideo', () async { - expect(() async => yt.videos.get(VideoId('qld9w0b-1ao')), - throwsA(const TypeMatcher())); - expect(() async => yt.videos.get(VideoId('pb_hHv3fByo')), - throwsA(const TypeMatcher())); - }); + group('Get metadata of invalid videos throws VideoUnplayableException', () { + for (var val in {VideoId('qld9w0b-1ao'), VideoId('pb_hHv3fByo')}) { + test('VideoId - $val', () { + expect(() async => yt.videos.get(val), + throwsA(const TypeMatcher())); + }); + } }); }