parent
f15a8b3c23
commit
7e01cfbb4c
|
@ -18,3 +18,8 @@
|
||||||
## 0.0.5
|
## 0.0.5
|
||||||
|
|
||||||
- Implement Search Api (`SearchExtension`)
|
- Implement Search Api (`SearchExtension`)
|
||||||
|
|
||||||
|
## 0.0.6
|
||||||
|
|
||||||
|
- Implement Caption Api ('CaptionExtension`)
|
||||||
|
- Add Custom Exceptions
|
|
@ -1,6 +1,8 @@
|
||||||
library youtube_explode.cipher;
|
library youtube_explode.cipher;
|
||||||
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
import '../exceptions/exceptions.dart';
|
||||||
import '../extensions/helpers_extension.dart';
|
import '../extensions/helpers_extension.dart';
|
||||||
import 'cipher_operations.dart';
|
import 'cipher_operations.dart';
|
||||||
|
|
||||||
|
@ -27,7 +29,9 @@ Future<List<CipherOperation>> getCipherOperations(
|
||||||
var deciphererFuncName = _deciphererFuncNameExp.firstMatch(raw)?.group(1);
|
var deciphererFuncName = _deciphererFuncNameExp.firstMatch(raw)?.group(1);
|
||||||
|
|
||||||
if (deciphererFuncName.isNullOrWhiteSpace) {
|
if (deciphererFuncName.isNullOrWhiteSpace) {
|
||||||
throw Exception('Could not find decipherer name.');
|
throw UnrecognizedStructureException(
|
||||||
|
'Could not find decipherer name. Please report this issue on GitHub.',
|
||||||
|
raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
var exp = RegExp(r'(?!h\.)'
|
var exp = RegExp(r'(?!h\.)'
|
||||||
|
@ -35,7 +39,9 @@ Future<List<CipherOperation>> getCipherOperations(
|
||||||
r'=function\(\w+\)\{(.*?)\}');
|
r'=function\(\w+\)\{(.*?)\}');
|
||||||
var decipherFuncBody = exp.firstMatch(raw)?.group(1);
|
var decipherFuncBody = exp.firstMatch(raw)?.group(1);
|
||||||
if (decipherFuncBody.isNullOrWhiteSpace) {
|
if (decipherFuncBody.isNullOrWhiteSpace) {
|
||||||
throw Exception('Could not find decipherer body.');
|
throw UnrecognizedStructureException(
|
||||||
|
'Could not find decipherer body. Please report this issue on GitHub.',
|
||||||
|
raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
var deciphererFuncBodyStatements = decipherFuncBody.split(';');
|
var deciphererFuncBodyStatements = decipherFuncBody.split(';');
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
export 'unrecognized_structure_exception.dart';
|
||||||
|
export 'video_requires_purchase_exception.dart';
|
||||||
|
export 'video_unavailable_exception.dart';
|
||||||
|
export 'video_unplayable_exception.dart';
|
|
@ -0,0 +1,18 @@
|
||||||
|
/// Thrown when YoutubeExplode fails to extract required information.
|
||||||
|
/// This usually happens when YouTube makes changes that break YoutubeExplode.
|
||||||
|
class UnrecognizedStructureException implements FormatException {
|
||||||
|
///A message describing the format error.
|
||||||
|
@override
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
/// The actual source input which caused the error.
|
||||||
|
@override
|
||||||
|
final String source;
|
||||||
|
|
||||||
|
/// Initializes an instance of [UnrecognizedStructureException]
|
||||||
|
const UnrecognizedStructureException([this.message, this.source]);
|
||||||
|
|
||||||
|
/// Unimplemented
|
||||||
|
@override
|
||||||
|
int get offset => throw UnsupportedError('Offset not supported');
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
/// Thrown when a video is not playable because it requires purchase.
|
||||||
|
class VideoRequiresPurchaseException implements Exception {
|
||||||
|
/// ID of the preview video.
|
||||||
|
final String previewVideoId;
|
||||||
|
|
||||||
|
/// Initializes an instance of [VideoRequiresPurchaseException]
|
||||||
|
const VideoRequiresPurchaseException(this.previewVideoId);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => 'VideoRequiresPurchaseException: The video '
|
||||||
|
'$previewVideoId requires a purchase';
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
/// Thrown when a video is not available and cannot be processed.
|
||||||
|
/// This can happen because the video does not exist, is deleted,
|
||||||
|
/// is private, or due to other reasons.
|
||||||
|
class VideoUnavailableException implements Exception {
|
||||||
|
/// ID of the video.
|
||||||
|
final String videoId;
|
||||||
|
|
||||||
|
/// Initializes an instance of [VideoUnavailableException]
|
||||||
|
const VideoUnavailableException(this.videoId);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() =>
|
||||||
|
'VideoUnavailableException: Video $videoId is unavailable.';
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
/// Thrown when a video is not playable and its streams cannot be resolved.
|
||||||
|
/// This can happen because the video requires purchase,
|
||||||
|
/// is blocked in your country, is controversial, or due to other reasons.
|
||||||
|
class VideoUnplayableException {
|
||||||
|
/// ID of the video.
|
||||||
|
final String videoId;
|
||||||
|
|
||||||
|
/// Initializes an instance of [VideoUnplayableException]
|
||||||
|
const VideoUnplayableException(this.videoId);
|
||||||
|
|
||||||
|
String toString() =>
|
||||||
|
'VideoUnplayableException: Video $videoId couldn\'t be played';
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:xml/xml.dart' as xml;
|
import 'package:xml/xml.dart' as xml;
|
||||||
|
|
||||||
|
import '../exceptions/exceptions.dart';
|
||||||
import '../models/models.dart';
|
import '../models/models.dart';
|
||||||
import '../youtube_explode_base.dart';
|
import '../youtube_explode_base.dart';
|
||||||
import 'helpers_extension.dart';
|
import 'helpers_extension.dart';
|
||||||
|
@ -22,7 +23,7 @@ extension CaptionExtension on YoutubeExplode {
|
||||||
var playAbility = playerResponseJson['playabilityStatus'];
|
var playAbility = playerResponseJson['playabilityStatus'];
|
||||||
|
|
||||||
if (playAbility['status'].toLowerCase() == 'error') {
|
if (playAbility['status'].toLowerCase() == 'error') {
|
||||||
throw Exception('Video [$videoId] is unavailable');
|
throw VideoUnavailableException(videoId);
|
||||||
}
|
}
|
||||||
|
|
||||||
var trackInfos = <ClosedCaptionTrackInfo>[];
|
var trackInfos = <ClosedCaptionTrackInfo>[];
|
||||||
|
@ -41,7 +42,8 @@ extension CaptionExtension on YoutubeExplode {
|
||||||
|
|
||||||
var isAutoGenerated = trackJson['vssId'].toLowerCase().startsWith('a.');
|
var isAutoGenerated = trackJson['vssId'].toLowerCase().startsWith('a.');
|
||||||
|
|
||||||
trackInfos.add(ClosedCaptionTrackInfo(url, language, isAutoGenerated));
|
trackInfos.add(ClosedCaptionTrackInfo(url, language,
|
||||||
|
isAutoGenerated: isAutoGenerated));
|
||||||
}
|
}
|
||||||
return trackInfos;
|
return trackInfos;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'models.dart';
|
||||||
|
|
||||||
/// Metadata associated with a certain [ClosedCaptionTrack]
|
/// Metadata associated with a certain [ClosedCaptionTrack]
|
||||||
class ClosedCaptionTrackInfo {
|
class ClosedCaptionTrackInfo {
|
||||||
|
|
||||||
/// Manifest URL of the associated track.
|
/// Manifest URL of the associated track.
|
||||||
final Uri url;
|
final Uri url;
|
||||||
|
|
||||||
|
@ -13,5 +12,5 @@ class ClosedCaptionTrackInfo {
|
||||||
final bool isAutoGenerated;
|
final bool isAutoGenerated;
|
||||||
|
|
||||||
/// Initializes an instance of [ClosedCaptionTrackInfo]
|
/// Initializes an instance of [ClosedCaptionTrackInfo]
|
||||||
const ClosedCaptionTrackInfo(this.url, this.language, this.isAutoGenerated);
|
const ClosedCaptionTrackInfo(this.url, this.language, {this.isAutoGenerated});
|
||||||
}
|
}
|
|
@ -6,6 +6,7 @@ import 'package:http/http.dart' as http;
|
||||||
import 'package:http_parser/http_parser.dart' show MediaType;
|
import 'package:http_parser/http_parser.dart' show MediaType;
|
||||||
|
|
||||||
import 'cipher/cipher.dart';
|
import 'cipher/cipher.dart';
|
||||||
|
import 'exceptions/exceptions.dart';
|
||||||
import 'extensions/extensions.dart';
|
import 'extensions/extensions.dart';
|
||||||
import 'models/models.dart';
|
import 'models/models.dart';
|
||||||
import 'parser.dart' as parser;
|
import 'parser.dart' as parser;
|
||||||
|
@ -212,7 +213,7 @@ class YoutubeExplode {
|
||||||
var playAbility = playerResponseJson['playabilityStatus'];
|
var playAbility = playerResponseJson['playabilityStatus'];
|
||||||
|
|
||||||
if (playAbility['status'].toString().toLowerCase() == 'error') {
|
if (playAbility['status'].toString().toLowerCase() == 'error') {
|
||||||
throw Exception('Video [$videoId] is unavailable');
|
throw VideoUnavailableException(videoId);
|
||||||
}
|
}
|
||||||
|
|
||||||
var errorReason = playAbility['reason'] as String;
|
var errorReason = playAbility['reason'] as String;
|
||||||
|
@ -288,7 +289,7 @@ class YoutubeExplode {
|
||||||
?.toLowerCase() as String;
|
?.toLowerCase() as String;
|
||||||
|
|
||||||
if (status.isNullOrWhiteSpace || status == 'error') {
|
if (status.isNullOrWhiteSpace || status == 'error') {
|
||||||
throw Exception('Video [$videoId] is unavailable');
|
throw VideoUnavailableException(videoId);
|
||||||
}
|
}
|
||||||
|
|
||||||
var details = playerResponseJson['videoDetails'];
|
var details = playerResponseJson['videoDetails'];
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
library youtube_explode;
|
library youtube_explode;
|
||||||
|
|
||||||
|
export 'src/exceptions/exceptions.dart';
|
||||||
export 'src/extensions/extensions.dart'
|
export 'src/extensions/extensions.dart'
|
||||||
hide StringUtility, ListDecipher, ListFirst; // Hide helper extensions.
|
hide StringUtility, ListDecipher, ListFirst; // Hide helper extensions.
|
||||||
export 'src/models/models.dart';
|
export 'src/models/models.dart';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: youtube_explode_dart
|
name: youtube_explode_dart
|
||||||
description: A port in dart of the youtube explode library. Support serveral API functions.
|
description: A port in dart of the youtube explode library. Support serveral API functions.
|
||||||
version: 0.0.5
|
version: 0.0.6
|
||||||
homepage: https://github.com/Hexer10/youtube_explode_dart
|
homepage: https://github.com/Hexer10/youtube_explode_dart
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
|
Loading…
Reference in New Issue