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

88 lines
2.2 KiB
Dart

import 'package:xml/xml.dart' as xml;
import '../../retry.dart';
import '../youtube_http_client.dart';
import 'stream_info_provider.dart';
///
class DashManifest {
static final _urlSignatureExp = RegExp(r'/s/(.*?)(?:/|$)');
final xml.XmlDocument _root;
Iterable<_StreamInfo> _streams;
///
Iterable<_StreamInfo> get streams => _streams ??= _root
.findElements('Representation')
.where((e) => e
.findElements('Initialization')
.first
.getAttribute('sourceURL')
.contains('sq/'))
.map((e) => _StreamInfo(e));
///
DashManifest(this._root);
///
// ignore: deprecated_member_use
DashManifest.parse(String raw) : _root = xml.parse(raw);
///
static Future<DashManifest> get(YoutubeHttpClient httpClient, dynamic url) {
return retry(() async {
var raw = await httpClient.getString(url);
return DashManifest.parse(raw);
});
}
///
static String getSignatureFromUrl(String url) =>
_urlSignatureExp.firstMatch(url)?.group(1);
}
class _StreamInfo extends StreamInfoProvider {
static final _contentLenExp = RegExp(r'[/\?]clen[/=](\d+)');
static final _containerExp = RegExp(r'mime[/=]\w*%2F([\w\d]*)');
final xml.XmlElement _root;
_StreamInfo(this._root);
@override
int get tag => int.parse(_root.getAttribute('id'));
@override
String get url => _root.getAttribute('BaseURL');
@override
int get contentLength => int.parse(_root.getAttribute('contentLength') ??
_contentLenExp.firstMatch(url).group(1));
@override
int get bitrate => int.parse(_root.getAttribute('bandwidth'));
@override
String get container =>
Uri.decodeFull(_containerExp.firstMatch(url).group(1));
bool get isAudioOnly =>
_root.findElements('AudioChannelConfiguration').isNotEmpty;
@override
String get audioCodec => isAudioOnly ? null : _root.getAttribute('codecs');
@override
String get videoCodec => isAudioOnly ? _root.getAttribute('codecs') : null;
@override
int get videoWidth => int.parse(_root.getAttribute('width'));
@override
int get videoHeight => int.parse(_root.getAttribute('height'));
@override
int get framerate => int.parse(_root.getAttribute('framerate'));
}