Version 1.7.5

This commit is contained in:
Mattia 2020-12-30 15:00:11 +01:00
parent a9275af1e2
commit 4498e79c89
13 changed files with 68 additions and 64 deletions

View File

@ -1,3 +1,8 @@
## 1.7.5
- Fix auto translated closed captions ( #50 )
- Deprecated `autoGenerated` from `getManifest`.
- Added `autoGenerated` parameter to `manifest.getByLanguage(...)`
## 1.7.4
- Fix slow download ( #92 )
- Fix stream retrieving on some videos ( #90 )

View File

@ -3,7 +3,8 @@ import 'package:http/http.dart';
import 'youtube_explode_exception.dart';
/// Exception thrown when a fatal failure occurs.
class FatalFailureException implements YoutubeExplodeException {
class FatalFailureException
implements YoutubeExplodeException {
/// Description message
@override
final String message;
@ -20,4 +21,7 @@ If this issue persists, please report it on the project's GitHub page.
Request: ${response.request}
Response: (${response.statusCode})
''';
@override
String toString() => '$runtimeType: $message';
}

View File

@ -21,4 +21,7 @@ Unfortunately, there's nothing the library can do to work around this error.
Request: ${response.request}
Response: $response
''';
@override
String toString() => '$runtimeType: $message';
}

View File

@ -22,5 +22,5 @@ Response: $response
''';
@override
String toString() => 'TransientFailureException: $message';
String toString() => '$runtimeType: $message';
}

View File

@ -15,4 +15,7 @@ class VideoRequiresPurchaseException implements VideoUnplayableException {
: message = 'Video `$videoId` is unplayable because it requires purchase.'
'Streams are not available for this video.'
'There is a preview video available: `$previewVideoId`.';
@override
String toString() => '$runtimeType: $message';
}

View File

@ -20,4 +20,7 @@ class VideoUnavailableException implements VideoUnplayableException {
'If you can however open this video in your browser in incognito mode, ' // ignore: lines_longer_than_80_chars
'it most likely means that YouTube changed something, which broke this library.\n' // ignore: lines_longer_than_80_chars
'Please report this issue on GitHub in that case.';
@override
String toString() => '$runtimeType: $message';
}

View File

@ -28,4 +28,7 @@ class VideoUnplayableException implements YoutubeExplodeException {
VideoUnplayableException.notLiveStream(VideoId videoId)
: message = 'Video \'$videoId\' is not an ongoing live stream.\n'
'Live stream manifest is not available for this video';
@override
String toString() => '$runtimeType: $message';
}

View File

@ -5,7 +5,4 @@ abstract class YoutubeExplodeException implements Exception {
///
YoutubeExplodeException(this.message);
@override
String toString() => '$runtimeType: $message}';
}
}

View File

@ -22,55 +22,31 @@ class ClosedCaptionClient {
/// Gets the manifest that contains information
/// about available closed caption tracks in the specified video.
Future<ClosedCaptionManifest> getManifest(dynamic videoId,
{bool autoGenerated = false}) async {
Future<ClosedCaptionManifest> getManifest(
dynamic videoId,
{@Deprecated('Not used anymore, use track.isAutoGenerated to see if a track is autogenerated or not.') // ignore: lines_longer_than_80_chars
bool autoGenerated = false,
List<ClosedCaptionFormat> formats = const [
ClosedCaptionFormat.srv1,
ClosedCaptionFormat.srv2,
ClosedCaptionFormat.srv3,
ClosedCaptionFormat.ttml,
ClosedCaptionFormat.vtt
]}) async {
videoId = VideoId.fromString(videoId);
var tracks = <ClosedCaptionTrackInfo>[];
if (!autoGenerated) {
var subList = await _httpClient.get(
'https://video.google.com/timedtext?hl=en&type=list&v=${videoId.value}',
validate: true);
// ignore: deprecated_member_use
var content = xml.parse(subList.body);
var tracks = <ClosedCaptionTrackInfo>{};
var videoInfoResponse =
await VideoInfoResponse.get(_httpClient, videoId.value);
var playerResponse = videoInfoResponse.playerResponse;
var langList = <String>[];
for (var track in content.findAllElements('track')) {
var lang = track.getAttribute('lang_code');
if (langList.contains(lang)) {
continue;
}
langList.add(lang);
for (var ext in ClosedCaptionFormat.values) {
tracks.add(ClosedCaptionTrackInfo(
Uri.parse('https://www.youtube.com/api/timedtext')
.replaceQueryParameters({
'lang': lang,
'v': videoId.value,
'fmt': ext.formatCode,
'name': track.getAttribute('name'),
}),
Language(lang, track.getAttribute('lang_translated')),
format: ext));
}
}
if (langList.isEmpty) {
return ClosedCaptionManifest([]);
}
return ClosedCaptionManifest(tracks);
} else {
var videoInfoResponse =
await VideoInfoResponse.get(_httpClient, videoId.value);
var playerResponse = videoInfoResponse.playerResponse;
for (var track in playerResponse.closedCaptionTrack) {
for (var ext in ClosedCaptionFormat.values) {
tracks.add(ClosedCaptionTrackInfo(
Uri.parse(track.url)
.replaceQueryParameters({'fmt': ext.formatCode}),
Language(track.languageCode, track.languageName),
isAutoGenerated: track.autoGenerated,
format: ext));
}
for (var track in playerResponse.closedCaptionTrack) {
for (var ext in formats) {
tracks.add(ClosedCaptionTrackInfo(
Uri.parse(track.url)
.replaceQueryParameters({'fmt': ext.formatCode}),
Language(track.languageCode, track.languageName),
isAutoGenerated: track.autoGenerated,
format: ext));
}
}
return ClosedCaptionManifest(tracks);

View File

@ -14,15 +14,17 @@ class ClosedCaptionManifest {
: tracks = UnmodifiableListView(tracks);
/// Gets all the closed caption tracks in the specified language and format.
/// If [autoGenerated] is true auto generated tracks are included as well.
/// Returns an empty list of no track is found.
List<ClosedCaptionTrackInfo> getByLanguage(String language,
{ClosedCaptionFormat format}) {
{ClosedCaptionFormat format, bool autoGenerated = false}) {
language = language.toLowerCase();
return tracks
.where((e) =>
(e.language.code.toLowerCase() == language ||
e.language.name.toLowerCase() == language) &&
(format == null || e.format == format))
(format == null || e.format == format) &&
(!autoGenerated || e.isAutoGenerated))
.toList();
}
}

View File

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
@ -31,7 +33,7 @@ class ClosedCaptionTrackInfo extends Equatable {
/// Keeping the same format.
ClosedCaptionTrackInfo autoTranslate(String lang) {
return ClosedCaptionTrackInfo(
url.replaceQueryParameters({'tlang': lang}), Language(lang, ''),
url.replaceQueryParameters({'tlang': lang}), Language(lang, lang),
isAutoGenerated: isAutoGenerated, format: format);
}

View File

@ -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.7.4
version: 1.7.5
homepage: https://github.com/Hexer10/youtube_explode_dart
environment:

View File

@ -22,10 +22,17 @@ void main() {
expect(track.captions, isNotEmpty);
});
test('Get closed auto translated caption track file of a video', () async {
var manifest = await yt.videos.closedCaptions.getManifest('WOxr2dmLHLo');
var trackInfo = manifest.tracks.first;
var subtitles = await yt.videos.closedCaptions.getSubTitles(trackInfo);
expect(subtitles, isNotEmpty);
});
test('Get closed caption track at a specific time', () async {
var manifest = await yt.videos.closedCaptions
.getManifest('WOxr2dmLHLo', autoGenerated: false);
var trackInfo = manifest.getByLanguage('en');
var manifest = await yt.videos.closedCaptions.getManifest('qfJthDvcZ08');
var trackInfo = manifest.getByLanguage('en', autoGenerated: false);
var track = await yt.videos.closedCaptions.get(trackInfo.first);
var caption =
track.getByTime(const Duration(hours: 0, minutes: 1, seconds: 48));
@ -33,13 +40,12 @@ void main() {
expect(caption, isNotNull);
expect(caption.parts, isEmpty);
expect(caption.text,
'The second way to add subtitles is the one\nwe always use.');
'But what if you don\'t have a captions file');
});
test('Get auto-generated closed caption track at a specific time', () async {
var manifest = await yt.videos.closedCaptions
.getManifest('ppJy5uGZLi4', autoGenerated: true);
var trackInfo = manifest.getByLanguage('en');
var manifest = await yt.videos.closedCaptions.getManifest('ppJy5uGZLi4');
var trackInfo = manifest.getByLanguage('en', autoGenerated: true);
var track = await yt.videos.closedCaptions.get(trackInfo.first);
var caption =
track.getByTime(const Duration(hours: 0, minutes: 13, seconds: 22));