parent
b89f786348
commit
5d76402694
|
@ -1,6 +1,9 @@
|
||||||
name: Dart CI
|
name: Dart CI
|
||||||
|
|
||||||
on: [push]
|
on:
|
||||||
|
push:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * * '
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:html/dom.dart';
|
import 'package:html/dom.dart';
|
||||||
import 'package:html/parser.dart' as parser;
|
import 'package:html/parser.dart' as parser;
|
||||||
|
import 'package:youtube_explode_dart/src/reverse_engineering/responses/player_config_base.dart';
|
||||||
|
|
||||||
import '../../extensions/helpers_extension.dart';
|
import '../../extensions/helpers_extension.dart';
|
||||||
import '../../retry.dart';
|
import '../../retry.dart';
|
||||||
|
@ -14,7 +15,7 @@ class EmbedPage {
|
||||||
static final _playerConfigExp2 = RegExp(r'yt.setConfig\((\{.*\})');
|
static final _playerConfigExp2 = RegExp(r'yt.setConfig\((\{.*\})');
|
||||||
|
|
||||||
final Document _root;
|
final Document _root;
|
||||||
_PlayerConfig _playerConfig;
|
EmbedPlayerConfig _playerConfig;
|
||||||
|
|
||||||
///
|
///
|
||||||
String get sourceUrl {
|
String get sourceUrl {
|
||||||
|
@ -32,7 +33,7 @@ class EmbedPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
_PlayerConfig get playerConfig {
|
EmbedPlayerConfig get playerConfig {
|
||||||
if (_playerConfig != null) {
|
if (_playerConfig != null) {
|
||||||
return _playerConfig;
|
return _playerConfig;
|
||||||
}
|
}
|
||||||
|
@ -41,7 +42,7 @@ class EmbedPage {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return _playerConfig =
|
return _playerConfig =
|
||||||
_PlayerConfig(json.decode(playerConfigJson.extractJson()));
|
EmbedPlayerConfig(json.decode(playerConfigJson.extractJson()));
|
||||||
}
|
}
|
||||||
|
|
||||||
String get _playerConfigJson => _root
|
String get _playerConfigJson => _root
|
||||||
|
@ -72,11 +73,14 @@ class EmbedPage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PlayerConfig {
|
/// Used internally
|
||||||
// Json parsed map.
|
class EmbedPlayerConfig implements PlayerConfigBase<Map<String, dynamic>> {
|
||||||
final Map<String, dynamic> _root;
|
@override
|
||||||
|
final Map<String, dynamic> root;
|
||||||
|
|
||||||
_PlayerConfig(this._root);
|
///
|
||||||
|
EmbedPlayerConfig(this.root);
|
||||||
|
|
||||||
String get sourceUrl => 'https://youtube.com${_root['assets']['js']}';
|
@override
|
||||||
|
String get sourceUrl => 'https://youtube.com${root['assets']['js']}';
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
/// Base class for PlayerConfig.
|
||||||
|
abstract class PlayerConfigBase<T> {
|
||||||
|
|
||||||
|
/// Root node.
|
||||||
|
final T root;
|
||||||
|
|
||||||
|
///
|
||||||
|
PlayerConfigBase(this.root);
|
||||||
|
|
||||||
|
/// Player source url.
|
||||||
|
String get sourceUrl;
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:html/dom.dart';
|
import 'package:html/dom.dart';
|
||||||
import 'package:html/parser.dart' as parser;
|
import 'package:html/parser.dart' as parser;
|
||||||
|
import 'package:youtube_explode_dart/src/reverse_engineering/responses/player_config_base.dart';
|
||||||
|
|
||||||
import '../../../youtube_explode_dart.dart';
|
import '../../../youtube_explode_dart.dart';
|
||||||
import '../../extensions/helpers_extension.dart';
|
import '../../extensions/helpers_extension.dart';
|
||||||
|
@ -34,7 +35,7 @@ class WatchPage {
|
||||||
|
|
||||||
_InitialData _initialData;
|
_InitialData _initialData;
|
||||||
String _xsfrToken;
|
String _xsfrToken;
|
||||||
_PlayerConfig _playerConfig;
|
WatchPlayerConfig _playerConfig;
|
||||||
|
|
||||||
///
|
///
|
||||||
String get sourceUrl {
|
String get sourceUrl {
|
||||||
|
@ -125,7 +126,7 @@ class WatchPage {
|
||||||
static final _playerConfigExp = RegExp(r'ytplayer\.config\s*=\s*(\{.*\})');
|
static final _playerConfigExp = RegExp(r'ytplayer\.config\s*=\s*(\{.*\})');
|
||||||
|
|
||||||
///
|
///
|
||||||
_PlayerConfig get playerConfig => _playerConfig ??= _PlayerConfig(
|
WatchPlayerConfig get playerConfig => _playerConfig ??= WatchPlayerConfig(
|
||||||
PlayerConfigJson.fromRawJson(_playerConfigExp
|
PlayerConfigJson.fromRawJson(_playerConfigExp
|
||||||
.firstMatch(_root.getElementsByTagName('html').first.text)
|
.firstMatch(_root.getElementsByTagName('html').first.text)
|
||||||
?.group(1)
|
?.group(1)
|
||||||
|
@ -172,14 +173,18 @@ class WatchPage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PlayerConfig {
|
/// Used internally
|
||||||
// Json parsed map
|
class WatchPlayerConfig implements PlayerConfigBase<PlayerConfigJson> {
|
||||||
|
@override
|
||||||
final PlayerConfigJson root;
|
final PlayerConfigJson root;
|
||||||
|
|
||||||
_PlayerConfig(this.root);
|
///
|
||||||
|
WatchPlayerConfig(this.root);
|
||||||
|
|
||||||
|
@override
|
||||||
String get sourceUrl => 'https://youtube.com${root.assets.js}';
|
String get sourceUrl => 'https://youtube.com${root.assets.js}';
|
||||||
|
|
||||||
|
///
|
||||||
PlayerResponse get playerResponse =>
|
PlayerResponse get playerResponse =>
|
||||||
PlayerResponse.parse(root.args.playerResponse);
|
PlayerResponse.parse(root.args.playerResponse);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ class StreamsClient {
|
||||||
Future<StreamContext> _getStreamContextFromWatchPage(VideoId videoId) async {
|
Future<StreamContext> _getStreamContextFromWatchPage(VideoId videoId) async {
|
||||||
var watchPage = await WatchPage.get(_httpClient, videoId.toString());
|
var watchPage = await WatchPage.get(_httpClient, videoId.toString());
|
||||||
|
|
||||||
dynamic /* _PlayerConfig */ playerConfig;
|
WatchPlayerConfig playerConfig;
|
||||||
try {
|
try {
|
||||||
playerConfig = watchPage.playerConfig;
|
playerConfig = watchPage.playerConfig;
|
||||||
} on FormatException {
|
} on FormatException {
|
||||||
|
@ -92,13 +92,13 @@ class StreamsClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
var previewVideoId = playerResponse.previewVideoId;
|
var previewVideoId = playerResponse.previewVideoId;
|
||||||
if (!((previewVideoId as String)?.isNullOrWhiteSpace ?? true)) {
|
if (!(previewVideoId.isNullOrWhiteSpace ?? true)) {
|
||||||
throw VideoRequiresPurchaseException.preview(
|
throw VideoRequiresPurchaseException.preview(
|
||||||
videoId, VideoId(previewVideoId));
|
videoId, VideoId(previewVideoId));
|
||||||
}
|
}
|
||||||
|
|
||||||
var playerSourceUrl =
|
var playerSourceUrl =
|
||||||
watchPage.sourceUrl ?? playerConfig?.sourceUrl as String;
|
watchPage.sourceUrl ?? playerConfig?.sourceUrl;
|
||||||
var playerSource = !playerSourceUrl.isNullOrWhiteSpace
|
var playerSource = !playerSourceUrl.isNullOrWhiteSpace
|
||||||
? await PlayerSource.get(_httpClient, playerSourceUrl)
|
? await PlayerSource.get(_httpClient, playerSourceUrl)
|
||||||
: null;
|
: null;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: youtube_explode_dart
|
name: youtube_explode_dart
|
||||||
description: A port in dart of the youtube explode library. Supports several API functions without the need of Youtube API Key.
|
description: A port in dart of the youtube explode library. Supports several API functions without the need of Youtube API Key.
|
||||||
version: 1.7.5
|
version: 1.7.6
|
||||||
homepage: https://github.com/Hexer10/youtube_explode_dart
|
homepage: https://github.com/Hexer10/youtube_explode_dart
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
|
|
@ -55,7 +55,7 @@ void main() {
|
||||||
VideoId('5VGm0dczmHc'), // rating not allowed
|
VideoId('5VGm0dczmHc'), // rating not allowed
|
||||||
VideoId('ZGdLIwrGHG8'), // unlisted
|
VideoId('ZGdLIwrGHG8'), // unlisted
|
||||||
VideoId('rsAAeyAr-9Y'), // recording of a live stream
|
VideoId('rsAAeyAr-9Y'), // recording of a live stream
|
||||||
VideoId('AI7ULzgf8RU'), // has DASH manifest
|
VideoId('AI7ULzgf8RU'), // has DASH manifest TODO: Test timesout
|
||||||
VideoId('-xNN-bJQ4vI'), // 360° video
|
VideoId('-xNN-bJQ4vI'), // 360° video
|
||||||
}) {
|
}) {
|
||||||
test('VideoId - ${val.value}', () async {
|
test('VideoId - ${val.value}', () async {
|
||||||
|
|
Loading…
Reference in New Issue