Version 1.9.3

This commit is contained in:
Mattia 2021-04-30 23:49:49 +02:00
parent 0f3d5e7a16
commit d405feff2f
9 changed files with 123 additions and 41 deletions

View File

@ -1,3 +1,6 @@
## 1.9.3
- `getUploadsFromPage` now returns an instance of `ChannelUploadsList`.
## 1.9.2+2
- Fix `videoThumbnail` in `ChannelVideo`.

View File

@ -1,3 +1,5 @@
import 'package:youtube_explode_dart/src/channels/channel_uploads_list.dart';
import '../common/common.dart';
import '../extensions/helpers_extension.dart';
import '../playlists/playlists.dart';
@ -9,7 +11,7 @@ import '../videos/video.dart';
import '../videos/video_id.dart';
import 'channel.dart';
import 'channel_id.dart';
import 'channel_video.dart';
import 'channel_uploads_list.dart';
import 'channels.dart';
import 'username.dart';
import 'video_sorting.dart';
@ -113,20 +115,33 @@ class ChannelClient {
///
/// Note that this endpoint provides less info about each video
/// (only the Title and VideoId).
Stream<ChannelVideo> getUploadsFromPage(dynamic channelId,
[VideoSorting videoSorting = VideoSorting.newest]) async* {
Future<ChannelUploadsList> getUploadsFromPage(dynamic channelId,
[VideoSorting videoSorting = VideoSorting.newest]) async {
channelId = ChannelId.fromString(channelId);
ChannelUploadPage? page = await ChannelUploadPage.get(
final page = await ChannelUploadPage.get(
_httpClient, (channelId as 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);
}
final channel = await get(channelId);
return ChannelUploadsList(
page.initialData.uploads
.map((e) => Video(
e.videoId,
e.videoTitle,
channel.title,
channelId,
e.videoUploadDate.toDateTime(),
null,
'',
e.videoDuration,
ThumbnailSet(e.videoId.value),
null,
Engagement(e.videoViews, null, null),
false))
.toList(),
channel.title,
channelId,
page,
_httpClient);
}
}

View File

@ -0,0 +1,52 @@
import 'dart:async';
import 'package:collection/collection.dart';
import 'package:youtube_explode_dart/src/reverse_engineering/responses/channel_upload_page.dart';
import '../../youtube_explode_dart.dart';
import '../extensions/helpers_extension.dart';
/// This list contains a channel uploads.
/// This behaves like a [List] but has the [SearchList.nextPage] to get the next batch of videos.
class ChannelUploadsList extends DelegatingList<Video> {
final ChannelUploadPage _page;
final YoutubeHttpClient _httpClient;
final String author;
final ChannelId channel;
/// Construct an instance of [SearchList]
/// See [SearchList]
ChannelUploadsList(
List<Video> base, this.author, this.channel, this._page, this._httpClient)
: super(base);
/// Fetches the next batch of videos or returns null if there are no more
/// results.
Future<ChannelUploadsList?> nextPage() async {
final page = await _page.nextPage(_httpClient);
if (page == null) {
return null;
}
return ChannelUploadsList(
page.initialData.uploads
.map((e) => Video(
e.videoId,
e.videoTitle,
author,
channel,
e.videoUploadDate.toDateTime(),
null,
'',
e.videoDuration,
ThumbnailSet(e.videoId.value),
null,
Engagement(e.videoViews, null, null),
false))
.toList(),
author,
channel,
page,
_httpClient);
}
}

View File

@ -1,4 +1,5 @@
import 'package:equatable/equatable.dart';
import '../videos/video_id.dart';
/// Metadata related to a search query result (playlist)
@ -15,8 +16,16 @@ class ChannelVideo with EquatableMixin {
/// Video thumbnail
final String videoThumbnail;
/// Video upload date.
/// Formatted like 10 hours ago
final String videoUploadDate;
/// Video view count.
final int videoViews;
/// Initialize an instance of [ChannelVideo]
ChannelVideo(this.videoId, this.videoTitle, this.videoDuration, this.videoThumbnail);
ChannelVideo(this.videoId, this.videoTitle, this.videoDuration,
this.videoThumbnail, this.videoUploadDate, this.videoViews);
@override
String toString() => '[ChannelVideo] $videoTitle ($videoId)';

View File

@ -163,24 +163,23 @@ class _InitialData {
var video = content.get('gridVideoRenderer')!;
return ChannelVideo(
VideoId(video.getT<String>('videoId')!),
video.get('title')?.getT<String>('simpleText') ??
video.get('title')?.getList('runs')?.map((e) => e['text']).join() ??
'',
video
.getList('thumbnailOverlays')
?.firstOrNull
?.get('thumbnailOverlayTimeStatusRenderer')
?.get('text')
?.getT<String>('simpleText')
?.toDuration() ??
Duration.zero,
video
.get('thumbnail')
?.getList('thumbnails')
?.last
.getT<String>('url') ??
'');
VideoId(video.getT<String>('videoId')!),
video.get('title')?.getT<String>('simpleText') ??
video.get('title')?.getList('runs')?.map((e) => e['text']).join() ??
'',
video
.getList('thumbnailOverlays')
?.firstOrNull
?.get('thumbnailOverlayTimeStatusRenderer')
?.get('text')
?.getT<String>('simpleText')
?.toDuration() ??
Duration.zero,
video.get('thumbnail')?.getList('thumbnails')?.last.getT<String>('url') ??
'',
video.get('publishedTimeText')?.getT<String>('simpleText') ?? '',
video.get('viewCountText')?.getT<String>('simpleText')?.parseInt() ?? 0,
);
}
}

View File

@ -7,14 +7,17 @@ import '../../youtube_explode_dart.dart';
import '../extensions/helpers_extension.dart';
/// This list contains search videos.
/// /// This behaves like a [List] but has the [SearchList.nextPage] to get the next batch of videos.
class SearchList extends DelegatingList<Video> {
final SearchPage _page;
final YoutubeHttpClient _httpClient;
///
/// Construct an instance of [SearchList]
/// See [SearchList]
SearchList(List<Video> base, this._page, this._httpClient) : super(base);
///
/// Fetches the next batch of videos or returns null if there are no more
/// results.
Future<SearchList?> nextPage() async {
final page = await _page.nextPage(_httpClient);
if (page == null) {

View File

@ -52,6 +52,7 @@ class Video with EquatableMixin {
/// Used internally.
/// Shouldn't be used in the code.
/// TODO: Deprecate this method
final WatchPage? watchPage;
/// Returns true if the watch page is available for this video.

View File

@ -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.9.2+2
version: 1.9.3
homepage: https://github.com/Hexer10/youtube_explode_dart

View File

@ -65,12 +65,9 @@ void main() {
}
});
test('Get videos of a youtube channel from the uploads page', () async {
var videos = await yt!.channels
.getUploadsFromPage('UCEnBXANsKmyj2r9xVyKoDiQ')
.take(30)
.toList();
var videos =
await yt!.channels.getUploadsFromPage('UCEnBXANsKmyj2r9xVyKoDiQ');
expect(videos, hasLength(30));
});
@ -79,7 +76,10 @@ void main() {
var aboutPage = await yt!.channels.getAboutPageByUsername(
'PewDiePie'); // or yt.channels.getAboutPage(channelId)
expect(aboutPage.title, 'PewDiePie');
expect(aboutPage.viewCount, greaterThanOrEqualTo(20000000000)); //Seems youtube likes to change and lower this number
expect(
aboutPage.viewCount,
greaterThanOrEqualTo(
20000000000)); //Seems youtube likes to change and lower this number
expect(aboutPage.description, isNotEmpty);
expect(aboutPage.thumbnails, isNotEmpty); // Avatar list
expect(aboutPage.channelLinks, isNotEmpty);