LocaleCompat.forLanguageTag: return Optional if parsing fails
It’s not obvious that the function will fail in some cases and throw an `IllegalArgumentException`. So instead of just failing if parsing fails, return an Optional that all callers have to decide what to do (e.g. the YoutubeExtractor can just ignore the locale in that case, like it does with most other fields in the json if they are unexpected).
This commit is contained in:
parent
3402cdb666
commit
7408173246
|
@ -11,10 +11,12 @@ import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
public class Localization implements Serializable {
|
public class Localization implements Serializable {
|
||||||
public static final Localization DEFAULT = new Localization("en", "GB");
|
public static final Localization DEFAULT = new Localization("en", "GB");
|
||||||
|
|
||||||
|
@ -26,20 +28,28 @@ public class Localization implements Serializable {
|
||||||
/**
|
/**
|
||||||
* @param localizationCodeList a list of localization code, formatted like {@link
|
* @param localizationCodeList a list of localization code, formatted like {@link
|
||||||
* #getLocalizationCode()}
|
* #getLocalizationCode()}
|
||||||
|
* @throws IllegalArgumentException If any of the localizationCodeList is formatted incorrectly
|
||||||
|
* @return list of Localization objects
|
||||||
*/
|
*/
|
||||||
|
@Nonnull
|
||||||
public static List<Localization> listFrom(final String... localizationCodeList) {
|
public static List<Localization> listFrom(final String... localizationCodeList) {
|
||||||
final List<Localization> toReturn = new ArrayList<>();
|
final List<Localization> toReturn = new ArrayList<>();
|
||||||
for (final String localizationCode : localizationCodeList) {
|
for (final String localizationCode : localizationCodeList) {
|
||||||
toReturn.add(fromLocalizationCode(localizationCode));
|
toReturn.add(fromLocalizationCode(localizationCode)
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException(
|
||||||
|
"Not a localization code: " + localizationCode
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
return Collections.unmodifiableList(toReturn);
|
return Collections.unmodifiableList(toReturn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param localizationCode a localization code, formatted like {@link #getLocalizationCode()}
|
* @param localizationCode a localization code, formatted like {@link #getLocalizationCode()}
|
||||||
|
* @return A Localization, if the code was valid.
|
||||||
*/
|
*/
|
||||||
public static Localization fromLocalizationCode(final String localizationCode) {
|
@Nonnull
|
||||||
return fromLocale(LocaleCompat.forLanguageTag(localizationCode));
|
public static Optional<Localization> fromLocalizationCode(final String localizationCode) {
|
||||||
|
return LocaleCompat.forLanguageTag(localizationCode).map(Localization::fromLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Localization(@Nonnull final String languageCode, @Nullable final String countryCode) {
|
public Localization(@Nonnull final String languageCode, @Nullable final String countryCode) {
|
||||||
|
@ -61,10 +71,6 @@ public class Localization implements Serializable {
|
||||||
return countryCode == null ? "" : countryCode;
|
return countryCode == null ? "" : countryCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Locale asLocale() {
|
|
||||||
return new Locale(getLanguageCode(), getCountryCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Localization fromLocale(@Nonnull final Locale locale) {
|
public static Localization fromLocale(@Nonnull final Locale locale) {
|
||||||
return new Localization(locale.getLanguage(), locale.getCountry());
|
return new Localization(locale.getLanguage(), locale.getCountry());
|
||||||
}
|
}
|
||||||
|
@ -72,6 +78,8 @@ public class Localization implements Serializable {
|
||||||
/**
|
/**
|
||||||
* Return a formatted string in the form of: {@code language-Country}, or
|
* Return a formatted string in the form of: {@code language-Country}, or
|
||||||
* just {@code language} if country is {@code null}.
|
* just {@code language} if country is {@code null}.
|
||||||
|
*
|
||||||
|
* @return A correctly formatted localizationCode for this localization.
|
||||||
*/
|
*/
|
||||||
public String getLocalizationCode() {
|
public String getLocalizationCode() {
|
||||||
return languageCode + (countryCode == null ? "" : "-" + countryCode);
|
return languageCode + (countryCode == null ? "" : "-" + countryCode);
|
||||||
|
|
|
@ -130,7 +130,10 @@ public class MediaCCCStreamExtractor extends StreamExtractor {
|
||||||
// track with multiple languages, so there is no specific language for this stream
|
// track with multiple languages, so there is no specific language for this stream
|
||||||
// Don't set the audio language in this case
|
// Don't set the audio language in this case
|
||||||
if (language != null && !language.contains("-")) {
|
if (language != null && !language.contains("-")) {
|
||||||
builder.setAudioLocale(LocaleCompat.forLanguageTag(language));
|
builder.setAudioLocale(LocaleCompat.forLanguageTag(language).orElseThrow(() ->
|
||||||
|
new ExtractionException(
|
||||||
|
"Cannot convert this language to a locale: " + language)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not checking containsSimilarStream here, since MediaCCC does not provide enough
|
// Not checking containsSimilarStream here, since MediaCCC does not provide enough
|
||||||
|
|
|
@ -190,7 +190,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
try { // Premiered 20 hours ago
|
try { // Premiered 20 hours ago
|
||||||
final TimeAgoParser timeAgoParser = TimeAgoPatternsManager.getTimeAgoParserFor(
|
final TimeAgoParser timeAgoParser = TimeAgoPatternsManager.getTimeAgoParserFor(
|
||||||
Localization.fromLocalizationCode("en"));
|
Localization.fromLocalizationCode("en").get());
|
||||||
final OffsetDateTime parsedTime = timeAgoParser.parse(time).offsetDateTime();
|
final OffsetDateTime parsedTime = timeAgoParser.parse(time).offsetDateTime();
|
||||||
return DateTimeFormatter.ISO_LOCAL_DATE.format(parsedTime);
|
return DateTimeFormatter.ISO_LOCAL_DATE.format(parsedTime);
|
||||||
} catch (final Exception ignored) {
|
} catch (final Exception ignored) {
|
||||||
|
@ -1378,8 +1378,13 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
final int audioTrackIdLastLocaleCharacter = audioTrackId.indexOf(".");
|
final int audioTrackIdLastLocaleCharacter = audioTrackId.indexOf(".");
|
||||||
if (audioTrackIdLastLocaleCharacter != -1) {
|
if (audioTrackIdLastLocaleCharacter != -1) {
|
||||||
// Audio tracks IDs are in the form LANGUAGE_CODE.TRACK_NUMBER
|
// Audio tracks IDs are in the form LANGUAGE_CODE.TRACK_NUMBER
|
||||||
itagItem.setAudioLocale(LocaleCompat.forLanguageTag(
|
@Nullable final Locale locale =
|
||||||
audioTrackId.substring(0, audioTrackIdLastLocaleCharacter)));
|
LocaleCompat.forLanguageTag(
|
||||||
|
audioTrackId.substring(0, audioTrackIdLastLocaleCharacter
|
||||||
|
)).orElse(null);
|
||||||
|
if (locale != null) {
|
||||||
|
itagItem.setAudioLocale(locale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
itagItem.setAudioTrackType(YoutubeParsingHelper.extractAudioTrackType(streamUrl));
|
itagItem.setAudioTrackType(YoutubeParsingHelper.extractAudioTrackType(streamUrl));
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,9 @@ public final class SubtitlesStream extends Stream {
|
||||||
final boolean autoGenerated,
|
final boolean autoGenerated,
|
||||||
@Nullable final String manifestUrl) {
|
@Nullable final String manifestUrl) {
|
||||||
super(id, content, isUrl, mediaFormat, deliveryMethod, manifestUrl);
|
super(id, content, isUrl, mediaFormat, deliveryMethod, manifestUrl);
|
||||||
this.locale = LocaleCompat.forLanguageTag(languageCode);
|
this.locale = LocaleCompat.forLanguageTag(languageCode).orElseThrow(
|
||||||
|
() -> new IllegalArgumentException(
|
||||||
|
"not a valid locale language code: " + languageCode));
|
||||||
this.code = languageCode;
|
this.code = languageCode;
|
||||||
this.format = mediaFormat;
|
this.format = mediaFormat;
|
||||||
this.autoGenerated = autoGenerated;
|
this.autoGenerated = autoGenerated;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.schabi.newpipe.extractor.utils;
|
package org.schabi.newpipe.extractor.utils;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class contains a simple implementation of {@link Locale#forLanguageTag(String)} for Android
|
* This class contains a simple implementation of {@link Locale#forLanguageTag(String)} for Android
|
||||||
|
@ -15,29 +16,29 @@ public final class LocaleCompat {
|
||||||
|
|
||||||
// Source: The AndroidX LocaleListCompat class's private forLanguageTagCompat() method.
|
// Source: The AndroidX LocaleListCompat class's private forLanguageTagCompat() method.
|
||||||
// Use Locale.forLanguageTag() on Android API level >= 21 / Java instead.
|
// Use Locale.forLanguageTag() on Android API level >= 21 / Java instead.
|
||||||
public static Locale forLanguageTag(final String str) {
|
public static Optional<Locale> forLanguageTag(final String str) {
|
||||||
if (str.contains("-")) {
|
if (str.contains("-")) {
|
||||||
final String[] args = str.split("-", -1);
|
final String[] args = str.split("-", -1);
|
||||||
if (args.length > 2) {
|
if (args.length > 2) {
|
||||||
return new Locale(args[0], args[1], args[2]);
|
return Optional.of(new Locale(args[0], args[1], args[2]));
|
||||||
} else if (args.length > 1) {
|
} else if (args.length > 1) {
|
||||||
return new Locale(args[0], args[1]);
|
return Optional.of(new Locale(args[0], args[1]));
|
||||||
} else if (args.length == 1) {
|
} else if (args.length == 1) {
|
||||||
return new Locale(args[0]);
|
return Optional.of(new Locale(args[0]));
|
||||||
}
|
}
|
||||||
} else if (str.contains("_")) {
|
} else if (str.contains("_")) {
|
||||||
final String[] args = str.split("_", -1);
|
final String[] args = str.split("_", -1);
|
||||||
if (args.length > 2) {
|
if (args.length > 2) {
|
||||||
return new Locale(args[0], args[1], args[2]);
|
return Optional.of(new Locale(args[0], args[1], args[2]));
|
||||||
} else if (args.length > 1) {
|
} else if (args.length > 1) {
|
||||||
return new Locale(args[0], args[1]);
|
return Optional.of(new Locale(args[0], args[1]));
|
||||||
} else if (args.length == 1) {
|
} else if (args.length == 1) {
|
||||||
return new Locale(args[0]);
|
return Optional.of(new Locale(args[0]));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return new Locale(str);
|
return Optional.of(new Locale(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException("Can not parse language tag: [" + str + "]");
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue