Version 1.9.3
This commit is contained in:
parent
0f3d5e7a16
commit
d405feff2f
|
@ -1,3 +1,6 @@
|
|||
## 1.9.3
|
||||
- `getUploadsFromPage` now returns an instance of `ChannelUploadsList`.
|
||||
|
||||
## 1.9.2+2
|
||||
- Fix `videoThumbnail` in `ChannelVideo`.
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)';
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue