youtube_explode/lib/src/search/search_client.dart

111 lines
3.7 KiB
Dart
Raw Normal View History

2021-03-11 23:28:51 +01:00
import 'dart:convert';
import '../../youtube_explode_dart.dart';
2021-03-20 18:31:53 +01:00
import '../extensions/helpers_extension.dart';
import '../retry.dart';
2021-07-21 02:06:02 +02:00
import '../reverse_engineering/pages/search_page.dart';
2020-09-21 17:34:03 +02:00
import 'base_search_content.dart';
2020-06-06 11:28:36 +02:00
/// YouTube search queries.
class SearchClient {
final YoutubeHttpClient _httpClient;
/// Initializes an instance of [SearchClient]
SearchClient(this._httpClient);
/// Enumerates videos returned by the specified search query
/// (from the video search page).
/// The videos are sent in batch of 20 videos.
/// You [SearchList.nextPage] to get the next batch of videos.
Future<SearchList> getVideos(String searchQuery,
{SearchFilter filter = const SearchFilter('')}) async {
2021-03-20 18:31:53 +01:00
final page = await SearchPage.get(_httpClient, searchQuery, filter: filter);
return SearchList(
2021-08-31 18:06:34 +02:00
page.searchContent
2021-03-20 18:31:53 +01:00
.whereType<SearchVideo>()
.map((e) => Video(
e.id,
e.title,
e.author,
ChannelId(e.channelId),
e.uploadDate?.toDateTime(),
null,
e.description,
e.duration.toDuration(),
ThumbnailSet(e.id.value),
null,
Engagement(e.viewCount, null, null),
e.isLive))
2021-03-20 18:31:53 +01:00
.toList(),
page,
_httpClient);
2020-06-06 11:28:36 +02:00
}
2020-06-13 22:54:53 +02:00
2020-09-21 17:34:03 +02:00
/// Enumerates videos returned by the specified search query
/// (from the video search page).
/// Contains only instances of [SearchVideo] or [SearchPlaylist]
@Deprecated(
'Since version 1.9.0 this is the same as [SearchClient.getVideos].')
Stream<BaseSearchContent> getVideosFromPage(String searchQuery,
{bool onlyVideos = true,
SearchFilter filter = const SearchFilter('')}) async* {
2021-03-20 18:31:53 +01:00
SearchPage? page;
2020-09-21 17:34:03 +02:00
// ignore: literal_only_boolean_expressions
2021-03-20 18:31:53 +01:00
for (;;) {
2020-09-21 17:34:03 +02:00
if (page == null) {
2021-09-28 16:49:38 +02:00
page = await retry(
_httpClient,
() async =>
SearchPage.get(_httpClient, searchQuery, filter: filter));
2021-03-20 18:31:53 +01:00
} else {
page = await page.nextPage(_httpClient);
if (page == null) {
return;
}
2020-09-21 17:34:03 +02:00
}
if (onlyVideos) {
yield* Stream.fromIterable(
2021-08-31 18:06:34 +02:00
page!.searchContent.whereType<SearchVideo>());
} else {
2021-08-31 18:06:34 +02:00
yield* Stream.fromIterable(page!.searchContent);
}
2020-09-21 17:34:03 +02:00
}
}
2021-03-11 23:28:51 +01:00
/// Returns the suggestions youtube provide while search on the page.
Future<List<String>> getQuerySuggestions(String query) async {
final request = await _httpClient.get(
'https://suggestqueries-clients6.youtube.com/complete/search?client=youtube&hl=en&gl=en&q=${Uri.encodeComponent(query)}&callback=func');
final body = request.body;
final startIndex = body.indexOf('func(');
final jsonStr = body.substring(startIndex + 5, body.length - 1);
final data = json.decode(jsonStr) as List<dynamic>;
final suggestions = data[1] as List<dynamic>;
return suggestions.map((e) => e[0]).toList().cast<String>();
}
2020-06-13 22:54:53 +02:00
/// Queries to YouTube to get the results.
2020-10-17 22:09:52 +02:00
@Deprecated('Use getVideosFromPage instead - '
'Should be used only to get related videos')
Future<SearchQuery> queryFromPage(String searchQuery) =>
SearchQuery.search(_httpClient, searchQuery);
2020-06-06 11:28:36 +02:00
}
2020-09-21 17:34:03 +02:00
/*
channelId = ChannelId.fromString(channelId);
var page = await ChannelUploadPage.get(
_httpClient, channelId.value, videoSorting.code);
yield* Stream.fromIterable(page.initialData.uploads);
// ignore: literal_only_boolean_expressions
while (true) {
page = await page.nextPage(_httpClient);
if (page == null) {
return;
}
yield* Stream.fromIterable(page.initialData.uploads);
}
*/