youtube_explode/lib/src/videos/comments/comments_client.dart

148 lines
4.9 KiB
Dart
Raw Normal View History

import 'dart:convert';
import '../../channels/channel_id.dart';
import '../../extensions/helpers_extension.dart';
import '../../retry.dart';
import '../../reverse_engineering/youtube_http_client.dart';
import '../videos.dart';
import 'comment.dart';
/// Queries related to comments of YouTube videos.
class CommentsClient {
final YoutubeHttpClient _httpClient;
/// Initializes an instance of [CommentsClient]
CommentsClient(this._httpClient);
/// Returns the json parsed comments map.
2020-06-21 16:41:56 +02:00
Future<Map<String, dynamic>> _getCommentJson(
String continuation,
String clickTrackingParams,
String xsfrToken,
String visitorInfoLive,
String ysc) async {
2021-06-24 15:23:35 +02:00
final url = Uri(
scheme: 'https',
host: 'www.youtube.com',
2021-07-21 02:06:02 +02:00
path: '/next',
2021-06-24 15:23:35 +02:00
queryParameters: {
2021-07-21 02:06:02 +02:00
'key': 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',
2021-06-24 15:23:35 +02:00
});
return retry(() async {
var raw = await _httpClient.postString(url, headers: {
2021-07-18 16:12:31 +02:00
'x-youtube-client-name': '1',
2021-06-24 15:23:35 +02:00
'x-youtube-client-version': '2.20210622.10.00',
'cookie':
'YSC=$ysc; CONSENT=YES+cb; GPS=1; VISITOR_INFO1_LIVE=$visitorInfoLive',
}, body: {
'session_token': xsfrToken
});
return json.decode(raw);
});
}
/// Returns a stream emitting all the [video]'s comment.
/// A request is page for every comment page,
/// a page contains at most 20 comments, use .take if you want to limit
/// the results.
///
/// The streams doesn't emit any data if [Video.hasWatchPage] is false.
2020-09-21 17:34:03 +02:00
/// Use `videos.get(videoId, forceWatchPage: true)` to assure that the
/// WatchPage is fetched.
Stream<Comment> getComments(Video video) async* {
if (video.watchPage == null) {
return;
}
yield* _getComments(
2021-03-11 14:20:10 +01:00
video.watchPage!.initialData.continuation,
video.watchPage!.initialData.clickTrackingParams,
video.watchPage!.xsfrToken,
video.watchPage!.visitorInfoLive,
video.watchPage!.ysc);
}
Stream<Comment> _getComments(String continuation, String clickTrackingParams,
String xsfrToken, String visitorInfoLive, String ysc) async* {
2021-07-21 02:06:02 +02:00
// contents.twoColumnWatchNextResults.results.results.contents[2](firstWhere itemSectionRenderer != null).itemSectionRenderer.contents[0].continuationItemRenderer
var data = await _getCommentJson(
continuation, clickTrackingParams, xsfrToken, visitorInfoLive, ysc);
2021-06-24 15:23:35 +02:00
var contentRoot = data
.get('response')
?.get('continuationContents')
?.get('itemSectionContinuation')
?.getT<List<dynamic>>('contents')
?.map((e) => e['commentThreadRenderer'])
2021-06-24 15:23:35 +02:00
.toList()
.cast<Map<String, dynamic>>();
if (contentRoot == null) {
return;
}
2021-03-11 14:20:10 +01:00
for (final content in contentRoot) {
2021-06-24 15:23:35 +02:00
var commentRaw = content.get('comment')!.get('commentRenderer')!;
2021-03-11 14:20:10 +01:00
String? continuation;
String? clickTrackingParams;
2021-06-24 15:23:35 +02:00
final replies = content.get('replies');
if (replies != null) {
final continuationData = replies
.get('commentRepliesRenderer')!
.getList('continuations')!
.first
.get('nextContinuationData')!;
continuation = continuationData.getT<String>('continuation');
clickTrackingParams =
continuationData.getT<String>('clickTrackingParams');
}
2021-07-18 16:12:31 +02:00
yield Comment(
2021-06-24 15:23:35 +02:00
commentRaw.getT<String>('commentId')!,
commentRaw.get('authorText')!.getT<String>('simpleText')!,
ChannelId(commentRaw
.get('authorEndpoint')!
.get('browseEndpoint')!
.getT<String>('browseId')!),
commentRaw
.get('contentText')!
.getT<List<dynamic>>('runs')!
.parseRuns(),
commentRaw.get('voteCount')?.getT<String>('simpleText')?.parseInt() ??
commentRaw
.get('voteCount')
?.getT<List<dynamic>>('runs')
?.parseRuns()
.parseInt() ??
0,
commentRaw
.get('publishedTimeText')!
.getT<List<dynamic>>('runs')!
.parseRuns(),
commentRaw.getT<int>('replyCount') ?? 0,
continuation,
clickTrackingParams);
}
var continuationRoot = (data
2021-03-11 14:20:10 +01:00
.get('response')
?.get('continuationContents')
?.get('itemSectionContinuation')
2021-06-24 15:23:35 +02:00
?.getT<List<dynamic>>('continuations')
?.first)
?.get('nextContinuationData');
if (continuationRoot != null) {
yield* _getComments(
continuationRoot['continuation'],
continuationRoot['clickTrackingParams'],
xsfrToken,
visitorInfoLive,
ysc);
}
}
2021-07-21 02:06:02 +02:00
Stream<Comment> getReplies(Video video, Comment comment) async* {
if (video.watchPage == null ||
comment.continuation == null ||
comment.clicktrackingParams == null) {
return;
}
}
}