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).
pull/1151/head
Profpatsch 2024-01-07 14:31:34 +01:00
rodzic 3402cdb666
commit 7408173246
5 zmienionych plików z 40 dodań i 21 usunięć

Wyświetl plik

@ -11,10 +11,12 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class Localization implements Serializable {
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
* #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) {
final List<Localization> toReturn = new ArrayList<>();
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);
}
/**
* @param localizationCode a localization code, formatted like {@link #getLocalizationCode()}
* @return A Localization, if the code was valid.
*/
public static Localization fromLocalizationCode(final String localizationCode) {
return fromLocale(LocaleCompat.forLanguageTag(localizationCode));
@Nonnull
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) {
@ -61,10 +71,6 @@ public class Localization implements Serializable {
return countryCode == null ? "" : countryCode;
}
public Locale asLocale() {
return new Locale(getLanguageCode(), getCountryCode());
}
public static Localization fromLocale(@Nonnull final Locale locale) {
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
* just {@code language} if country is {@code null}.
*
* @return A correctly formatted localizationCode for this localization.
*/
public String getLocalizationCode() {
return languageCode + (countryCode == null ? "" : "-" + countryCode);

Wyświetl plik

@ -130,7 +130,10 @@ public class MediaCCCStreamExtractor extends StreamExtractor {
// track with multiple languages, so there is no specific language for this stream
// Don't set the audio language in this case
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

Wyświetl plik

@ -190,7 +190,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
try { // Premiered 20 hours ago
final TimeAgoParser timeAgoParser = TimeAgoPatternsManager.getTimeAgoParserFor(
Localization.fromLocalizationCode("en"));
Localization.fromLocalizationCode("en").get());
final OffsetDateTime parsedTime = timeAgoParser.parse(time).offsetDateTime();
return DateTimeFormatter.ISO_LOCAL_DATE.format(parsedTime);
} catch (final Exception ignored) {
@ -1378,8 +1378,13 @@ public class YoutubeStreamExtractor extends StreamExtractor {
final int audioTrackIdLastLocaleCharacter = audioTrackId.indexOf(".");
if (audioTrackIdLastLocaleCharacter != -1) {
// Audio tracks IDs are in the form LANGUAGE_CODE.TRACK_NUMBER
itagItem.setAudioLocale(LocaleCompat.forLanguageTag(
audioTrackId.substring(0, audioTrackIdLastLocaleCharacter)));
@Nullable final Locale locale =
LocaleCompat.forLanguageTag(
audioTrackId.substring(0, audioTrackIdLastLocaleCharacter
)).orElse(null);
if (locale != null) {
itagItem.setAudioLocale(locale);
}
}
itagItem.setAudioTrackType(YoutubeParsingHelper.extractAudioTrackType(streamUrl));
}

Wyświetl plik

@ -231,7 +231,9 @@ public final class SubtitlesStream extends Stream {
final boolean autoGenerated,
@Nullable final String 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.format = mediaFormat;
this.autoGenerated = autoGenerated;

Wyświetl plik

@ -1,6 +1,7 @@
package org.schabi.newpipe.extractor.utils;
import java.util.Locale;
import java.util.Optional;
/**
* 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.
// 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("-")) {
final String[] args = str.split("-", -1);
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) {
return new Locale(args[0], args[1]);
return Optional.of(new Locale(args[0], args[1]));
} else if (args.length == 1) {
return new Locale(args[0]);
return Optional.of(new Locale(args[0]));
}
} else if (str.contains("_")) {
final String[] args = str.split("_", -1);
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) {
return new Locale(args[0], args[1]);
return Optional.of(new Locale(args[0], args[1]));
} else if (args.length == 1) {
return new Locale(args[0]);
return Optional.of(new Locale(args[0]));
}
} else {
return new Locale(str);
return Optional.of(new Locale(str));
}
throw new IllegalArgumentException("Can not parse language tag: [" + str + "]");
return Optional.empty();
}
}