2021-03-11 14:20:10 +01:00
|
|
|
import 'package:collection/collection.dart';
|
2020-05-31 23:36:23 +02:00
|
|
|
import 'package:html/dom.dart';
|
|
|
|
import 'package:html/parser.dart' as parser;
|
2020-06-03 13:18:37 +02:00
|
|
|
|
2020-06-03 23:02:21 +02:00
|
|
|
import '../../extensions/helpers_extension.dart';
|
2020-06-05 16:17:08 +02:00
|
|
|
import '../../retry.dart';
|
2020-06-03 23:02:21 +02:00
|
|
|
import '../youtube_http_client.dart';
|
2021-02-26 16:08:48 +01:00
|
|
|
import 'player_config_base.dart';
|
2020-05-31 23:36:23 +02:00
|
|
|
|
2020-07-16 20:02:54 +02:00
|
|
|
///
|
2020-05-31 23:36:23 +02:00
|
|
|
class EmbedPage {
|
2021-03-18 22:22:55 +01:00
|
|
|
static final _playerConfigExp =
|
|
|
|
RegExp('[\'""]PLAYER_CONFIG[\'""]\\s*:\\s*(\\{.*\\})');
|
2020-12-02 12:05:45 +01:00
|
|
|
static final _playerConfigExp2 = RegExp(r'yt.setConfig\((\{.*\})');
|
2021-04-02 22:56:32 +02:00
|
|
|
static final _playerConfigExp3 = RegExp(r'ytcfg.set\((\{.*\})');
|
2020-10-01 18:04:56 +02:00
|
|
|
|
2021-03-11 14:20:10 +01:00
|
|
|
final Document root;
|
|
|
|
late final EmbedPlayerConfig? playerConfig = getPlayerConfig();
|
2020-05-31 23:36:23 +02:00
|
|
|
|
2020-10-27 14:44:11 +01:00
|
|
|
///
|
2021-03-11 14:20:10 +01:00
|
|
|
String? get sourceUrl {
|
2021-04-02 22:56:32 +02:00
|
|
|
final url = root
|
|
|
|
.querySelectorAll('script')
|
2020-12-02 12:05:45 +01:00
|
|
|
.map((e) => e.attributes['src'])
|
2021-04-02 22:56:32 +02:00
|
|
|
.whereNotNull()
|
|
|
|
.firstWhereOrNull((e) => e.contains('player_ias') && e.endsWith('.js'));
|
|
|
|
|
2020-12-02 12:05:45 +01:00
|
|
|
// _root.querySelector('*[name="player_ias/base"]').attributes['src'];
|
2020-10-27 14:44:11 +01:00
|
|
|
if (url == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return 'https://youtube.com$url';
|
|
|
|
}
|
|
|
|
|
2020-07-16 20:02:54 +02:00
|
|
|
///
|
2021-03-11 14:20:10 +01:00
|
|
|
EmbedPlayerConfig? getPlayerConfig() {
|
2021-03-18 22:22:55 +01:00
|
|
|
var playerConfigJson =
|
2021-04-02 22:56:32 +02:00
|
|
|
(_playerConfigJson3 ?? _playerConfigJson2 ?? _playerConfigJson)
|
|
|
|
?.extractJson();
|
2020-06-03 13:18:37 +02:00
|
|
|
if (playerConfigJson == null) {
|
|
|
|
return null;
|
|
|
|
}
|
2021-03-18 22:22:34 +01:00
|
|
|
return EmbedPlayerConfig(playerConfigJson);
|
2020-06-03 13:18:37 +02:00
|
|
|
}
|
2020-05-31 23:36:23 +02:00
|
|
|
|
2021-03-11 14:20:10 +01:00
|
|
|
String? get _playerConfigJson => root
|
2020-05-31 23:36:23 +02:00
|
|
|
.getElementsByTagName('script')
|
|
|
|
.map((e) => e.text)
|
2020-06-05 16:17:08 +02:00
|
|
|
.map((e) => _playerConfigExp.firstMatch(e)?.group(1))
|
2021-03-11 14:20:10 +01:00
|
|
|
.firstWhereOrNull((e) => !e.isNullOrWhiteSpace);
|
2020-05-31 23:36:23 +02:00
|
|
|
|
2021-03-11 14:20:10 +01:00
|
|
|
String? get _playerConfigJson2 => root
|
2020-12-02 12:05:45 +01:00
|
|
|
.getElementsByTagName('script')
|
|
|
|
.map((e) => e.text)
|
|
|
|
.map((e) => _playerConfigExp2.firstMatch(e)?.group(1))
|
2021-03-11 14:20:10 +01:00
|
|
|
.firstWhereOrNull((e) => !e.isNullOrWhiteSpace);
|
2020-12-02 12:05:45 +01:00
|
|
|
|
2021-04-02 22:56:32 +02:00
|
|
|
String? get _playerConfigJson3 => root
|
|
|
|
.getElementsByTagName('script')
|
|
|
|
.map((e) => e.text)
|
|
|
|
.map((e) => _playerConfigExp3.firstMatch(e)?.group(1))
|
|
|
|
.firstWhereOrNull((e) => !e.isNullOrWhiteSpace);
|
|
|
|
|
2020-07-16 20:02:54 +02:00
|
|
|
///
|
2021-03-11 14:20:10 +01:00
|
|
|
EmbedPage(this.root);
|
2020-06-22 17:40:57 +02:00
|
|
|
|
2020-07-16 20:02:54 +02:00
|
|
|
///
|
2021-03-11 14:20:10 +01:00
|
|
|
EmbedPage.parse(String raw) : root = parser.parse(raw);
|
2020-05-31 23:36:23 +02:00
|
|
|
|
2020-07-16 20:02:54 +02:00
|
|
|
///
|
2020-06-03 13:18:37 +02:00
|
|
|
static Future<EmbedPage> get(YoutubeHttpClient httpClient, String videoId) {
|
2020-05-31 23:36:23 +02:00
|
|
|
var url = 'https://youtube.com/embed/$videoId?hl=en';
|
2021-04-02 22:56:32 +02:00
|
|
|
// final url = 'http://localhost:8080/embed/$videoId?hl=en';
|
2020-05-31 23:36:23 +02:00
|
|
|
return retry(() async {
|
|
|
|
var raw = await httpClient.getString(url);
|
|
|
|
return EmbedPage.parse(raw);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-28 10:32:09 +01:00
|
|
|
/// Used internally
|
2021-07-21 02:06:02 +02:00
|
|
|
class EmbedPlayerConfig implements PlayerConfigBase {
|
2021-01-28 10:32:09 +01:00
|
|
|
@override
|
2021-07-21 02:06:02 +02:00
|
|
|
final JsonMap root;
|
2020-05-31 23:36:23 +02:00
|
|
|
|
2021-01-28 10:32:09 +01:00
|
|
|
///
|
|
|
|
EmbedPlayerConfig(this.root);
|
2020-05-31 23:36:23 +02:00
|
|
|
|
2021-01-28 10:32:09 +01:00
|
|
|
@override
|
|
|
|
String get sourceUrl => 'https://youtube.com${root['assets']['js']}';
|
2020-05-31 23:36:23 +02:00
|
|
|
}
|