youtube_explode/lib/src/reverse_engineering/responses/playlist_response.dart

118 lines
2.8 KiB
Dart

import 'dart:convert';
import '../../channels/channel_id.dart';
import '../../common/common.dart';
import '../../exceptions/exceptions.dart';
import '../../extensions/helpers_extension.dart';
import '../../retry.dart';
import '../youtube_http_client.dart';
///
class PlaylistResponse {
Iterable<_Video> _videos;
// Json parsed map
final Map<String, dynamic> _root;
///
String get title => _root['title'];
///
String get author => _root['author'];
///
String get description => _root['description'];
///
ThumbnailSet get thumbnails => ThumbnailSet(videos.firstOrNull.id);
///
int get viewCount => _root['views'];
///
int get likeCount => _root['likes'];
///
int get dislikeCount => _root['dislikes'];
///
Iterable<_Video> get videos => _videos ??=
_root['video']?.map((e) => _Video(e))?.cast<_Video>() ?? const <_Video>[];
///
PlaylistResponse(this._root);
///
PlaylistResponse.parse(String raw) : _root = json.tryDecode(raw) {
if (_root == null) {
throw TransientFailureException('Playerlist response is broken.');
}
}
///
static Future<PlaylistResponse> get(YoutubeHttpClient httpClient, String id,
{int index = 0}) {
var url =
'https://youtube.com/list_ajax?style=json&action_get_list=1&list=$id&index=$index&hl=en';
return retry(() async {
var raw = await httpClient.getString(url);
return PlaylistResponse.parse(raw);
});
}
///
static Future<PlaylistResponse> searchResults(
YoutubeHttpClient httpClient, String query,
{int page = 0}) {
var url = 'https://youtube.com/search_ajax?style=json&search_query='
'${Uri.encodeQueryComponent(query)}&page=$page&hl=en';
return retry(() async {
var raw = await httpClient.getString(url, validate: false);
return PlaylistResponse.parse(raw);
});
}
}
class _Video {
// Json parsed map
final Map<String, dynamic> _root;
_Video(this._root);
String get id => _root['encrypted_id'];
String get author => _root['author'];
ChannelId get channelId => ChannelId('UC${_root['user_id']}');
DateTime get uploadDate =>
DateTime.fromMillisecondsSinceEpoch(_root['time_created'] * 1000);
String get title => _root['title'];
String get description => _root['description'];
Duration get duration => Duration(seconds: _root['length_seconds']);
int get viewCount => int.parse((_root['views'] as String).stripNonDigits());
int get likes => _root['likes'];
int get dislikes => _root['dislikes'];
Iterable<String> get keywords => RegExp(r'"[^\"]+"|\S+')
.allMatches(_root['keywords'])
.map((e) => e.group(0))
.toList(growable: false);
}
extension on JsonCodec {
dynamic tryDecode(String source) {
try {
return json.decode(source);
} on FormatException {
return null;
}
}
}