Version 1.10.1
This commit is contained in:
parent
73504b2a44
commit
c640d08f29
|
@ -1,3 +1,8 @@
|
|||
## 1.10.1
|
||||
- Fix issue #146: Closed Captions couldn't be extracted anymore.
|
||||
- Code cleanup.
|
||||
-
|
||||
|
||||
## 1.10.0
|
||||
- Fix issue #144: get_video_info was removed from yt.
|
||||
- Min sdk version now is 2.13.0
|
||||
|
|
|
@ -5,7 +5,6 @@ part 'engagement.freezed.dart';
|
|||
/// User activity statistics.
|
||||
@freezed
|
||||
class Engagement with _$Engagement {
|
||||
const Engagement._();
|
||||
|
||||
const factory Engagement(
|
||||
/// View count.
|
||||
|
@ -18,6 +17,8 @@ class Engagement with _$Engagement {
|
|||
int? dislikeCount,
|
||||
) = _Engagement;
|
||||
|
||||
const Engagement._();
|
||||
|
||||
/// Average user rating in stars (1 star to 5 stars).
|
||||
/// Returns -1 if likeCount or dislikeCount is null.
|
||||
num get avgRating {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import 'package:html/parser.dart' as parser;
|
||||
import 'package:youtube_explode_dart/src/reverse_engineering/models/youtube_page.dart';
|
||||
|
||||
import '../../exceptions/exceptions.dart';
|
||||
import '../../extensions/helpers_extension.dart';
|
||||
import '../../retry.dart';
|
||||
import '../youtube_http_client.dart';
|
||||
import '../models/initial_data.dart';
|
||||
import '../models/youtube_page.dart';
|
||||
import '../youtube_http_client.dart';
|
||||
|
||||
///
|
||||
class ChannelPage extends YoutubePage<_InitialData> {
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:html/parser.dart' as parser;
|
||||
import 'package:youtube_explode_dart/src/reverse_engineering/models/youtube_page.dart';
|
||||
|
||||
import '../../channels/channel_video.dart';
|
||||
import '../../exceptions/exceptions.dart';
|
||||
import '../../extensions/helpers_extension.dart';
|
||||
import '../../retry.dart';
|
||||
import '../../videos/videos.dart';
|
||||
import '../youtube_http_client.dart';
|
||||
import '../models/initial_data.dart';
|
||||
import '../models/youtube_page.dart';
|
||||
import '../youtube_http_client.dart';
|
||||
|
||||
///
|
||||
class ChannelUploadPage extends YoutubePage<_InitialData> {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:html/parser.dart' as parser;
|
||||
import 'package:youtube_explode_dart/src/reverse_engineering/models/youtube_page.dart';
|
||||
|
||||
import '../../../youtube_explode_dart.dart';
|
||||
import '../../extensions/helpers_extension.dart';
|
||||
import '../../retry.dart';
|
||||
import '../youtube_http_client.dart';
|
||||
import '../models/initial_data.dart';
|
||||
import '../models/youtube_page.dart';
|
||||
import '../youtube_http_client.dart';
|
||||
|
||||
///
|
||||
class PlaylistPage extends YoutubePage<_InitialData> {
|
||||
|
|
|
@ -11,8 +11,8 @@ import '../../search/related_query.dart';
|
|||
import '../../search/search_filter.dart';
|
||||
import '../../search/search_video.dart';
|
||||
import '../../videos/videos.dart';
|
||||
import '../youtube_http_client.dart';
|
||||
import '../models/initial_data.dart';
|
||||
import '../youtube_http_client.dart';
|
||||
|
||||
///
|
||||
class SearchPage extends YoutubePage<_InitialData> {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:html/parser.dart' as parser;
|
||||
import 'package:youtube_explode_dart/src/reverse_engineering/models/youtube_page.dart';
|
||||
|
||||
import '../../../youtube_explode_dart.dart';
|
||||
import '../../extensions/helpers_extension.dart';
|
||||
import '../../retry.dart';
|
||||
import '../../videos/video_id.dart';
|
||||
import '../models/initial_data.dart';
|
||||
import '../models/youtube_page.dart';
|
||||
import '../player/player_response.dart';
|
||||
import '../youtube_http_client.dart';
|
||||
import 'player_config_base.dart';
|
||||
import '../models/initial_data.dart';
|
||||
|
||||
///
|
||||
class WatchPage extends YoutubePage<_InitialData> {
|
||||
|
@ -21,12 +21,11 @@ class WatchPage extends YoutubePage<_InitialData> {
|
|||
static final RegExp _visitorInfoLiveExp =
|
||||
RegExp('VISITOR_INFO1_LIVE=([^;]+)');
|
||||
static final RegExp _yscExp = RegExp('YSC=([^;]+)');
|
||||
static final RegExp _playerResponseExp =
|
||||
RegExp(r'var\s+ytInitialPlayerResponse\s*=\s*(\{.*\})');
|
||||
|
||||
static final _xsfrTokenExp = RegExp(r'"XSRF_TOKEN"\s*:\s*"(.+?)"');
|
||||
|
||||
@override
|
||||
// Overridden to be non-nullable.
|
||||
// ignore: overridden_fields
|
||||
final Document root;
|
||||
|
||||
///
|
||||
|
@ -48,18 +47,6 @@ class WatchPage extends YoutubePage<_InitialData> {
|
|||
return 'https://youtube.com$url';
|
||||
}
|
||||
|
||||
late final String xsfrToken = getXsfrToken()!.replaceAll(r'\u003d', '=');
|
||||
|
||||
///
|
||||
String? getXsfrToken() {
|
||||
return _xsfrTokenExp
|
||||
.firstMatch(root
|
||||
.querySelectorAll('script')
|
||||
.firstWhere((e) => _xsfrTokenExp.hasMatch(e.text))
|
||||
.text)
|
||||
?.group(1);
|
||||
}
|
||||
|
||||
///
|
||||
bool get isOk => root.body?.querySelector('#player') != null;
|
||||
|
||||
|
|
|
@ -148,8 +148,8 @@ class ClosedCaptionTrack {
|
|||
String get languageCode => root.getT<String>('languageCode')!;
|
||||
|
||||
///
|
||||
String get languageName =>
|
||||
root.get('name')!.getT<List<dynamic>>('runs')!.parseRuns();
|
||||
String? get languageName =>
|
||||
root.get('name')!.getT<String>('simpleText');
|
||||
|
||||
///
|
||||
bool get autoGenerated =>
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:http_parser/http_parser.dart';
|
||||
|
||||
import '../../exceptions/exceptions.dart';
|
||||
import '../../extensions/helpers_extension.dart';
|
||||
import '../../retry.dart';
|
||||
import '../youtube_http_client.dart';
|
||||
import '../player/player_response.dart';
|
||||
import '../models/stream_info_provider.dart';
|
||||
import '../player/player_response.dart';
|
||||
import '../youtube_http_client.dart';
|
||||
|
||||
///
|
||||
///
|
||||
@deprecated
|
||||
@Deprecated('This endpoint is not supported anymore.')
|
||||
class VideoInfoClient {
|
||||
final Map<String, String> root;
|
||||
|
||||
|
@ -51,6 +52,7 @@ class VideoInfoClient {
|
|||
VideoInfoClient.parse(String raw) : root = Uri.splitQueryString(raw);
|
||||
|
||||
///
|
||||
@alwaysThrows
|
||||
static Future<VideoInfoClient> get(
|
||||
YoutubeHttpClient httpClient, String videoId,
|
||||
[String? sts]) {
|
||||
|
|
|
@ -37,6 +37,7 @@ class SearchVideo with _$SearchVideo, BaseSearchContent {
|
|||
String? uploadDate,
|
||||
|
||||
/// True if this video is a live stream.
|
||||
// ignore: avoid_positional_boolean_parameters
|
||||
bool isLive,
|
||||
|
||||
/// Channel id
|
||||
|
|
|
@ -72,6 +72,7 @@ mixin _$SearchVideo {
|
|||
String? get uploadDate => throw _privateConstructorUsedError;
|
||||
|
||||
/// True if this video is a live stream.
|
||||
// ignore: avoid_positional_boolean_parameters
|
||||
bool get isLive => throw _privateConstructorUsedError;
|
||||
|
||||
/// Channel id
|
||||
|
@ -317,6 +318,7 @@ class _$_SearchVideo with BaseSearchContent implements _SearchVideo {
|
|||
@override
|
||||
|
||||
/// True if this video is a live stream.
|
||||
// ignore: avoid_positional_boolean_parameters
|
||||
final bool isLive;
|
||||
@override
|
||||
|
||||
|
@ -428,6 +430,7 @@ abstract class _SearchVideo implements SearchVideo, BaseSearchContent {
|
|||
@override
|
||||
|
||||
/// True if this video is a live stream.
|
||||
// ignore: avoid_positional_boolean_parameters
|
||||
bool get isLive => throw _privateConstructorUsedError;
|
||||
@override
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:youtube_explode_dart/src/reverse_engineering/pages/watch_page.dart';
|
||||
|
||||
import '../../extensions/helpers_extension.dart';
|
||||
import '../../reverse_engineering/responses/closed_caption_client.dart' as re
|
||||
show ClosedCaptionClient;
|
||||
import '../../reverse_engineering/responses/video_info_client.dart';
|
||||
import '../../reverse_engineering/youtube_http_client.dart';
|
||||
import '../videos.dart';
|
||||
import 'closed_caption.dart';
|
||||
|
@ -34,16 +35,16 @@ class ClosedCaptionClient {
|
|||
]}) async {
|
||||
videoId = VideoId.fromString(videoId);
|
||||
var tracks = <ClosedCaptionTrackInfo>{};
|
||||
var videoInfoResponse =
|
||||
await VideoInfoClient.get(_httpClient, videoId.value);
|
||||
var playerResponse = videoInfoResponse.playerResponse;
|
||||
var watchPage =
|
||||
await WatchPage.get(_httpClient, videoId.value);
|
||||
var playerResponse = watchPage.playerResponse!;
|
||||
|
||||
for (final track in playerResponse.closedCaptionTrack) {
|
||||
for (final ext in formats) {
|
||||
tracks.add(ClosedCaptionTrackInfo(
|
||||
Uri.parse(track.url)
|
||||
.replaceQueryParameters({'fmt': ext.formatCode}),
|
||||
Language(track.languageCode, track.languageName),
|
||||
Language(track.languageCode, track.languageName ?? ''),
|
||||
isAutoGenerated: track.autoGenerated,
|
||||
format: ext));
|
||||
}
|
||||
|
|
|
@ -13,14 +13,11 @@ class Language with _$Language {
|
|||
/// ISO 639-1 code of this language.
|
||||
String code,
|
||||
|
||||
/// Full English name of this language.
|
||||
/// Full English name of this language. This could be an empty string.
|
||||
String name) = _Language;
|
||||
|
||||
const Language._();
|
||||
|
||||
@override
|
||||
String toString() => 'Language: $name';
|
||||
|
||||
///
|
||||
factory Language.fromJson(Map<String, dynamic> json) =>
|
||||
_$LanguageFromJson(json);
|
||||
|
|
|
@ -40,7 +40,7 @@ mixin _$Language {
|
|||
/// ISO 639-1 code of this language.
|
||||
String get code => throw _privateConstructorUsedError;
|
||||
|
||||
/// Full English name of this language.
|
||||
/// Full English name of this language. This could be an empty string.
|
||||
String get name => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
@ -131,9 +131,14 @@ class _$_Language extends _Language {
|
|||
final String code;
|
||||
@override
|
||||
|
||||
/// Full English name of this language.
|
||||
/// Full English name of this language. This could be an empty string.
|
||||
final String name;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Language(code: $code, name: $name)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
|
@ -173,7 +178,7 @@ abstract class _Language extends Language {
|
|||
String get code => throw _privateConstructorUsedError;
|
||||
@override
|
||||
|
||||
/// Full English name of this language.
|
||||
/// Full English name of this language. This could be an empty string.
|
||||
String get name => throw _privateConstructorUsedError;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
import '../../channels/channel_id.dart';
|
||||
import '../../extensions/helpers_extension.dart';
|
||||
import '../../reverse_engineering/responses/comments_client.dart' as re;
|
||||
import '../../reverse_engineering/youtube_http_client.dart';
|
||||
import '../videos.dart';
|
||||
|
|
|
@ -26,9 +26,6 @@ class Bitrate with Comparable<Bitrate>, _$Bitrate {
|
|||
@override
|
||||
int compareTo(Bitrate other) => bitsPerSecond.compareTo(other.bitsPerSecond);
|
||||
|
||||
@override
|
||||
List<Object> get props => [bitsPerSecond];
|
||||
|
||||
String _getLargestSymbol() {
|
||||
if (gigaBitsPerSecond.abs() >= 1) {
|
||||
return 'Gbit/s';
|
||||
|
|
|
@ -4,10 +4,8 @@ import '../../reverse_engineering/cipher/cipher_operations.dart';
|
|||
import '../../reverse_engineering/dash_manifest.dart';
|
||||
import '../../reverse_engineering/heuristics.dart';
|
||||
import '../../reverse_engineering/models/stream_info_provider.dart';
|
||||
import '../../reverse_engineering/pages/embed_page.dart';
|
||||
import '../../reverse_engineering/pages/watch_page.dart';
|
||||
import '../../reverse_engineering/player/player_source.dart';
|
||||
import '../../reverse_engineering/responses/video_info_client.dart';
|
||||
import '../../reverse_engineering/youtube_http_client.dart';
|
||||
import '../video_id.dart';
|
||||
import 'bitrate.dart';
|
||||
|
@ -37,7 +35,8 @@ class StreamsClient {
|
|||
return DashManifest.get(_httpClient, dashManifestUrl);
|
||||
}
|
||||
|
||||
Future<StreamContext> _getStreamContextFromVideoInfo(VideoId videoId) async {
|
||||
// Not used anymore since Youtube removed the `video_info` endpoint.
|
||||
/* Future<StreamContext> _getStreamContextFromVideoInfo(VideoId videoId) async {
|
||||
var embedPage = await EmbedPage.get(_httpClient, videoId.toString());
|
||||
var playerConfig = embedPage.playerConfig;
|
||||
if (playerConfig == null) {
|
||||
|
@ -79,7 +78,7 @@ class StreamsClient {
|
|||
streamInfoProviders.addAll(dashManifest.streams);
|
||||
}
|
||||
return StreamContext(streamInfoProviders, cipherOperations);
|
||||
}
|
||||
}*/
|
||||
|
||||
Future<StreamContext> _getStreamContextFromWatchPage(VideoId videoId) async {
|
||||
final watchPage = await WatchPage.get(_httpClient, videoId.toString());
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import 'package:youtube_explode_dart/src/reverse_engineering/player/player_response.dart';
|
||||
|
||||
import '../channels/channel_id.dart';
|
||||
import '../common/common.dart';
|
||||
import '../extensions/helpers_extension.dart';
|
||||
|
|
|
@ -11,13 +11,6 @@ class VideoId with _$VideoId {
|
|||
static final _shortMatchExp = RegExp(r'youtu\.be/(.*?)(?:\?|&|/|$)');
|
||||
static final _embedMatchExp = RegExp(r'youtube\..+?/embed/(.*?)(?:\?|&|/|$)');
|
||||
|
||||
const VideoId._();
|
||||
|
||||
const factory VideoId._internal(
|
||||
|
||||
/// ID as string.
|
||||
String value) = _VideoId;
|
||||
|
||||
/// Initializes an instance of [VideoId] with a url or video id.
|
||||
factory VideoId(String idOrUrl) {
|
||||
final id = parseVideoId(idOrUrl);
|
||||
|
@ -29,6 +22,13 @@ class VideoId with _$VideoId {
|
|||
return VideoId._internal(id);
|
||||
}
|
||||
|
||||
const VideoId._();
|
||||
|
||||
const factory VideoId._internal(
|
||||
|
||||
/// ID as string.
|
||||
String value) = _VideoId;
|
||||
|
||||
/// Converts [obj] to a [VideoId] by calling .toString on that object.
|
||||
/// If it is already a [VideoId], [obj] is returned
|
||||
factory VideoId.fromString(dynamic obj) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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.
|
||||
version: 1.10.0
|
||||
version: 1.10.1
|
||||
|
||||
homepage: https://github.com/Hexer10/youtube_explode_dart
|
||||
|
||||
|
|
Loading…
Reference in New Issue