Skip to content

Commit

Permalink
[YouTube] Add support for extracting auto-translated captions
Browse files Browse the repository at this point in the history
Closes #977
Based on and adresses TeamNewPipe/NewPipe#8023
  • Loading branch information
TobiGr committed Dec 5, 2022
1 parent 41c8dce commit efce384
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ private void loadSubtitles() {
.setMediaFormat(fmt)
.setLanguageCode(languageCode)
.setAutoGenerated(false)
.setAutoTranslated(false)
.build());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -688,21 +688,20 @@ public List<SubtitlesStream> getSubtitlesDefault() throws ParsingException {

@Override
@Nonnull
public List<SubtitlesStream> getSubtitles(final MediaFormat format) throws ParsingException {
public List<SubtitlesStream> getSubtitles(@Nonnull final MediaFormat format) {
assertPageFetched();

// We cannot store the subtitles list because the media format may change
final List<SubtitlesStream> subtitlesToReturn = new ArrayList<>();
final JsonObject renderer = playerResponse.getObject("captions")
.getObject("playerCaptionsTracklistRenderer");
final JsonArray captionsArray = renderer.getArray("captionTracks");
// TODO: use this to apply auto translation to different language from a source language
// final JsonArray autoCaptionsArray = renderer.getArray("translationLanguages");

for (int i = 0; i < captionsArray.size(); i++) {
final String languageCode = captionsArray.getObject(i).getString("languageCode");
final String baseUrl = captionsArray.getObject(i).getString("baseUrl");
final String vssId = captionsArray.getObject(i).getString("vssId");
final JsonObject caption = captionsArray.getObject(i);
final String languageCode = caption.getString("languageCode");
final String baseUrl = caption.getString("baseUrl");
final String vssId = caption.getString("vssId");

if (languageCode != null && baseUrl != null && vssId != null) {
final boolean isAutoGenerated = vssId.startsWith("a.");
Expand All @@ -717,7 +716,24 @@ public List<SubtitlesStream> getSubtitles(final MediaFormat format) throws Parsi
.setMediaFormat(format)
.setLanguageCode(languageCode)
.setAutoGenerated(isAutoGenerated)
.setAutoTranslated(false)
.build());
if (i == 0 && caption.getBoolean("isTranslatable")
&& renderer.has("translationLanguages")) {
final JsonArray languages = renderer.getArray("translationLanguages");
for (int j = 0; j < languages.size(); j++) {
final JsonObject lang = languages.getObject(j);
final String tLanguageCode = lang.getString("languageCode");
subtitlesToReturn.add(new SubtitlesStream.Builder()
.setContent(cleanUrl + "&fmt=" + format.getSuffix()
+ "&tlang=" + tLanguageCode, true)
.setMediaFormat(format)
.setLanguageCode(tLanguageCode)
.setAutoGenerated(isAutoGenerated)
.setAutoTranslated(true)
.build());
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public final class SubtitlesStream extends Stream {
private final MediaFormat format;
private final Locale locale;
private final boolean autoGenerated;
private final boolean autoTranslated;
private final String code;

/**
Expand All @@ -30,6 +31,7 @@ public static final class Builder {
private String languageCode;
// Use of the Boolean class instead of the primitive type needed for setter call check
private Boolean autoGenerated;
private Boolean autoTranslated;

/**
* Create a new {@link Builder} instance with default values.
Expand Down Expand Up @@ -150,6 +152,18 @@ public Builder setAutoGenerated(final boolean autoGenerated) {
return this;
}

/**
* Set whether the subtitles have been automatically translated
* (i.e. by a machine like Google Translator) by the streaming service.
* @param autoTranslated whether the subtitles have been automatically translated by the
* streaming service
* @return this {@link Builder} instance
*/
public Builder setAutoTranslated(final boolean autoTranslated) {
this.autoTranslated = autoTranslated;
return this;
}

/**
* Build a {@link SubtitlesStream} using the builder's current values.
*
Expand Down Expand Up @@ -194,13 +208,19 @@ public SubtitlesStream build() {
+ "with setIsAutoGenerated.");
}

if (autoTranslated == null) {
throw new IllegalStateException("The subtitles stream has been not set as an "
+ "automatically translated subtitles stream or not. "
+ "Please specify this information with setIsAutoTranslated.");
}

if (id == null) {
id = languageCode + (mediaFormat != null ? "." + mediaFormat.suffix
: "");
}

return new SubtitlesStream(id, content, isUrl, mediaFormat, deliveryMethod,
languageCode, autoGenerated, manifestUrl);
languageCode, autoGenerated, autoTranslated, manifestUrl);
}
}

Expand All @@ -217,6 +237,7 @@ public SubtitlesStream build() {
* @param deliveryMethod the {@link DeliveryMethod} of the stream
* @param languageCode the language code of the stream
* @param autoGenerated whether the subtitles are auto-generated by the streaming service
* @param autoTranslated whether the subtitles are auto-translated by the streaming service
* @param manifestUrl the URL of the manifest this stream comes from (if applicable,
* otherwise null)
*/
Expand All @@ -228,6 +249,7 @@ private SubtitlesStream(@Nonnull final String id,
@Nonnull final DeliveryMethod deliveryMethod,
@Nonnull final String languageCode,
final boolean autoGenerated,
final boolean autoTranslated,
@Nullable final String manifestUrl) {
super(id, content, isUrl, mediaFormat, deliveryMethod, manifestUrl);

Expand All @@ -253,6 +275,7 @@ private SubtitlesStream(@Nonnull final String id,
this.code = languageCode;
this.format = mediaFormat;
this.autoGenerated = autoGenerated;
this.autoTranslated = autoTranslated;
}

/**
Expand All @@ -265,7 +288,7 @@ public String getExtension() {
}

/**
* Return whether if the subtitles are auto-generated.
* Return whether the subtitles are auto-generated.
* <p>
* Some streaming services can generate subtitles for their contents, like YouTube.
* </p>
Expand All @@ -276,6 +299,21 @@ public boolean isAutoGenerated() {
return autoGenerated;
}

/**
* Whether the subtitles are translated automatically by a machine.
*
* <p>
* Some streaming services provide automatically translated subtitles.
* YouTube, for example, uses Google translator to generate translated subtitles.
* Automatically translated subtitles might not coincide completely with the original text.
* </p>
*
* @return {code true} if the subtitles are auto-translated, {@link false} otherwise
*/
public boolean isAutoTranslated() {
return autoTranslated;
}

/**
* {@inheritDoc}
*/
Expand Down

0 comments on commit efce384

Please sign in to comment.