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

111 lines
2.9 KiB
Dart
Raw Normal View History

2020-05-31 23:36:23 +02:00
import 'package:http_parser/http_parser.dart';
2020-06-03 23:02:21 +02:00
import '../../exceptions/exceptions.dart';
import '../../retry.dart';
import '../youtube_http_client.dart';
import 'player_response.dart';
import 'stream_info_provider.dart';
2020-05-31 23:36:23 +02:00
class VideoInfoResponse {
final Map<String, String> _root;
VideoInfoResponse(this._root);
String get status => _root['status'];
2020-06-03 23:02:21 +02:00
bool get isVideoAvailable => status.toLowerCase() != 'fail';
2020-05-31 23:36:23 +02:00
PlayerResponse get playerResponse =>
PlayerResponse.parse(_root['player_response']);
Iterable<_StreamInfo> get muxedStreams =>
_root['url_encoded_fmt_stream_map']
?.split(',')
?.map(Uri.splitQueryString)
?.map((e) => _StreamInfo(e)) ??
const [];
Iterable<_StreamInfo> get adaptiveStreams =>
_root['adaptive_fmts']
?.split(',')
?.map(Uri.splitQueryString)
?.map((e) => _StreamInfo(e)) ??
const [];
Iterable<_StreamInfo> get streams => [...muxedStreams, ...adaptiveStreams];
2020-06-03 13:18:37 +02:00
VideoInfoResponse.parse(String raw) : _root = Uri.splitQueryString(raw);
static Future<VideoInfoResponse> get(
YoutubeHttpClient httpClient, String videoId,
[String sts]) {
var eurl = Uri.encodeFull('https://youtube.googleapis.com/v/$videoId');
var url =
2020-06-03 23:02:21 +02:00
'https://youtube.com/get_video_info?video_id=$videoId&el=embedded&eurl=$eurl&hl=en${sts != null ? '&sts=$sts' : ''}';
2020-06-03 13:18:37 +02:00
return retry(() async {
var raw = await httpClient.getString(url);
var result = VideoInfoResponse.parse(raw);
if (!result.isVideoAvailable || !result.playerResponse.isVideoAvailable) {
throw VideoUnplayableException(videoId);
}
return result;
});
}
2020-05-31 23:36:23 +02:00
}
class _StreamInfo extends StreamInfoProvider {
final Map<String, String> _root;
_StreamInfo(this._root);
@override
int get tag => int.parse(_root['itag']);
@override
String get url => _root['url'];
@override
String get signature => _root['s'];
@override
String get signatureParameter => _root['sp'];
@override
int get contentLength => int.tryParse(_root['clen'] ??
StreamInfoProvider.contentLenExp.firstMatch(url).group(1));
@override
int get bitrate => int.parse(_root['bitrate']);
MediaType get mimeType => MediaType.parse(_root["type"]);
@override
String get container => mimeType.subtype;
List<String> get codecs =>
mimeType.parameters['codecs'].split(',').map((e) => e.trim());
@override
String get audioCodec => codecs.last;
@override
String get videoCodec => isAudioOnly ? null : codecs.first;
bool get isAudioOnly => mimeType.type == 'audio';
@override
String get videoQualityLabel => _root['quality_label'];
List<int> get _size =>
_root['size'].split(',').map((e) => int.tryParse(e ?? ''));
@override
int get videoWidth => _size.first;
@override
int get videoHeight => _size.last;
@override
int get framerate => int.tryParse(_root['fps'] ?? '');
2020-06-10 00:08:16 +02:00
}