diff --git a/CHANGELOG.md b/CHANGELOG.md index d2184fc..68556b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 1.10.5 +- Implement: `CommentsList.totalCount` (#150), `Comment.isHearted` (#151). + ## 1.10.4 - Fix infinite loop when getting channel uploads. diff --git a/lib/src/reverse_engineering/clients/comments_client.dart b/lib/src/reverse_engineering/clients/comments_client.dart index dec7af5..adfbd56 100644 --- a/lib/src/reverse_engineering/clients/comments_client.dart +++ b/lib/src/reverse_engineering/clients/comments_client.dart @@ -84,8 +84,10 @@ class CommentsClient { ?.getT('token'); } + // onResponseReceivedEndpoints[0].reloadContinuationItemsCommand.continuationItems[0].commentsHeaderRenderer int getCommentsCount() => root - .getList('onResponseReceivedEndpoints')![1] + .getList('onResponseReceivedEndpoints')! + .first .get('reloadContinuationItemsCommand')! .getList('continuationItems')! .first @@ -156,6 +158,12 @@ class _Comment { ?.getT('simpleText') ?.parseIntWithUnits(); + late final bool isHearted = _commentRenderer + .get('actionButtons') + ?.get('commentActionButtonsRenderer') + ?.get('creatorHeart') != + null; + _Comment(this.root); @override diff --git a/lib/src/videos/comments/comment.dart b/lib/src/videos/comments/comment.dart index 558b124..7380621 100644 --- a/lib/src/videos/comments/comment.dart +++ b/lib/src/videos/comments/comment.dart @@ -27,6 +27,9 @@ class Comment with _$Comment { /// Comment reply count. int replyCount, + /// True if the comment is hearted by the creator. + bool isHearted, + /// Used internally. /// Shouldn't be used in the code. @internal String? continuation, diff --git a/lib/src/videos/comments/comment.freezed.dart b/lib/src/videos/comments/comment.freezed.dart index e4d37cc..ad06c14 100644 --- a/lib/src/videos/comments/comment.freezed.dart +++ b/lib/src/videos/comments/comment.freezed.dart @@ -16,8 +16,15 @@ final _privateConstructorUsedError = UnsupportedError( class _$CommentTearOff { const _$CommentTearOff(); - _Comment call(String author, ChannelId channelId, String text, int likeCount, - String publishedTime, int replyCount, @internal String? continuation) { + _Comment call( + String author, + ChannelId channelId, + String text, + int likeCount, + String publishedTime, + int replyCount, + bool isHearted, + @internal String? continuation) { return _Comment( author, channelId, @@ -25,6 +32,7 @@ class _$CommentTearOff { likeCount, publishedTime, replyCount, + isHearted, continuation, ); } @@ -53,6 +61,9 @@ mixin _$Comment { /// Comment reply count. int get replyCount => throw _privateConstructorUsedError; + /// True if the comment is hearted by the creator. + bool get isHearted => throw _privateConstructorUsedError; + /// Used internally. /// Shouldn't be used in the code. @internal @@ -73,6 +84,7 @@ abstract class $CommentCopyWith<$Res> { int likeCount, String publishedTime, int replyCount, + bool isHearted, @internal String? continuation}); $ChannelIdCopyWith<$Res> get channelId; @@ -94,6 +106,7 @@ class _$CommentCopyWithImpl<$Res> implements $CommentCopyWith<$Res> { Object? likeCount = freezed, Object? publishedTime = freezed, Object? replyCount = freezed, + Object? isHearted = freezed, Object? continuation = freezed, }) { return _then(_value.copyWith( @@ -121,6 +134,10 @@ class _$CommentCopyWithImpl<$Res> implements $CommentCopyWith<$Res> { ? _value.replyCount : replyCount // ignore: cast_nullable_to_non_nullable as int, + isHearted: isHearted == freezed + ? _value.isHearted + : isHearted // ignore: cast_nullable_to_non_nullable + as bool, continuation: continuation == freezed ? _value.continuation : continuation // ignore: cast_nullable_to_non_nullable @@ -148,6 +165,7 @@ abstract class _$CommentCopyWith<$Res> implements $CommentCopyWith<$Res> { int likeCount, String publishedTime, int replyCount, + bool isHearted, @internal String? continuation}); @override @@ -171,6 +189,7 @@ class __$CommentCopyWithImpl<$Res> extends _$CommentCopyWithImpl<$Res> Object? likeCount = freezed, Object? publishedTime = freezed, Object? replyCount = freezed, + Object? isHearted = freezed, Object? continuation = freezed, }) { return _then(_Comment( @@ -198,6 +217,10 @@ class __$CommentCopyWithImpl<$Res> extends _$CommentCopyWithImpl<$Res> ? _value.replyCount : replyCount // ignore: cast_nullable_to_non_nullable as int, + isHearted == freezed + ? _value.isHearted + : isHearted // ignore: cast_nullable_to_non_nullable + as bool, continuation == freezed ? _value.continuation : continuation // ignore: cast_nullable_to_non_nullable @@ -209,8 +232,15 @@ class __$CommentCopyWithImpl<$Res> extends _$CommentCopyWithImpl<$Res> /// @nodoc class _$_Comment implements _Comment { - const _$_Comment(this.author, this.channelId, this.text, this.likeCount, - this.publishedTime, this.replyCount, @internal this.continuation); + const _$_Comment( + this.author, + this.channelId, + this.text, + this.likeCount, + this.publishedTime, + this.replyCount, + this.isHearted, + @internal this.continuation); @override @@ -238,6 +268,10 @@ class _$_Comment implements _Comment { final int replyCount; @override + /// True if the comment is hearted by the creator. + final bool isHearted; + @override + /// Used internally. /// Shouldn't be used in the code. @internal @@ -245,7 +279,7 @@ class _$_Comment implements _Comment { @override String toString() { - return 'Comment(author: $author, channelId: $channelId, text: $text, likeCount: $likeCount, publishedTime: $publishedTime, replyCount: $replyCount, continuation: $continuation)'; + return 'Comment(author: $author, channelId: $channelId, text: $text, likeCount: $likeCount, publishedTime: $publishedTime, replyCount: $replyCount, isHearted: $isHearted, continuation: $continuation)'; } @override @@ -268,6 +302,9 @@ class _$_Comment implements _Comment { (identical(other.replyCount, replyCount) || const DeepCollectionEquality() .equals(other.replyCount, replyCount)) && + (identical(other.isHearted, isHearted) || + const DeepCollectionEquality() + .equals(other.isHearted, isHearted)) && (identical(other.continuation, continuation) || const DeepCollectionEquality() .equals(other.continuation, continuation))); @@ -282,6 +319,7 @@ class _$_Comment implements _Comment { const DeepCollectionEquality().hash(likeCount) ^ const DeepCollectionEquality().hash(publishedTime) ^ const DeepCollectionEquality().hash(replyCount) ^ + const DeepCollectionEquality().hash(isHearted) ^ const DeepCollectionEquality().hash(continuation); @JsonKey(ignore: true) @@ -298,6 +336,7 @@ abstract class _Comment implements Comment { int likeCount, String publishedTime, int replyCount, + bool isHearted, @internal String? continuation) = _$_Comment; @override @@ -326,6 +365,10 @@ abstract class _Comment implements Comment { int get replyCount => throw _privateConstructorUsedError; @override + /// True if the comment is hearted by the creator. + bool get isHearted => throw _privateConstructorUsedError; + @override + /// Used internally. /// Shouldn't be used in the code. @internal diff --git a/lib/src/videos/comments/comments_client.dart b/lib/src/videos/comments/comments_client.dart index f06f714..38e077a 100644 --- a/lib/src/videos/comments/comments_client.dart +++ b/lib/src/videos/comments/comments_client.dart @@ -34,8 +34,10 @@ class CommentsClient { e.likeCount ?? 0, e.publishTime, e.repliesCount ?? 0, + e.isHearted, e.continuation)) .toList(growable: false), + page.getCommentsCount(), page, _httpClient); } @@ -61,8 +63,10 @@ class CommentsClient { e.likeCount ?? 0, e.publishTime, e.repliesCount ?? 0, + e.isHearted, e.continuation)) .toList(growable: false), + 0, page, _httpClient); } diff --git a/lib/src/videos/comments/comments_list.dart b/lib/src/videos/comments/comments_list.dart index fbd8889..69e876d 100644 --- a/lib/src/videos/comments/comments_list.dart +++ b/lib/src/videos/comments/comments_list.dart @@ -10,10 +10,12 @@ import '../../../youtube_explode_dart.dart'; class CommentsList extends DelegatingList { final re.CommentsClient _client; final YoutubeHttpClient _httpClient; + final int totalLength; /// Construct an instance of [SearchList] /// See [SearchList] - CommentsList(List base, this._client, this._httpClient) + CommentsList( + List base, this.totalLength, this._client, this._httpClient) : super(base); /// Fetches the next batch of videos or returns null if there are no more @@ -33,8 +35,10 @@ class CommentsList extends DelegatingList { e.likeCount ?? 0, e.publishTime, e.repliesCount ?? 0, + e.isHearted, e.continuation)) .toList(growable: false), + totalLength, page, _httpClient); } diff --git a/pubspec.yaml b/pubspec.yaml index c3d4e23..9bf5f0d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: youtube_explode_dart description: A port in dart of the youtube explode library. Supports several API functions without the need of Youtube API Key. -version: 1.10.4 +version: 1.10.5 homepage: https://github.com/Hexer10/youtube_explode_dart diff --git a/test/comments_client_test.dart b/test/comments_client_test.dart index 100e9be..84e1f72 100644 --- a/test/comments_client_test.dart +++ b/test/comments_client_test.dart @@ -14,7 +14,9 @@ void main() { test('Get comments of a video', () async { var videoUrl = 'https://www.youtube.com/watch?v=AI7ULzgf8RU'; var video = await yt!.videos.get(VideoId(videoUrl)); - var comments = await yt!.videos.commentsClient.getComments(video); - expect(comments!.length, greaterThanOrEqualTo(1)); + var comments = (await yt!.videos.commentsClient.getComments(video))!; + expect(comments.length, greaterThanOrEqualTo(1)); + expect(comments.totalLength, greaterThanOrEqualTo(3)); + expect(comments.first.isHearted, false); }); } diff --git a/test/streams_test.dart b/test/streams_test.dart index 996e840..72f64e7 100644 --- a/test/streams_test.dart +++ b/test/streams_test.dart @@ -14,7 +14,6 @@ void main() { group('Get streams manifest of any video', () { for (final val in { VideoId('9bZkp7q19f0'), //Normal - VideoId('ZGdLIwrGHG8'), //Unlisted VideoId('rsAAeyAr-9Y'), //LiveStreamRecording VideoId('V5Fsj_sCKdg'), //ContainsHighQualityStreams VideoId('AI7ULzgf8RU'), //ContainsDashManifest @@ -62,7 +61,6 @@ void main() { group('Get specific stream of any playable video', () { for (final val in { VideoId('9bZkp7q19f0'), //Normal - VideoId('ZGdLIwrGHG8'), //Unlisted VideoId('rsAAeyAr-9Y'), //LiveStreamRecording VideoId('V5Fsj_sCKdg'), //ContainsHighQualityStreams VideoId('AI7ULzgf8RU'), //ContainsDashManifest diff --git a/test/video_test.dart b/test/video_test.dart index 2dd639c..6791c1a 100644 --- a/test/video_test.dart +++ b/test/video_test.dart @@ -49,7 +49,6 @@ void main() { group('Get metadata of any video', () { for (final val in { VideoId('9bZkp7q19f0'), //Normal - VideoId('ZGdLIwrGHG8'), //Unlisted VideoId('5qap5aO4i9A'), //LiveStream VideoId('rsAAeyAr-9Y'), //LiveStreamRecording VideoId('V5Fsj_sCKdg'), //ContainsHighQualityStreams