Version 1.6.2
This commit is contained in:
Mattia 2020-10-27 14:44:11 +01:00
parent 51e40f27cc
commit 9c8e9630ab
15 changed files with 82 additions and 32 deletions

View File

@ -3,6 +3,9 @@
- Only throw custom exceptions from the library.
- `getUploadsFromPage` no longer throws.
## 1.6.2
- Bug fixes: #80
## 1.6.1
- Add thumbnail to `SearchVideo` thanks to @shinyford !

View File

@ -29,6 +29,32 @@ extension StringUtility on String {
/// Strips out all non digit characters.
String stripNonDigits() => replaceAll(_exp, '');
///
String extractJson() {
var buffer = StringBuffer();
var depth = 0;
for (var i = 0; i < length; i++) {
var ch = this[i];
var chPrv = i > 0 ? this[i - 1] : '';
buffer.write(ch);
if (ch == '{' && chPrv != '\\') {
depth++;
} else if (ch == '}' && chPrv != '\\') {
depth--;
}
if (depth == 0) {
break;
}
}
return buffer.toString();
}
}
/// List decipher utility.

View File

@ -7,14 +7,25 @@ import '../../extensions/helpers_extension.dart';
import '../../retry.dart';
import '../youtube_http_client.dart';
///
class EmbedPage {
static final _playerConfigExp = RegExp(r"'PLAYER_CONFIG':\s*(\{.*\})\}");
static final _playerConfigExp =
RegExp('[\'"]PLAYER_CONFIG[\'"]\\s*:\\s*(\\{.*\\})');
final Document _root;
_PlayerConfig _playerConfig;
String __playerConfigJson;
///
String get sourceUrl {
var url = _root.querySelector('*[name="player_ias/base"]').attributes['src'];
if (url == null) {
return null;
}
return 'https://youtube.com$url';
}
///
_PlayerConfig get playerconfig {
if (_playerConfig != null) {
@ -24,7 +35,8 @@ class EmbedPage {
if (playerConfigJson == null) {
return null;
}
return _playerConfig = _PlayerConfig(json.decode(playerConfigJson));
return _playerConfig =
_PlayerConfig(json.decode(playerConfigJson.extractJson()));
}
String get _playerConfigJson => __playerConfigJson ??= _root

View File

@ -30,7 +30,7 @@ class PlayerSource {
var val = RegExp(r'(?<=invalid namespace.*?;[\w\s]+=)\d+')
.stringMatch(_root)
?.nullIfWhitespace ??
RegExp(r'(?<=this\.signatureTimestamp=)\d+')
RegExp(r'(?<=signatureTimestamp[=\:])\d+')
.stringMatch(_root)
?.nullIfWhitespace;
if (val == null) {

View File

@ -1,5 +1,3 @@
import 'dart:convert';
import 'package:html/dom.dart';
import 'package:html/parser.dart' as parser;
@ -35,6 +33,16 @@ class WatchPage {
String _xsfrToken;
_PlayerConfig _playerConfig;
///
String get sourceUrl {
var url =
_root.querySelector('*[name="player_ias/base"]').attributes['src'];
if (url == null) {
return null;
}
return 'https://youtube.com$url';
}
///
_InitialData get initialData =>
_initialData ??= _InitialData(WatchPageId.fromRawJson(_extractJson(
@ -86,13 +94,14 @@ class WatchPage {
?.nullIfWhitespace ??
'0');
static final _playerConfigExp = RegExp(r'ytplayer\.config\s*=\s*(\{.*\}\});');
static final _playerConfigExp = RegExp(r'ytplayer\.config\s*=\s*(\{.*\})');
///
_PlayerConfig get playerConfig => _playerConfig ??= _PlayerConfig(
PlayerConfigJson.fromRawJson(_playerConfigExp
.firstMatch(_root.getElementsByTagName('html').first.text)
?.group(1)));
?.group(1)
?.extractJson()));
String _extractJson(String html, String separator) {
return _matchJson(

View File

@ -11,7 +11,7 @@ class YoutubeHttpClient extends http.BaseClient {
final Map<String, String> _defaultHeaders = const {
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
'accept-language': 'en-US,en;q=1.0',
'x-youtube-client-name': '1',
'x-youtube-client-version': '2.20200609.04.02',

View File

@ -39,8 +39,8 @@ class StreamsClient {
throw VideoUnplayableException.unplayable(videoId);
}
var playerSource =
await PlayerSource.get(_httpClient, playerConfig.sourceUrl);
var playerSource = await PlayerSource.get(
_httpClient, embedPage.sourceUrl ?? playerConfig.sourceUrl);
var cipherOperations = playerSource.getCiperOperations();
var videoInfoResponse = await VideoInfoResponse.get(
@ -91,8 +91,8 @@ class StreamsClient {
videoId, VideoId(previewVideoId));
}
var playerSource =
await PlayerSource.get(_httpClient, playerConfig.sourceUrl);
var playerSource = await PlayerSource.get(
_httpClient, watchPage.sourceUrl ?? playerConfig.sourceUrl);
var cipherOperations = playerSource.getCiperOperations();
if (!playerResponse.isVideoPlayable) {

View File

@ -3,11 +3,11 @@ import 'package:youtube_explode_dart/youtube_explode_dart.dart';
void main() {
YoutubeExplode yt;
setUp(() {
setUpAll(() {
yt = YoutubeExplode();
});
tearDown(() {
tearDownAll(() {
yt.close();
});

View File

@ -3,11 +3,11 @@ import 'package:youtube_explode_dart/youtube_explode_dart.dart';
void main() {
YoutubeExplode yt;
setUp(() {
setUpAll(() {
yt = YoutubeExplode();
});
tearDown(() {
tearDownAll(() {
yt.close();
});

View File

@ -3,11 +3,11 @@ import 'package:youtube_explode_dart/youtube_explode_dart.dart';
void main() {
YoutubeExplode yt;
setUp(() {
setUpAll(() {
yt = YoutubeExplode();
});
tearDown(() {
tearDownAll(() {
yt.close();
});

View File

@ -3,11 +3,11 @@ import 'package:youtube_explode_dart/youtube_explode_dart.dart';
void main() {
YoutubeExplode yt;
setUp(() {
setUpAll(() {
yt = YoutubeExplode();
});
tearDown(() {
tearDownAll(() {
yt.close();
});

View File

@ -3,11 +3,11 @@ import 'package:youtube_explode_dart/youtube_explode_dart.dart';
void main() {
YoutubeExplode yt;
setUp(() {
setUpAll(() {
yt = YoutubeExplode();
});
tearDown(() {
tearDownAll(() {
yt.close();
});

View File

@ -35,12 +35,12 @@ void main() {
});
test('Search youtube videos have thumbnails', () async {
var searchQuery = await yt.search.queryFromPage('hello');
expect(searchQuery.content.first, isA<SearchVideo>());
var searchQuery = await yt.search.queryFromPage('hello');
expect(searchQuery.content.first, isA<SearchVideo>());
var video = searchQuery.content.first as SearchVideo;
expect(video.videoThumbnails, isNotEmpty);
});
var video = searchQuery.content.first as SearchVideo;
expect(video.videoThumbnails, isNotEmpty);
});
test('Search youtube videos from search page (stream)', () async {
var query = await yt.search.getVideosFromPage('hello').take(30).toList();

View File

@ -3,11 +3,11 @@ import 'package:youtube_explode_dart/youtube_explode_dart.dart';
void main() {
YoutubeExplode yt;
setUp(() {
setUpAll(() {
yt = YoutubeExplode();
});
tearDown(() {
tearDownAll(() {
yt.close();
});
@ -53,5 +53,5 @@ void main() {
}
});
}
}, skip: 'Occasionally may fail with certain videos');
});
}

View File

@ -3,11 +3,11 @@ import 'package:youtube_explode_dart/youtube_explode_dart.dart';
void main() {
YoutubeExplode yt;
setUp(() {
setUpAll(() {
yt = YoutubeExplode();
});
tearDown(() {
tearDownAll(() {
yt.close();
});