Implement v5 - 1

This commit is contained in:
Hexah 2020-04-18 23:22:13 +02:00
parent d36aa68486
commit 447f7f27d7
12 changed files with 191 additions and 6 deletions

View File

@ -15,5 +15,5 @@ linter:
- prefer_contains
analyzer:
# exclude:
# - path/to/excluded/files/**
exclude:
- example\**

View File

@ -0,0 +1,3 @@
class ChannelClient {
ChannelClient._();
}

View File

@ -0,0 +1,26 @@
import 'dart:io';
import 'package:http/http.dart';
import 'youtube_explode_exception.dart';
/// Exception thrown when a fatal failure occurs.
class FatalFailureException implements YoutubeExplodeException {
final String message;
/// Initializes an instance of [FatalFailureException]
FatalFailureException(this.message);
/// Initializes an instance of [FatalFailureException] with an [HttpRequest]
FatalFailureException.httpRequest(Response response)
: message = '''
Failed to perform an HTTP request to YouTube due to a fatal failure.
In most cases, this error indicates that YouTube most likely changed something, which broke the library.
If this issue persists, please report it on the project's GitHub page.
Request: ${response.request}
Response: $response
''';
@override
String toString() => 'FatalFailureException: $message';
}

View File

@ -0,0 +1,25 @@
import 'package:http/http.dart';
import 'youtube_explode_exception.dart';
/// Exception thrown when a fatal failure occurs.
class RequestLimitExceeded implements YoutubeExplodeException {
final String message;
/// Initializes an instance of [FatalFailureException]
RequestLimitExceeded(this.message);
/// Initializes an instance of [FatalFailureException] with an [HttpRequest]
RequestLimitExceeded.httpRequest(Response response)
: message = '''
Failed to perform an HTTP request to YouTube because of rate limiting.
This error indicates that YouTube thinks there were too many requests made from this IP and considers it suspicious.
To resolve this error, please wait some time and try again -or- try injecting an HttpClient that has cookies for an authenticated user.
Unfortunately, there's nothing the library can do to work around this error.
Request: ${response.request}
Response: $response
''';
@override
String toString() => 'FatalFailureException: $message';
}

View File

@ -0,0 +1,5 @@
/// Parent class for domain exceptions thrown by [YoutubeExplode]
abstract class YoutubeExplodeException implements Exception {
final String message;
YoutubeExplodeException(this.message);
}

View File

@ -1,4 +1,4 @@
import '../cipher/cipher_operations.dart';
import '../reverse_engineering/cipher/cipher_operations.dart';
/// Utility for Strings.
extension StringUtility on String {

View File

@ -2,8 +2,8 @@ library youtube_explode.cipher;
import 'package:http/http.dart' as http;
import '../exceptions/exceptions.dart';
import '../extensions/helpers_extension.dart';
import '../../exceptions/exceptions.dart';
import '../../extensions/helpers_extension.dart';
import 'cipher_operations.dart';
final _deciphererFuncNameExp = RegExp(

View File

@ -0,0 +1,54 @@
import 'package:html/dom.dart';
import 'package:html/parser.dart' as parser;
class ChannelPage {
final Document _root;
bool get isOk => _root.querySelector('meta[property="og:url"]') != null;
String get channelUrl => _root
.querySelectorThrow('meta[property="og:url"]')
.getAttributeThrow('content');
String get channelId => channelId.substringAfter('channel/');
String get channelTitle => _root
.querySelectorThrow('meta[property="og:title"]')
.getAttributeThrow('content');
String get channelLogoUrl => _root
.querySelectorThrow('meta[property="og:image"]')
.getAttributeThrow('content');
ChannelPage(this._root);
ChannelPage.parse(String raw) : _root = parser.parse(raw);
static Future<ChannelPage> hello() {}
}
extension on Document {
Element querySelectorThrow(String selectors) {
var element = querySelector(selectors);
if (element == null) {
//TODO: throw
}
return element;
}
}
extension on Element {
String getAttributeThrow(String name) {
var attribute = attributes[name];
if (attribute == null) {
//TODO: throw
}
return attribute;
}
}
extension on String {
String substringAfter(String separator) =>
substring(indexOf(separator) + length);
}

View File

@ -0,0 +1 @@
export 'youtube_http_client.dart';

View File

@ -0,0 +1,69 @@
import 'package:http/http.dart';
class YoutubeHttpClient {
final Client _httpClient = Client();
/// Throws if something is wrong with the response.
void _validateResponse(Request request, int statusCode) {
if (request.url.host.endsWith('.google.com') &&
request.url.path.startsWith('/sorry/')) {
//TODO: throw RequestLimitExceededException.FailedHttpRequest(response);
}
if (statusCode >= 500) {
//TODO: TransientFailureException.FailedHttpRequest(response);
}
if (statusCode == 429) {
//TODO: throw RequestLimitExceededException.FailedHttpRequest(response);
}
if (statusCode >= 400) {
//TODO: throw FatalFailureException.FailedHttpRequest(response);
}
}
Future<Response> get(dynamic url, {Map<String, String> headers}) {
return _httpClient.get(url, headers: headers);
}
Future<Response> head(dynamic url, {Map<String, String> headers}) {
return _httpClient.head(url, headers: headers);
}
Future<String> getString(dynamic url,
{Map<String, String> headers, bool validate = true}) async {
var response = await _httpClient.get(url, headers: headers);
if (validate) {
_validateResponse(response.request, response.statusCode);
}
return response.body;
}
Stream<List<int>> getStream(dynamic url,
{Map<String, String> headers,
int from,
int to,
bool validate = true}) async* {
var request = Request('get', url);
request.headers['range'] = 'bytes=$from-$to';
var response = await request.send();
if (validate) {
_validateResponse(response.request, response.statusCode);
}
yield* response.stream;
}
Future<int> getContentLength(dynamic url,
{Map<String, String> headers, bool validate = true}) async {
var response = await head(url, headers: headers);
if (validate) {
_validateResponse(response.request, response.statusCode);
}
return int.parse(response.headers['content-length']);
}
}

View File

@ -11,6 +11,8 @@ import 'extensions/extensions.dart';
import 'models/models.dart';
import 'parser.dart' as parser;
import 'channel/channel_client.dart';
/// YoutubeExplode entry class.
class YoutubeExplode {
static final _regMatchExp = RegExp(r'youtube\..+?/watch.*?v=(.*?)(?:&|/|$)');
@ -24,7 +26,7 @@ class YoutubeExplode {
/// HTTP Client.
// Visible only for extensions.
http.Client client;
final http.Client client;
/// Initialize [YoutubeExplode] class and http client.
YoutubeExplode() : client = http.Client();