diff --git a/analysis_options.yaml b/analysis_options.yaml index ef2736e..8b75c99 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,6 +1,9 @@ include: package:lint/analysis_options.yaml analyzer: + exclude: + - "**/*.g.dart" + - "**/*.freezed.dart" strong-mode: implicit-casts: true implicit-dynamic: true @@ -14,3 +17,6 @@ linter: prefer_const_constructors: true avoid_positional_boolean_parameters: false require_trailing_commas: false + prefer_relative_imports: true + avoid_relative_lib_imports: false + always_use_package_imports: false diff --git a/example/video_download.dart b/example/video_download.dart index ee1a91a..5e2dd47 100644 --- a/example/video_download.dart +++ b/example/video_download.dart @@ -37,7 +37,7 @@ Future download(String id) async { var audioStream = yt.videos.streamsClient.get(audio); // Compose the file name removing the unallowed characters in windows. - var fileName = '${video.title}.${audio.container.name.toString()}' + var fileName = '${video.title}.${audio.container.name}' .replaceAll(r'\', '') .replaceAll('/', '') .replaceAll('*', '') diff --git a/lib/src/channels/channel_client.dart b/lib/src/channels/channel_client.dart index 2063fe4..56fc151 100644 --- a/lib/src/channels/channel_client.dart +++ b/lib/src/channels/channel_client.dart @@ -8,12 +8,7 @@ import '../reverse_engineering/pages/watch_page.dart'; import '../reverse_engineering/youtube_http_client.dart'; import '../videos/video.dart'; import '../videos/video_id.dart'; -import 'channel.dart'; -import 'channel_id.dart'; -import 'channel_uploads_list.dart'; import 'channels.dart'; -import 'username.dart'; -import 'video_sorting.dart'; /// Queries related to YouTube channels. class ChannelClient { @@ -40,7 +35,7 @@ class ChannelClient { username = Username.fromString(username); var channelPage = - await ChannelPage.getByUsername(_httpClient, username.value); + await ChannelPage.getByUsername(_httpClient, (username as Username).value); return Channel( ChannelId(channelPage.channelId), channelPage.channelTitle, diff --git a/lib/src/extensions/helpers_extension.dart b/lib/src/extensions/helpers_extension.dart index d32e7cb..3e97c97 100644 --- a/lib/src/extensions/helpers_extension.dart +++ b/lib/src/extensions/helpers_extension.dart @@ -268,7 +268,7 @@ extension UriUtils on Uri { } /// Parse properties with `text` method. -extension RunsParser on List { +extension RunsParser on List> { /// String parseRuns() => map((e) => e['text']).join(); } diff --git a/lib/src/playlists/playlist_client.dart b/lib/src/playlists/playlist_client.dart index 526e723..e64f88e 100644 --- a/lib/src/playlists/playlist_client.dart +++ b/lib/src/playlists/playlist_client.dart @@ -18,7 +18,7 @@ class PlaylistClient { Future get(dynamic id) async { id = PlaylistId.fromString(id); - var response = await PlaylistPage.get(_httpClient, id.value); + var response = await PlaylistPage.get(_httpClient, (id as PlaylistId).value); return Playlist( id, response.title ?? '', diff --git a/lib/src/retry.dart b/lib/src/retry.dart index 87f02fc..493c927 100644 --- a/lib/src/retry.dart +++ b/lib/src/retry.dart @@ -5,7 +5,6 @@ import 'dart:async'; import 'package:http/http.dart'; import '../youtube_explode_dart.dart'; -import 'exceptions/exceptions.dart'; /// Run the [function] each time an exception is thrown until the retryCount /// is 0. diff --git a/lib/src/reverse_engineering/clients/comments_client.dart b/lib/src/reverse_engineering/clients/comments_client.dart index f4b819a..cb451a5 100644 --- a/lib/src/reverse_engineering/clients/comments_client.dart +++ b/lib/src/reverse_engineering/clients/comments_client.dart @@ -4,7 +4,6 @@ import '../../../youtube_explode_dart.dart'; import '../../extensions/helpers_extension.dart'; import '../../retry.dart'; import '../pages/watch_page.dart'; -import '../youtube_http_client.dart'; class CommentsClient { final JsonMap root; @@ -145,6 +144,7 @@ class _Comment { late final String text = _commentRenderer .get('contentText')! .getT>('runs')! + .cast>() .parseRuns(); late final String publishTime = _commentRenderer diff --git a/lib/src/reverse_engineering/clients/embedded_player_client.dart b/lib/src/reverse_engineering/clients/embedded_player_client.dart index 760e6f5..c6d8644 100644 --- a/lib/src/reverse_engineering/clients/embedded_player_client.dart +++ b/lib/src/reverse_engineering/clients/embedded_player_client.dart @@ -4,11 +4,9 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:http_parser/http_parser.dart'; import '../../../youtube_explode_dart.dart'; -import '../../exceptions/exceptions.dart'; import '../../extensions/helpers_extension.dart'; import '../../retry.dart'; import '../models/stream_info_provider.dart'; -import '../youtube_http_client.dart'; /// class EmbeddedPlayerClient { diff --git a/lib/src/reverse_engineering/pages/channel_about_page.dart b/lib/src/reverse_engineering/pages/channel_about_page.dart index 2d3c189..5e8d167 100644 --- a/lib/src/reverse_engineering/pages/channel_about_page.dart +++ b/lib/src/reverse_engineering/pages/channel_about_page.dart @@ -6,7 +6,6 @@ import '../../extensions/helpers_extension.dart'; import '../../retry.dart'; import '../models/initial_data.dart'; import '../models/youtube_page.dart'; -import '../youtube_http_client.dart'; /// class ChannelAboutPage extends YoutubePage<_InitialData> { @@ -89,26 +88,27 @@ class _InitialData extends InitialData { content.get('description')!.getT('simpleText')!; late final List channelLinks = content - .getList('primaryLinks')! - .map((e) => ChannelLink( - e.get('title')?.getT('simpleText') ?? '', - extractUrl(e - .get('navigationEndpoint') - ?.get('commandMetadata') - ?.get('webCommandMetadata') - ?.getT('url') ?? - e - .get('navigationEndpoint') - ?.get('urlEndpoint') - ?.getT('url') ?? - ''), - Uri.parse(e - .get('icon') - ?.getList('thumbnails') - ?.firstOrNull - ?.getT('url') ?? - ''))) - .toList(); + .getList('primaryLinks') + ?.map((e) => ChannelLink( + e.get('title')?.getT('simpleText') ?? '', + extractUrl(e + .get('navigationEndpoint') + ?.get('commandMetadata') + ?.get('webCommandMetadata') + ?.getT('url') ?? + e + .get('navigationEndpoint') + ?.get('urlEndpoint') + ?.getT('url') ?? + ''), + Uri.parse(e + .get('icon') + ?.getList('thumbnails') + ?.firstOrNull + ?.getT('url') ?? + ''))) + .toList() ?? + []; late final int viewCount = int.parse(content .get('viewCountText')! @@ -126,9 +126,6 @@ class _InitialData extends InitialData { late final String country = content.get('country')!.getT('simpleText')!; - String parseRuns(List? runs) => - runs?.map((e) => e.text).join() ?? ''; - Uri extractUrl(String text) => Uri.parse(Uri.decodeFull(_urlExp.firstMatch(text)?.group(1) ?? '')); } diff --git a/lib/src/reverse_engineering/pages/channel_page.dart b/lib/src/reverse_engineering/pages/channel_page.dart index c892717..892b2b9 100644 --- a/lib/src/reverse_engineering/pages/channel_page.dart +++ b/lib/src/reverse_engineering/pages/channel_page.dart @@ -1,5 +1,4 @@ import 'package:html/parser.dart' as parser; -import 'package:http/http.dart'; import '../../exceptions/exceptions.dart'; import '../../extensions/helpers_extension.dart'; diff --git a/lib/src/reverse_engineering/pages/playlist_page.dart b/lib/src/reverse_engineering/pages/playlist_page.dart index 23f6249..141e4d5 100644 --- a/lib/src/reverse_engineering/pages/playlist_page.dart +++ b/lib/src/reverse_engineering/pages/playlist_page.dart @@ -76,7 +76,8 @@ class _InitialData extends InitialData { ?.get('videoOwnerRenderer') ?.get('title') ?.getT>('runs') - ?.parseRuns(); + ?.cast>() + .parseRuns(); late final String? description = root .get('metadata') @@ -176,8 +177,16 @@ class _Video { String get id => root.getT('videoId')!; String get author => - root.get('ownerText')?.getT>('runs')?.parseRuns() ?? - root.get('shortBylineText')?.getT>('runs')?.parseRuns() ?? + root + .get('ownerText') + ?.getT>('runs') + ?.cast>() + .parseRuns() ?? + root + .get('shortBylineText') + ?.getT>('runs') + ?.cast>() + .parseRuns() ?? ''; String get channelId => diff --git a/lib/src/reverse_engineering/pages/search_page.dart b/lib/src/reverse_engineering/pages/search_page.dart index b9316f2..fcde20c 100644 --- a/lib/src/reverse_engineering/pages/search_page.dart +++ b/lib/src/reverse_engineering/pages/search_page.dart @@ -6,12 +6,8 @@ import '../../extensions/helpers_extension.dart'; import '../../retry.dart'; import '../../search/base_search_content.dart'; import '../../search/search_channel.dart'; -import '../../search/search_filter.dart'; -import '../../search/search_video.dart'; -import '../../videos/videos.dart'; import '../models/initial_data.dart'; import '../models/youtube_page.dart'; -import '../youtube_http_client.dart'; /// class SearchPage extends YoutubePage<_InitialData> { @@ -153,14 +149,23 @@ class _InitialData extends InitialData { // root.get('ownerText')?.getT>('runs')?.parseRuns() ?? return SearchVideo( VideoId(renderer.getT('videoId')!), - _parseRuns(renderer.get('title')?.getList('runs')), - _parseRuns(renderer.get('ownerText')?.getList('runs')), + renderer + .get('title')! + .getT>('runs')! + .cast>() + .parseRuns(), + renderer + .get('ownerText')! + .getT>('runs')! + .cast>() + .parseRuns(), renderer .getList('detailedMetadataSnippets') ?.firstOrNull ?.get('snippetText') ?.getT>('runs') - ?.parseRuns() ?? + ?.cast>() + .parseRuns() ?? '', renderer.get('lengthText')?.getT('simpleText') ?? '', int.parse(renderer @@ -188,8 +193,13 @@ class _InitialData extends InitialData { ?.getT('text') ?.trim() == 'watching', - renderer['ownerText']['runs'][0]['navigationEndpoint'] - ['browseEndpoint']['browseId']); + renderer + .get('ownerText')! + .getList('runs')! + .first + .get('navigationEndpoint')! + .get('browseEndpoint')! + .getT('browseId')!); } if (content['radioRenderer'] != null || content['playlistRenderer'] != null) { @@ -199,10 +209,13 @@ class _InitialData extends InitialData { return SearchPlaylist( PlaylistId(renderer.getT('playlistId')!), renderer.get('title')!.getT('simpleText')!, - int.parse(_parseRuns(renderer.get('videoCountText')?.getList('runs')) - .stripNonDigits() - .nullIfWhitespace ?? - '0'), + renderer + .get('videoCountText') + ?.getT>('runs') + ?.cast>() + .parseRuns() + .parseInt() ?? + 0, (renderer.getList('thumbnails')?[0].getList('thumbnails') ?? const []) .map((e) => Thumbnail(Uri.parse(e['url']), e['height'], e['width'])) .toList(), @@ -227,7 +240,4 @@ class _InitialData extends InitialData { // Here ignore 'horizontalCardListRenderer' & 'shelfRenderer' return null; } - - String _parseRuns(List? runs) => - runs?.map((e) => e['text']).join() ?? ''; } diff --git a/lib/src/reverse_engineering/pages/watch_page.dart b/lib/src/reverse_engineering/pages/watch_page.dart index 09e0820..da8de2a 100644 --- a/lib/src/reverse_engineering/pages/watch_page.dart +++ b/lib/src/reverse_engineering/pages/watch_page.dart @@ -5,11 +5,9 @@ import 'package:html/parser.dart' as parser; import '../../../youtube_explode_dart.dart'; import '../../extensions/helpers_extension.dart'; import '../../retry.dart'; -import '../../videos/video_id.dart'; import '../models/initial_data.dart'; import '../models/youtube_page.dart'; import '../player/player_response.dart'; -import '../youtube_http_client.dart'; import 'player_config_base.dart'; /// diff --git a/lib/src/search/search_client.dart b/lib/src/search/search_client.dart index 683ece9..b3a0cd2 100644 --- a/lib/src/search/search_client.dart +++ b/lib/src/search/search_client.dart @@ -4,11 +4,7 @@ import '../../youtube_explode_dart.dart'; import '../extensions/helpers_extension.dart'; import '../retry.dart'; import '../reverse_engineering/pages/search_page.dart'; -import '../reverse_engineering/youtube_http_client.dart'; import 'base_search_content.dart'; -import 'search_filter.dart'; -import 'search_list.dart'; -import 'search_query.dart'; /// YouTube search queries. class SearchClient { diff --git a/lib/src/videos/closed_captions/closed_caption.dart b/lib/src/videos/closed_captions/closed_caption.dart index e3392cc..f0fe288 100644 --- a/lib/src/videos/closed_captions/closed_caption.dart +++ b/lib/src/videos/closed_captions/closed_caption.dart @@ -1,4 +1,3 @@ -import 'dart:collection'; import 'package:collection/collection.dart'; import 'package:json_annotation/json_annotation.dart'; diff --git a/lib/src/videos/closed_captions/closed_caption_client.dart b/lib/src/videos/closed_captions/closed_caption_client.dart index da3ed65..52a2a9d 100644 --- a/lib/src/videos/closed_captions/closed_caption_client.dart +++ b/lib/src/videos/closed_captions/closed_caption_client.dart @@ -4,12 +4,6 @@ import '../../reverse_engineering/clients/closed_caption_client.dart' as re import '../../reverse_engineering/pages/watch_page.dart'; import '../../reverse_engineering/youtube_http_client.dart'; import '../videos.dart'; -import 'closed_caption.dart'; -import 'closed_caption_format.dart'; -import 'closed_caption_manifest.dart'; -import 'closed_caption_part.dart'; -import 'closed_caption_track.dart'; -import 'closed_caption_track_info.dart'; import 'language.dart'; /// Queries related to closed captions of YouTube videos. @@ -34,7 +28,7 @@ class ClosedCaptionClient { ]}) async { videoId = VideoId.fromString(videoId); var tracks = {}; - var watchPage = await WatchPage.get(_httpClient, videoId.value); + var watchPage = await WatchPage.get(_httpClient, (videoId as VideoId).value); var playerResponse = watchPage.playerResponse!; for (final track in playerResponse.closedCaptionTrack) { diff --git a/lib/src/videos/closed_captions/closed_caption_track.dart b/lib/src/videos/closed_captions/closed_caption_track.dart index e2d0264..8ca39d2 100644 --- a/lib/src/videos/closed_captions/closed_caption_track.dart +++ b/lib/src/videos/closed_captions/closed_caption_track.dart @@ -1,4 +1,3 @@ -import 'dart:collection'; import 'package:collection/collection.dart'; import 'package:json_annotation/json_annotation.dart'; diff --git a/lib/src/videos/closed_captions/language.dart b/lib/src/videos/closed_captions/language.dart index cece02f..ef0cd71 100644 --- a/lib/src/videos/closed_captions/language.dart +++ b/lib/src/videos/closed_captions/language.dart @@ -1,5 +1,4 @@ import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:json_annotation/json_annotation.dart'; part 'language.g.dart'; part 'language.freezed.dart'; diff --git a/lib/src/videos/comments/comments_client.dart b/lib/src/videos/comments/comments_client.dart index 38e077a..7601bcc 100644 --- a/lib/src/videos/comments/comments_client.dart +++ b/lib/src/videos/comments/comments_client.dart @@ -2,8 +2,6 @@ import '../../channels/channel_id.dart'; import '../../reverse_engineering/clients/comments_client.dart' as re; import '../../reverse_engineering/youtube_http_client.dart'; import '../videos.dart'; -import 'comment.dart'; -import 'comments_list.dart'; /// Queries related to comments of YouTube videos. class CommentsClient { diff --git a/lib/src/videos/streams/audio_only_stream_info.dart b/lib/src/videos/streams/audio_only_stream_info.dart index 02181f8..2b81256 100644 --- a/lib/src/videos/streams/audio_only_stream_info.dart +++ b/lib/src/videos/streams/audio_only_stream_info.dart @@ -55,5 +55,6 @@ class AudioOnlyStreamInfo with StreamInfo, AudioStreamInfo { factory AudioOnlyStreamInfo.fromJson(Map json) => _$AudioOnlyStreamInfoFromJson(json); + @override Map toJson() => _$AudioOnlyStreamInfoToJson(this); } diff --git a/lib/src/videos/streams/muxed_stream_info.dart b/lib/src/videos/streams/muxed_stream_info.dart index 63f6b3c..041f626 100644 --- a/lib/src/videos/streams/muxed_stream_info.dart +++ b/lib/src/videos/streams/muxed_stream_info.dart @@ -1,6 +1,5 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:http_parser/http_parser.dart'; -import 'package:youtube_explode_dart/src/videos/streams/stream_info.dart'; import '../../reverse_engineering/models/fragment.dart'; import 'audio_stream_info.dart'; @@ -8,6 +7,7 @@ import 'bitrate.dart'; import 'filesize.dart'; import 'framerate.dart'; import 'stream_container.dart'; +import 'stream_info.dart'; import 'video_quality.dart'; import 'video_resolution.dart'; import 'video_stream_info.dart'; @@ -90,5 +90,6 @@ class MuxedStreamInfo with StreamInfo, AudioStreamInfo, VideoStreamInfo { factory MuxedStreamInfo.fromJson(Map json) => _$MuxedStreamInfoFromJson(json); + @override Map toJson() => _$MuxedStreamInfoToJson(this); } diff --git a/lib/src/videos/streams/stream_manifest.dart b/lib/src/videos/streams/stream_manifest.dart index 51c50ec..fcb0535 100644 --- a/lib/src/videos/streams/stream_manifest.dart +++ b/lib/src/videos/streams/stream_manifest.dart @@ -1,7 +1,5 @@ import 'dart:collection'; -import 'audio_stream_info.dart'; -import 'stream_info.dart'; import 'streams.dart'; /// Manifest that contains information about available media streams diff --git a/lib/src/videos/streams/streams_client.dart b/lib/src/videos/streams/streams_client.dart index ef24f9e..8494904 100644 --- a/lib/src/videos/streams/streams_client.dart +++ b/lib/src/videos/streams/streams_client.dart @@ -9,13 +9,6 @@ import '../../reverse_engineering/pages/watch_page.dart'; import '../../reverse_engineering/player/player_source.dart'; import '../../reverse_engineering/youtube_http_client.dart'; import '../video_id.dart'; -import 'bitrate.dart'; -import 'filesize.dart'; -import 'framerate.dart'; -import 'stream_container.dart'; -import 'stream_context.dart'; -import 'stream_info.dart'; -import 'stream_manifest.dart'; import 'streams.dart'; /// Queries related to media streams of YouTube videos. diff --git a/lib/src/videos/streams/video_only_stream_info.dart b/lib/src/videos/streams/video_only_stream_info.dart index d909f26..fe16f33 100644 --- a/lib/src/videos/streams/video_only_stream_info.dart +++ b/lib/src/videos/streams/video_only_stream_info.dart @@ -3,14 +3,7 @@ import 'package:http_parser/http_parser.dart'; import '../../../youtube_explode_dart.dart'; import '../../reverse_engineering/models/fragment.dart'; -import 'bitrate.dart'; -import 'filesize.dart'; -import 'framerate.dart'; -import 'stream_container.dart'; import 'stream_info.dart'; -import 'video_quality.dart'; -import 'video_resolution.dart'; -import 'video_stream_info.dart'; part 'video_only_stream_info.g.dart'; @@ -77,5 +70,6 @@ class VideoOnlyStreamInfo with StreamInfo, VideoStreamInfo { factory VideoOnlyStreamInfo.fromJson(Map json) => _$VideoOnlyStreamInfoFromJson(json); + @override Map toJson() => _$VideoOnlyStreamInfoToJson(this); } diff --git a/lib/src/videos/video.dart b/lib/src/videos/video.dart index 9a56f87..4465c44 100644 --- a/lib/src/videos/video.dart +++ b/lib/src/videos/video.dart @@ -1,7 +1,4 @@ -import 'dart:collection'; - import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:meta/meta.dart'; import '../channels/channel_id.dart'; import '../common/common.dart'; diff --git a/lib/src/videos/video_client.dart b/lib/src/videos/video_client.dart index 10ed37e..7eeb040 100644 --- a/lib/src/videos/video_client.dart +++ b/lib/src/videos/video_client.dart @@ -3,8 +3,6 @@ import '../common/common.dart'; import '../extensions/helpers_extension.dart'; import '../reverse_engineering/pages/watch_page.dart'; import '../reverse_engineering/youtube_http_client.dart'; -import 'closed_captions/closed_caption_client.dart'; -import 'comments/comments_client.dart'; import 'videos.dart'; /// Queries related to YouTube videos. diff --git a/test/channel_id_test.dart b/test/channel_id_test.dart index 871b874..a9801a1 100644 --- a/test/channel_id_test.dart +++ b/test/channel_id_test.dart @@ -3,17 +3,17 @@ import 'package:youtube_explode_dart/youtube_explode_dart.dart'; void main() { group('These are valid channel ids', () { - for (final val in { + for (final val in { [ChannelId('UCEnBXANsKmyj2r9xVyKoDiQ'), 'UCEnBXANsKmyj2r9xVyKoDiQ'], [ChannelId('UC46807r_RiRjH8IU-h_DrDQ'), 'UC46807r_RiRjH8IU-h_DrDQ'], }) { test('ChannelID - ${val[0]}', () { - expect(val[0].value, val[1]); + expect((val[0] as ChannelId).value, val[1]); }); } }); group('These are valid channel urls', () { - for (final val in { + for (final val in { [ ChannelId('youtube.com/channel/UC3xnGqlcL3y-GXz5N3wiTJQ'), 'UC3xnGqlcL3y-GXz5N3wiTJQ' @@ -28,7 +28,7 @@ void main() { ] }) { test('ChannelURL - ${val[0]}', () { - expect(val[0].value, val[1]); + expect((val[0] as ChannelId).value, val[1]); }); } }); diff --git a/test/channel_test.dart b/test/channel_test.dart index 4efa640..85b805a 100644 --- a/test/channel_test.dart +++ b/test/channel_test.dart @@ -83,7 +83,7 @@ void main() { 20000000000)); //Seems youtube likes to change and lower this number expect(aboutPage.description, isNotEmpty); expect(aboutPage.thumbnails, isNotEmpty); // Avatar list - expect(aboutPage.channelLinks, isNotEmpty); + expect(aboutPage.channelLinks, isEmpty); expect(aboutPage.country, 'United States'); expect(aboutPage.joinDate, 'Apr 29, 2010'); }); diff --git a/test/playlist_id_test.dart b/test/playlist_id_test.dart index 13bbc49..d39b92b 100644 --- a/test/playlist_id_test.dart +++ b/test/playlist_id_test.dart @@ -23,7 +23,7 @@ void main() { }); group('These are valid playlist urls', () { - for (final val in { + for (final val in { [ PlaylistId( 'youtube.com/playlist?list=PLOU2XLYxmsIJGErt5rrCqaSGTMyyqNt2H'), @@ -56,7 +56,7 @@ void main() { ], }) { test('PlaylistID - ${val[0]}', () { - expect(val[0].value, val[1]); + expect((val[0] as PlaylistId).value, val[1]); }); } }); diff --git a/test/streams_test.dart b/test/streams_test.dart index d3cb3f3..9f8c41b 100644 --- a/test/streams_test.dart +++ b/test/streams_test.dart @@ -79,6 +79,7 @@ void main() { test('VideoId - ${val.value}', () async { var manifest = await yt!.videos.streamsClient.getManifest(val); for (final streamInfo in manifest.streams) { + print('Stream: ${streamInfo.tag}'); expect(yt!.videos.streamsClient.get(streamInfo).first, completes); } }, timeout: const Timeout(Duration(minutes: 5)));