youtube_explode/lib/src/reverse_engineering/dash_manifest.dart

97 lines
2.3 KiB
Dart

import 'package:xml/xml.dart' as xml;
import '../retry.dart';
import 'models/stream_info_provider.dart';
import 'youtube_http_client.dart';
///
class DashManifest {
static final _urlSignatureExp = RegExp(r'/s/(.*?)(?:/|$)');
final xml.XmlDocument _root;
///
late final Iterable<_StreamInfo> 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(httpClient, () 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+)');
final xml.XmlElement root;
_StreamInfo(this.root);
@override
StreamSource get source => StreamSource.dash;
@override
late final int tag = int.parse(root.getAttribute('id')!);
@override
late final String url = root.getAttribute('BaseURL')!;
@override
late final int contentLength = int.parse(
(root.getAttribute('contentLength') ??
_contentLenExp.firstMatch(url)?.group(1))!);
@override
late final int bitrate = int.parse(root.getAttribute('bandwidth')!);
@override
late final String? container = '';
/*
Uri.decodeFull((_containerExp.firstMatch(url)?.group(1))!);*/
late final bool isAudioOnly =
root.findElements('AudioChannelConfiguration').isNotEmpty;
@override
late final String? audioCodec =
isAudioOnly ? null : root.getAttribute('codecs');
@override
late final String? videoCodec =
isAudioOnly ? root.getAttribute('codecs') : null;
@override
late final int videoWidth = int.parse(root.getAttribute('width')!);
@override
late final int videoHeight = int.parse(root.getAttribute('height')!);
@override
late final int framerate = int.parse(root.getAttribute('framerate')!);
// TODO: Implement this
@override
late final String? videoQualityLabel = null;
}