Refactor Language
|
@ -2,7 +2,9 @@ package net.filebot;
|
|||
|
||||
import static java.util.Arrays.*;
|
||||
import static java.util.Collections.*;
|
||||
import static java.util.Comparator.*;
|
||||
import static java.util.stream.Collectors.*;
|
||||
import static net.filebot.Logging.*;
|
||||
import static net.filebot.util.RegularExpressions.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
@ -23,13 +25,17 @@ public class Language implements Serializable {
|
|||
// ISO 639-2/B code
|
||||
private final String iso_639_2B;
|
||||
|
||||
// BCP 47 language tag
|
||||
private final String tag;
|
||||
|
||||
// Language name
|
||||
private final String[] names;
|
||||
|
||||
public Language(String iso_639_1, String iso_639_3, String iso_639_2B, String[] names) {
|
||||
public Language(String iso_639_1, String iso_639_3, String iso_639_2B, String tag, String[] names) {
|
||||
this.iso_639_1 = iso_639_1;
|
||||
this.iso_639_3 = iso_639_3;
|
||||
this.iso_639_2B = iso_639_2B;
|
||||
this.tag = tag;
|
||||
this.names = names.clone();
|
||||
}
|
||||
|
||||
|
@ -38,7 +44,7 @@ public class Language implements Serializable {
|
|||
}
|
||||
|
||||
public String getISO2() {
|
||||
return iso_639_1; // 2-letter code
|
||||
return iso_639_1;
|
||||
}
|
||||
|
||||
public String getISO3() {
|
||||
|
@ -49,6 +55,10 @@ public class Language implements Serializable {
|
|||
return iso_639_2B; // alternative 3-letter code
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return names[0];
|
||||
}
|
||||
|
@ -63,33 +73,36 @@ public class Language implements Serializable {
|
|||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
return new Locale(getCode());
|
||||
Locale locale = Locale.forLanguageTag(tag);
|
||||
|
||||
// e.g. x-jat
|
||||
if (locale == null || locale.getLanguage().isEmpty()) {
|
||||
return new Locale(iso_639_1);
|
||||
}
|
||||
|
||||
return locale;
|
||||
}
|
||||
|
||||
public boolean matches(String code) {
|
||||
if (iso_639_1.equalsIgnoreCase(code) || iso_639_3.equalsIgnoreCase(code) || iso_639_2B.equalsIgnoreCase(code)) {
|
||||
if (Stream.of(iso_639_1, iso_639_2B, iso_639_3, tag).anyMatch(c -> c.equalsIgnoreCase(code))) {
|
||||
return true;
|
||||
}
|
||||
for (String it : names) {
|
||||
if (it.equalsIgnoreCase(code) || code.toLowerCase().contains(it.toLowerCase())) {
|
||||
|
||||
for (String c : names) {
|
||||
if (c.equalsIgnoreCase(code) || code.toLowerCase().contains(c.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Language clone() {
|
||||
return new Language(iso_639_1, iso_639_3, iso_639_2B, names);
|
||||
return new Language(iso_639_1, iso_639_3, iso_639_2B, tag, names);
|
||||
}
|
||||
|
||||
public static final Comparator<Language> ALPHABETIC_ORDER = new Comparator<Language>() {
|
||||
|
||||
@Override
|
||||
public int compare(Language o1, Language o2) {
|
||||
return o1.getName().compareToIgnoreCase(o2.getName());
|
||||
}
|
||||
};
|
||||
public static final Comparator<Language> ALPHABETIC_ORDER = comparing(Language::getName, String::compareToIgnoreCase);
|
||||
|
||||
public static Language getLanguage(String code) {
|
||||
if (code == null || code.isEmpty()) {
|
||||
|
@ -97,11 +110,14 @@ public class Language implements Serializable {
|
|||
}
|
||||
|
||||
try {
|
||||
String[] values = TAB.split(getProperty(code), 3);
|
||||
return new Language(code, values[0], values[1], TAB.split(values[2]));
|
||||
String[] values = TAB.split(getProperty(code), 4);
|
||||
return new Language(code, values[0], values[1], values[2], TAB.split(values[3]));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
e.printStackTrace();
|
||||
debug.warning("Illegal language code: " + code);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<Language> getLanguages(String... codes) {
|
||||
|
@ -126,20 +142,20 @@ public class Language implements Serializable {
|
|||
|
||||
public static List<Language> availableLanguages() {
|
||||
String languages = getProperty("languages.ui");
|
||||
return getLanguages(COMMA.split(languages));
|
||||
return getLanguages(SPACE.split(languages));
|
||||
}
|
||||
|
||||
public static List<Language> commonLanguages() {
|
||||
String languages = getProperty("languages.common");
|
||||
return getLanguages(COMMA.split(languages));
|
||||
return getLanguages(SPACE.split(languages));
|
||||
}
|
||||
|
||||
public static List<Language> preferredLanguages() {
|
||||
// English | System language | common languages
|
||||
Stream<String> codes = Stream.of("en", Locale.getDefault().getLanguage());
|
||||
// English | system language | common languages
|
||||
Stream<String> codes = Stream.of(Locale.ENGLISH, Locale.getDefault()).map(Locale::getLanguage);
|
||||
|
||||
// append common languages
|
||||
codes = Stream.concat(codes, stream(COMMA.split(getProperty("languages.common")))).distinct();
|
||||
codes = Stream.concat(codes, SPACE.splitAsStream(getProperty("languages.common"))).distinct();
|
||||
|
||||
return codes.map(Language::getLanguage).collect(toList());
|
||||
}
|
||||
|
|
|
@ -1,45 +1,51 @@
|
|||
# available languages
|
||||
languages.ui = sq,ar,hy,pb,bg,ca,zh,hr,cs,da,nl,en,et,fi,fr,de,el,he,hi,hu,id,it,ja,ko,lv,lt,mk,ms,no,fa,pl,pt,ro,ru,sr,sk,sl,es,sv,th,tr,vi
|
||||
languages.common = en,de,fr,es,pt,ru,ja,zh
|
||||
sq: sqi alb Albanian
|
||||
ar: ara ara Arabic
|
||||
hy: hye arm Armenian
|
||||
pb: pob pob Brazilian Portuguese (BR)
|
||||
bg: bul bul Bulgarian
|
||||
ca: cat cat Catalan
|
||||
zh: zho chi Chinese
|
||||
hr: hrv hrv Croatian
|
||||
cs: ces cze Czech
|
||||
da: dan dan Danish
|
||||
nl: nld dut Dutch
|
||||
en: eng eng English
|
||||
et: est est Estonian
|
||||
fi: fin fin Finnish
|
||||
fr: fra fre French
|
||||
de: deu ger German
|
||||
el: ell gre Greek
|
||||
he: heb heb Hebrew
|
||||
hi: hin hin Hindi
|
||||
hu: hun hun Hungarian
|
||||
id: ind ind Indonesian
|
||||
it: ita ita Italian
|
||||
ja: jpn jpn Japanese
|
||||
ko: kor kor Korean
|
||||
lv: lav lav Latvian
|
||||
lt: lit lit Lithuanian
|
||||
mk: mkd mac Macedonian
|
||||
ms: msa may Malay
|
||||
no: nor nor Norwegian
|
||||
fa: fas per Persian
|
||||
pl: pol pol Polish
|
||||
pt: por por Portuguese
|
||||
ro: ron rum Romanian
|
||||
ru: rus rus Russian
|
||||
sr: srp srp Serbian
|
||||
sk: slk slo Slovak
|
||||
sl: slv slv Slovenian
|
||||
es: spa spa Spanish
|
||||
sv: swe swe Swedish
|
||||
th: tha tha Thai
|
||||
tr: tur tur Turkish
|
||||
vi: vie vie Vietnamese
|
||||
languages.ui: sq ar hy bg ca hr cs da nl en fi fr qc de el he hi hu is id it ja x-jat ko lv lt mk ms zh tw hk no fa pl pt pb ro ru sr sk sl es mx sv th tr uk vi
|
||||
languages.common: en de fr es pb ru ja zh
|
||||
|
||||
sq: sqi alb sq-SQ Albanian
|
||||
ar: ara ara ar-AR Arabic
|
||||
hy: hye arm hy-HY Armenian
|
||||
bg: bul bul bg-BG Bulgarian
|
||||
ca: cat cat ca-ES Catalan
|
||||
hr: hrv hrv hr-HR Croatian
|
||||
cs: ces cze cs-CZ Czech
|
||||
da: dan dan da-DK Danish
|
||||
nl: nld dut nl-NL Dutch
|
||||
en: eng eng en-US English
|
||||
fi: fin fin fi-FI Finnish
|
||||
fr: fra fre fr-FR French
|
||||
qc: quc caf fr-CA Canadian French Quebec French French (CA)
|
||||
de: deu ger de-DE German
|
||||
el: ell gre el-GR Greek
|
||||
he: heb heb he-IL Hebrew
|
||||
hi: hin hin hi-IN Hindi
|
||||
hu: hun hun hu-HU Hungarian
|
||||
is: isl ice is-IS Icelandic
|
||||
id: ind ind id-ID Indonesian
|
||||
it: ita ita it-IT Italian
|
||||
ja: jpn jpn ja-JP Japanese
|
||||
x-jat: x-jat x-jat x-jat Romanized Japanese
|
||||
ko: kor kor ko-KR Korean
|
||||
lv: lav lav lv-LV Latvian
|
||||
lt: lit lit lt-LT Lithuanian
|
||||
mk: mkd mac mk-MK Macedonian
|
||||
ms: msa may ms-MS Malay
|
||||
zh: zho chi zh-CN Chinese
|
||||
tw: zht zht zh-TW Taiwanese Chinese Chinese (TW)
|
||||
hk: hkg cnt cn-CN Cantonese
|
||||
no: nor nor no-NO Norwegian
|
||||
fa: fas per fa-IR Persian Farsi
|
||||
pl: pol pol pl-PL Polish
|
||||
pt: por por pt-PT Portuguese
|
||||
pb: pob pob pt-BR Brazilian Portuguese Portuguese (BR)
|
||||
ro: ron rum ro-RO Romanian
|
||||
ru: rus rus ru-RU Russian
|
||||
sr: srp srp sr-RS Serbian
|
||||
sk: slk slo sk-SK Slovak
|
||||
sl: slv slv sl-SI Slovenian
|
||||
es: spa spa es-ES Spanish
|
||||
mx: mxn mxn es-MX Mexican Spanish Spanish (MX)
|
||||
sv: swe swe sv-SE Swedish
|
||||
th: tha tha th-TH Thai
|
||||
tr: tur tur tr-TR Turkish
|
||||
uk: ukr ukr uk-UA Ukrainian
|
||||
vi: vie vie vi-VN Vietnamese
|
||||
|
|
|
@ -686,7 +686,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||
|
||||
try {
|
||||
log.fine("Looking up subtitles by hash via " + service.getName());
|
||||
Map<File, List<SubtitleDescriptor>> options = lookupSubtitlesByHash(service, remainingVideos, language.getName(), false, strict);
|
||||
Map<File, List<SubtitleDescriptor>> options = lookupSubtitlesByHash(service, remainingVideos, language.getLocale(), false, strict);
|
||||
Map<File, File> downloads = downloadSubtitleBatch(service, options, output, encoding, format);
|
||||
remainingVideos.removeAll(downloads.keySet());
|
||||
subtitleFiles.addAll(downloads.values());
|
||||
|
@ -702,7 +702,7 @@ public class CmdlineOperations implements CmdlineInterface {
|
|||
|
||||
try {
|
||||
log.fine(format("Looking up subtitles by name via %s", service.getName()));
|
||||
Map<File, List<SubtitleDescriptor>> options = findSubtitlesByName(service, remainingVideos, language.getName(), query, false, strict);
|
||||
Map<File, List<SubtitleDescriptor>> options = findSubtitlesByName(service, remainingVideos, language.getLocale(), query, false, strict);
|
||||
Map<File, File> downloads = downloadSubtitleBatch(service, options, output, encoding, format);
|
||||
remainingVideos.removeAll(downloads.keySet());
|
||||
subtitleFiles.addAll(downloads.values());
|
||||
|
|
After Width: | Height: | Size: 611 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 494 B |
After Width: | Height: | Size: 748 B |
After Width: | Height: | Size: 526 B |
After Width: | Height: | Size: 997 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 461 B |
After Width: | Height: | Size: 870 B |
After Width: | Height: | Size: 399 B |
After Width: | Height: | Size: 574 B |
After Width: | Height: | Size: 471 B |
After Width: | Height: | Size: 705 B |
|
@ -66,8 +66,8 @@ import net.filebot.web.VideoHashSubtitleService;
|
|||
|
||||
public final class SubtitleUtilities {
|
||||
|
||||
public static Map<File, List<SubtitleDescriptor>> lookupSubtitlesByHash(VideoHashSubtitleService service, Collection<File> files, String languageName, boolean addOptions, boolean strict) throws Exception {
|
||||
Map<File, List<SubtitleDescriptor>> options = service.getSubtitleList(files.toArray(new File[files.size()]), languageName);
|
||||
public static Map<File, List<SubtitleDescriptor>> lookupSubtitlesByHash(VideoHashSubtitleService service, Collection<File> files, Locale locale, boolean addOptions, boolean strict) throws Exception {
|
||||
Map<File, List<SubtitleDescriptor>> options = service.getSubtitleList(files.toArray(new File[files.size()]), locale);
|
||||
Map<File, List<SubtitleDescriptor>> results = new LinkedHashMap<File, List<SubtitleDescriptor>>(options.size());
|
||||
|
||||
options.forEach((k, v) -> {
|
||||
|
@ -89,7 +89,7 @@ public final class SubtitleUtilities {
|
|||
return results;
|
||||
}
|
||||
|
||||
public static Map<File, List<SubtitleDescriptor>> findSubtitlesByName(SubtitleProvider service, Collection<File> fileSet, String languageName, String forceQuery, boolean addOptions, boolean strict) throws Exception {
|
||||
public static Map<File, List<SubtitleDescriptor>> findSubtitlesByName(SubtitleProvider service, Collection<File> fileSet, Locale locale, String forceQuery, boolean addOptions, boolean strict) throws Exception {
|
||||
// ignore anything that is not a video
|
||||
fileSet = filter(fileSet, VIDEO_FILES);
|
||||
|
||||
|
@ -182,7 +182,7 @@ public final class SubtitleUtilities {
|
|||
}
|
||||
}
|
||||
|
||||
subtitles.addAll(service.getSubtitleList(it, episodeFilter, languageName));
|
||||
subtitles.addAll(service.getSubtitleList(it, episodeFilter, locale));
|
||||
}
|
||||
|
||||
// allow early abort
|
||||
|
|
|
@ -45,7 +45,10 @@ public class LanguageComboBox extends JComboBox {
|
|||
|
||||
// restore favorite languages
|
||||
for (String favoriteLanguage : persistentFavoriteLanguages) {
|
||||
getModel().favorites().add(getModel().favorites().size(), getLanguage(favoriteLanguage));
|
||||
Language language = getLanguage(favoriteLanguage);
|
||||
if (language != null) {
|
||||
getModel().favorites().add(getModel().favorites().size(), language);
|
||||
}
|
||||
}
|
||||
|
||||
// guess favorite languages
|
||||
|
|
|
@ -22,7 +22,7 @@ public class LanguageComboBoxCellRenderer implements ListCellRenderer {
|
|||
|
||||
private ListCellRenderer base;
|
||||
|
||||
public LanguageComboBoxCellRenderer(final ListCellRenderer base) {
|
||||
public LanguageComboBoxCellRenderer(ListCellRenderer base) {
|
||||
this.base = base;
|
||||
this.padding = new CompoundBorder(padding, ((JLabel) base).getBorder());
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import net.filebot.Language;
|
|||
|
||||
public class LanguageComboBoxModel extends AbstractListModel implements ComboBoxModel {
|
||||
|
||||
public static final Language ALL_LANGUAGES = new Language("undefined", "undefined", "undefined", new String[] { "All Languages" });
|
||||
public static final Language ALL_LANGUAGES = new Language("undefined", "und", "und", "und", new String[] { "All Languages" });
|
||||
|
||||
private Language defaultLanguage;
|
||||
private Language selection;
|
||||
|
|
|
@ -491,13 +491,10 @@ public class RenamePanel extends JComponent {
|
|||
// restore current preference values
|
||||
try {
|
||||
modeCombo.setSelectedItem(persistentPreferredMatchMode.getValue());
|
||||
for (Language language : languages) {
|
||||
if (language.getCode().equals(persistentPreferredLanguage.getValue())) {
|
||||
languageList.setSelectedValue(language, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
orderCombo.setSelectedItem(SortOrder.forName(persistentPreferredEpisodeOrder.getValue()));
|
||||
|
||||
String selectedLanguage = persistentPreferredLanguage.getValue();
|
||||
languages.stream().filter(l -> l.getCode().equals(selectedLanguage)).findFirst().ifPresent(l -> languageList.setSelectedValue(l, true));
|
||||
} catch (Exception e) {
|
||||
debug.log(Level.WARNING, e.getMessage(), e);
|
||||
}
|
||||
|
@ -846,7 +843,7 @@ public class RenamePanel extends JComponent {
|
|||
}
|
||||
|
||||
public Locale getLocale(ActionEvent evt) {
|
||||
return new Locale(persistentPreferredLanguage.getValue());
|
||||
return Language.getLanguage(persistentPreferredLanguage.getValue()).getLocale();
|
||||
}
|
||||
|
||||
private boolean isAutoDetectionEnabled(ActionEvent evt) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.HashMap;
|
|||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
@ -193,9 +194,9 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||
servicePanel.add(component);
|
||||
}
|
||||
|
||||
public void startQuery(String languageName) {
|
||||
final SubtitleMappingTableModel mappingModel = (SubtitleMappingTableModel) subtitleMappingTable.getModel();
|
||||
QueryTask queryTask = new QueryTask(services, mappingModel.getVideoFiles(), languageName, SubtitleAutoMatchDialog.this) {
|
||||
public void startQuery(Locale locale) {
|
||||
SubtitleMappingTableModel mappingModel = (SubtitleMappingTableModel) subtitleMappingTable.getModel();
|
||||
QueryTask queryTask = new QueryTask(services, mappingModel.getVideoFiles(), locale, SubtitleAutoMatchDialog.this) {
|
||||
|
||||
@Override
|
||||
protected void process(List<Map<File, List<SubtitleDescriptorBean>>> sequence) {
|
||||
|
@ -724,13 +725,13 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||
private final Collection<SubtitleServiceBean> services;
|
||||
|
||||
private final Collection<File> remainingVideos;
|
||||
private final String languageName;
|
||||
private final Locale locale;
|
||||
|
||||
public QueryTask(Collection<SubtitleServiceBean> services, Collection<File> videoFiles, String languageName, Component parent) {
|
||||
public QueryTask(Collection<SubtitleServiceBean> services, Collection<File> videoFiles, Locale locale, Component parent) {
|
||||
this.parent = parent;
|
||||
this.services = services;
|
||||
this.remainingVideos = new TreeSet<File>(videoFiles);
|
||||
this.languageName = languageName;
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -746,7 +747,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||
|
||||
try {
|
||||
Map<File, List<SubtitleDescriptorBean>> subtitleSet = new HashMap<File, List<SubtitleDescriptorBean>>();
|
||||
for (final Entry<File, List<SubtitleDescriptor>> result : service.lookupSubtitles(remainingVideos, languageName, parent).entrySet()) {
|
||||
for (final Entry<File, List<SubtitleDescriptor>> result : service.lookupSubtitles(remainingVideos, locale, parent).entrySet()) {
|
||||
Set<SubtitleDescriptor> subtitlesByRelevance = new LinkedHashSet<SubtitleDescriptor>();
|
||||
|
||||
// guess best hash match (default order is open bad due to invalid hash links)
|
||||
|
@ -871,13 +872,13 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||
|
||||
public abstract float getMatchProbabilty(File videoFile, SubtitleDescriptor descriptor);
|
||||
|
||||
protected abstract Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> files, String languageName, Component parent) throws Exception;
|
||||
protected abstract Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> files, Locale locale, Component parent) throws Exception;
|
||||
|
||||
public final Map<File, List<SubtitleDescriptor>> lookupSubtitles(Collection<File> files, String languageName, Component parent) throws Exception {
|
||||
public final Map<File, List<SubtitleDescriptor>> lookupSubtitles(Collection<File> files, Locale locale, Component parent) throws Exception {
|
||||
setState(StateValue.STARTED);
|
||||
|
||||
try {
|
||||
return getSubtitleList(files, languageName, parent);
|
||||
return getSubtitleList(files, locale, parent);
|
||||
} catch (Exception e) {
|
||||
throw (error = e);
|
||||
} finally {
|
||||
|
@ -914,8 +915,8 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> files, String languageName, Component parent) throws Exception {
|
||||
return lookupSubtitlesByHash(service, files, languageName, true, false);
|
||||
protected Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> files, Locale locale, Component parent) throws Exception {
|
||||
return lookupSubtitlesByHash(service, files, locale, true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -939,8 +940,8 @@ class SubtitleAutoMatchDialog extends JDialog {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> fileSet, String languageName, Component parent) throws Exception {
|
||||
return findSubtitlesByName(service, fileSet, languageName, null, true, false);
|
||||
protected Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> fileSet, Locale locale, Component parent) throws Exception {
|
||||
return findSubtitlesByName(service, fileSet, locale, null, true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.io.File;
|
|||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
@ -154,7 +155,7 @@ abstract class SubtitleDropTarget extends JButton {
|
|||
|
||||
public abstract SubtitleProvider[] getSubtitleProviders();
|
||||
|
||||
public abstract String getQueryLanguage();
|
||||
public abstract Locale getQueryLanguage();
|
||||
|
||||
@Override
|
||||
protected DropAction getDropAction(List<File> selection) {
|
||||
|
|
|
@ -144,9 +144,9 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleProvider, Subtitl
|
|||
};
|
||||
|
||||
@Override
|
||||
public String getQueryLanguage() {
|
||||
public Locale getQueryLanguage() {
|
||||
// use currently selected language for drop target
|
||||
return languageComboBox.getModel().getSelectedItem() == ALL_LANGUAGES ? null : languageComboBox.getModel().getSelectedItem().getName();
|
||||
return languageComboBox.getModel().getSelectedItem() == ALL_LANGUAGES ? null : languageComboBox.getModel().getSelectedItem().getLocale();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -267,8 +267,8 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleProvider, Subtitl
|
|||
return provider;
|
||||
}
|
||||
|
||||
public String getLanguageName() {
|
||||
return language == ALL_LANGUAGES ? null : language.getName();
|
||||
public Locale getLanguage() {
|
||||
return language == ALL_LANGUAGES ? null : language.getLocale();
|
||||
}
|
||||
|
||||
public int[][] getEpisodeFilter() {
|
||||
|
@ -296,7 +296,7 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleProvider, Subtitl
|
|||
public Collection<SubtitlePackage> fetch() throws Exception {
|
||||
List<SubtitlePackage> packages = new ArrayList<SubtitlePackage>();
|
||||
|
||||
for (SubtitleDescriptor subtitle : request.getProvider().getSubtitleList(getSearchResult(), request.getEpisodeFilter(), request.getLanguageName())) {
|
||||
for (SubtitleDescriptor subtitle : request.getProvider().getSubtitleList(getSearchResult(), request.getEpisodeFilter(), request.getLanguage())) {
|
||||
packages.add(new SubtitlePackage(request.getProvider(), subtitle));
|
||||
}
|
||||
|
||||
|
@ -305,12 +305,12 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleProvider, Subtitl
|
|||
|
||||
@Override
|
||||
public URI getLink() {
|
||||
return request.getProvider().getSubtitleListLink(getSearchResult(), request.getLanguageName());
|
||||
return request.getProvider().getSubtitleListLink(getSearchResult(), request.getLanguage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Collection<SubtitlePackage> subtitles) {
|
||||
getComponent().setLanguageVisible(request.getLanguageName() == null);
|
||||
getComponent().setLanguageVisible(request.getLanguage() == null);
|
||||
getComponent().getPackageModel().addAll(subtitles);
|
||||
}
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ public class AnidbClient extends AbstractEpisodeListProvider {
|
|||
}).map(it -> it.getKey()).limit(5).collect(Collectors.toList()));
|
||||
|
||||
// parse episode data
|
||||
String animeTitle = selectString("anime/titles/title[@type='official' and @lang='" + locale.getLanguage() + "']", dom);
|
||||
String animeTitle = selectString("anime/titles/title[@type='official' and @lang='" + getLanguageCode(locale) + "']", dom);
|
||||
if (animeTitle == null || animeTitle.length() == 0) {
|
||||
animeTitle = seriesInfo.getName();
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ public class AnidbClient extends AbstractEpisodeListProvider {
|
|||
if (type == 1 || type == 2) {
|
||||
Integer id = Integer.parseInt(getAttribute("id", node));
|
||||
SimpleDate airdate = SimpleDate.parse(getTextContent("airdate", node));
|
||||
String title = selectString(".//title[@lang='" + locale.getLanguage() + "']", node);
|
||||
String title = selectString(".//title[@lang='" + getLanguageCode(locale) + "']", node);
|
||||
if (title.isEmpty()) { // English language fall-back
|
||||
title = selectString(".//title[@lang='en']", node);
|
||||
}
|
||||
|
@ -179,6 +179,26 @@ public class AnidbClient extends AbstractEpisodeListProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map locale to AniDB language code
|
||||
*/
|
||||
public String getLanguageCode(Locale locale) {
|
||||
// Note: ISO 639 is not a stable standard— some languages' codes have changed.
|
||||
// Locale's constructor recognizes both the new and the old codes for the languages whose codes have changed,
|
||||
// but this function always returns the old code.
|
||||
String code = locale.getLanguage();
|
||||
|
||||
// Java language code => AniDB language code
|
||||
switch (code) {
|
||||
case "iw":
|
||||
return "he"; // Hebrew
|
||||
case "in":
|
||||
return "id"; // Indonesian
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is overridden in {@link net.filebot.WebServices.AnidbClientWithLocalSearch} to fetch the Anime Index from our own host and not anidb.net
|
||||
*/
|
||||
|
|
|
@ -17,7 +17,6 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
@ -117,15 +116,15 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
});
|
||||
}
|
||||
|
||||
public List<SubtitleDescriptor> getSubtitleList(SubtitleSearchResult searchResult, String languageName) throws Exception {
|
||||
return getSubtitleList(searchResult, -1, -1, languageName);
|
||||
public List<SubtitleDescriptor> getSubtitleList(SubtitleSearchResult searchResult, Locale locale) throws Exception {
|
||||
return getSubtitleList(searchResult, -1, -1, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SubtitleDescriptor> getSubtitleList(SubtitleSearchResult searchResult, int[][] episodeFilter, String languageName) throws Exception {
|
||||
public List<SubtitleDescriptor> getSubtitleList(SubtitleSearchResult searchResult, int[][] episodeFilter, Locale locale) throws Exception {
|
||||
// no filter
|
||||
if (episodeFilter == null || episodeFilter.length == 0) {
|
||||
return getSubtitleList(searchResult, -1, -1, languageName);
|
||||
return getSubtitleList(searchResult, -1, -1, locale);
|
||||
}
|
||||
|
||||
int[] seasons = stream(episodeFilter).mapToInt(ii -> ii[0]).filter(i -> i >= 0).sorted().distinct().toArray();
|
||||
|
@ -133,21 +132,21 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
|
||||
// no filter
|
||||
if (seasons.length == 0 && episodes.length == 0) {
|
||||
return getSubtitleList(searchResult, -1, -1, languageName);
|
||||
return getSubtitleList(searchResult, -1, -1, locale);
|
||||
}
|
||||
|
||||
// episode filter
|
||||
if (seasons.length == 1 && episodes.length == 1) {
|
||||
return getSubtitleList(searchResult, seasons[0], episodes[0], languageName);
|
||||
return getSubtitleList(searchResult, seasons[0], episodes[0], locale);
|
||||
}
|
||||
|
||||
// season filter
|
||||
if (seasons.length > 0 && episodes.length == 0) {
|
||||
return stream(seasons).boxed().flatMap(s -> {
|
||||
try {
|
||||
return getSubtitleList(searchResult, s, -1, languageName).stream();
|
||||
return getSubtitleList(searchResult, s, -1, locale).stream();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(String.format("Failed to retrieve subtitle list for season: %s S%02d [%s]", searchResult, s, languageName), e);
|
||||
throw new RuntimeException(String.format("Failed to retrieve subtitle list for season: %s S%02d [%s]", searchResult, s, locale), e);
|
||||
}
|
||||
}).distinct().collect(toList());
|
||||
}
|
||||
|
@ -155,15 +154,15 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
// multi-episode filter
|
||||
return stream(episodeFilter).flatMap(ii -> {
|
||||
try {
|
||||
return getSubtitleList(searchResult, ii[0], ii[1], languageName).stream();
|
||||
return getSubtitleList(searchResult, ii[0], ii[1], locale).stream();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(String.format("Failed to retrieve subtitle list for episode: %s %s [%s]", searchResult, asList(ii), languageName), e);
|
||||
throw new RuntimeException(String.format("Failed to retrieve subtitle list for episode: %s %s [%s]", searchResult, asList(ii), locale), e);
|
||||
}
|
||||
}).distinct().collect(toList());
|
||||
}
|
||||
|
||||
public synchronized List<SubtitleDescriptor> getSubtitleList(SubtitleSearchResult searchResult, int season, int episode, String languageName) throws Exception {
|
||||
Query query = Query.forImdbId(searchResult.getImdbId(), season, episode, getLanguageFilter(languageName));
|
||||
public synchronized List<SubtitleDescriptor> getSubtitleList(SubtitleSearchResult searchResult, int season, int episode, Locale locale) throws Exception {
|
||||
Query query = Query.forImdbId(searchResult.getImdbId(), season, episode, getLanguageFilter(locale));
|
||||
|
||||
// require login
|
||||
return getSubtitlesCache().computeIfAbsent(query, it -> {
|
||||
|
@ -173,13 +172,13 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<File, List<SubtitleDescriptor>> getSubtitleList(File[] files, String languageName) throws Exception {
|
||||
public Map<File, List<SubtitleDescriptor>> getSubtitleList(File[] files, Locale locale) throws Exception {
|
||||
Map<File, List<SubtitleDescriptor>> results = new HashMap<File, List<SubtitleDescriptor>>(files.length);
|
||||
Set<File> remainingFiles = new HashSet<File>(asList(files));
|
||||
|
||||
// lookup subtitles by hash
|
||||
if (remainingFiles.size() > 0) {
|
||||
results.putAll(getSubtitleListByHash(remainingFiles.toArray(new File[0]), languageName));
|
||||
results.putAll(getSubtitleListByHash(remainingFiles.toArray(new File[0]), locale));
|
||||
}
|
||||
|
||||
// remove files for which subtitles have already been found
|
||||
|
@ -191,7 +190,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
|
||||
// lookup subtitles by tag
|
||||
if (remainingFiles.size() > 0) {
|
||||
results.putAll(getSubtitleListByTag(remainingFiles.toArray(new File[0]), languageName));
|
||||
results.putAll(getSubtitleListByTag(remainingFiles.toArray(new File[0]), locale));
|
||||
}
|
||||
|
||||
return results;
|
||||
|
@ -213,12 +212,12 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
return results;
|
||||
}
|
||||
|
||||
public Map<File, List<SubtitleDescriptor>> getSubtitleListByHash(File[] files, String language) throws Exception {
|
||||
public Map<File, List<SubtitleDescriptor>> getSubtitleListByHash(File[] files, Locale locale) throws Exception {
|
||||
return getSubtitleList(files, f -> {
|
||||
if (f.length() > HASH_CHUNK_SIZE) {
|
||||
try {
|
||||
String hash = computeHash(f);
|
||||
return Query.forHash(hash, f.length(), getLanguageFilter(language));
|
||||
return Query.forHash(hash, f.length(), getLanguageFilter(locale));
|
||||
} catch (Exception e) {
|
||||
debug.log(Level.SEVERE, "Failed to compute hash", e);
|
||||
}
|
||||
|
@ -227,7 +226,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
try {
|
||||
Map<?, ?> json = asMap(readJson(readTextFile(f)));
|
||||
if (json != null) {
|
||||
return Query.forHash(json.get("hash").toString(), Long.parseLong(json.get("size").toString()), getLanguageFilter(language));
|
||||
return Query.forHash(json.get("hash").toString(), Long.parseLong(json.get("size").toString()), getLanguageFilter(locale));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
debug.finest("Ignore sample file: " + f);
|
||||
|
@ -237,10 +236,10 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
});
|
||||
}
|
||||
|
||||
public Map<File, List<SubtitleDescriptor>> getSubtitleListByTag(File[] files, String language) throws Exception {
|
||||
public Map<File, List<SubtitleDescriptor>> getSubtitleListByTag(File[] files, Locale locale) throws Exception {
|
||||
return getSubtitleList(files, f -> {
|
||||
String tag = getNameWithoutExtension(f.getName());
|
||||
return Query.forTag(tag, getLanguageFilter(language));
|
||||
return Query.forTag(tag, getLanguageFilter(locale));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -279,7 +278,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
}
|
||||
|
||||
@Override
|
||||
public synchronized void uploadSubtitle(Object identity, Locale language, File[] videoFile, File[] subtitleFile) throws Exception {
|
||||
public synchronized void uploadSubtitle(Object identity, Locale locale, File[] videoFile, File[] subtitleFile) throws Exception {
|
||||
int imdbid = -1;
|
||||
try {
|
||||
imdbid = ((Movie) identity).getImdbId();
|
||||
|
@ -287,7 +286,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
throw new IllegalArgumentException("Illegal Movie ID: " + identity);
|
||||
}
|
||||
|
||||
String subLanguageID = getSubLanguageID(language.getDisplayName(Locale.ENGLISH), false);
|
||||
String subLanguageID = getSubLanguageID(locale);
|
||||
|
||||
BaseInfo info = new BaseInfo();
|
||||
info.setIDMovieImdb(imdbid);
|
||||
|
@ -368,19 +367,8 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
}
|
||||
|
||||
@Override
|
||||
public URI getSubtitleListLink(SubtitleSearchResult searchResult, String languageName) {
|
||||
Movie movie = searchResult;
|
||||
String sublanguageid = "all";
|
||||
|
||||
if (languageName != null) {
|
||||
try {
|
||||
sublanguageid = getSubLanguageID(languageName, true);
|
||||
} catch (Exception e) {
|
||||
debug.log(Level.WARNING, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return URI.create(String.format("http://www.opensubtitles.org/en/search/imdbid-%d/sublanguageid-%s", movie.getImdbId(), sublanguageid));
|
||||
public URI getSubtitleListLink(SubtitleSearchResult searchResult, Locale locale) {
|
||||
return URI.create(String.format("http://www.opensubtitles.org/en/search/imdbid-%d/sublanguageid-%s", searchResult.getImdbId(), getSubLanguageID(locale)));
|
||||
}
|
||||
|
||||
public synchronized Locale detectLanguage(byte[] data) throws Exception {
|
||||
|
@ -442,13 +430,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
|
||||
// try to get language map from cache
|
||||
Cache cache = Cache.getCache(getName() + "_languages", CacheType.Persistent);
|
||||
Map<?, ?> m = (Map<?, ?>) cache.computeIfAbsent("subLanguageMap", it -> {
|
||||
try {
|
||||
return xmlrpc.getSubLanguages();
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Failed to retrieve subtitle language map", e);
|
||||
}
|
||||
});
|
||||
Map<?, ?> m = (Map<?, ?>) cache.computeIfAbsent("subLanguageMap", k -> xmlrpc.getSubLanguages());
|
||||
|
||||
// add additional language aliases for improved compatibility
|
||||
Map<String, Locale> additionalLanguageMappings = MediaDetection.releaseInfo.getLanguageMap(Locale.ENGLISH);
|
||||
|
@ -456,13 +438,13 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
m.forEach((k, v) -> {
|
||||
// map id by name
|
||||
String subLanguageID = k.toString().toLowerCase();
|
||||
String subLanguageName = v.toString().toLowerCase();
|
||||
String languageCode = v.toString().toLowerCase();
|
||||
|
||||
subLanguageMap.put(subLanguageName, subLanguageID);
|
||||
subLanguageMap.put(languageCode, subLanguageID);
|
||||
subLanguageMap.put(subLanguageID, subLanguageID); // add reverse mapping as well for improved compatibility
|
||||
|
||||
// add additional language aliases for improved compatibility
|
||||
for (String key : new String[] { subLanguageID, subLanguageName }) {
|
||||
for (String key : new String[] { subLanguageID, languageCode }) {
|
||||
Locale locale = additionalLanguageMappings.get(key);
|
||||
if (locale != null) {
|
||||
for (String identifier : asList(locale.getLanguage(), locale.getISO3Language(), locale.getDisplayLanguage(Locale.ENGLISH))) {
|
||||
|
@ -475,38 +457,34 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
|||
});
|
||||
|
||||
// some additional special handling
|
||||
subLanguageMap.put("brazilian", "pob");
|
||||
subLanguageMap.put("chinese", "chi,zht,zhe"); // Chinese (Simplified) / Chinese (Traditional) / Chinese (bilingual)
|
||||
subLanguageMap.put("pb", "pob");
|
||||
subLanguageMap.put("zh", "chi"); // Chinese (Simplified)
|
||||
subLanguageMap.put("tw", "zht"); // Chinese (Traditional)
|
||||
|
||||
return subLanguageMap;
|
||||
}
|
||||
|
||||
protected String[] getLanguageFilter(String language) {
|
||||
return language == null || language.isEmpty() ? new String[0] : new String[] { getSubLanguageID(language, true) };
|
||||
protected String[] getLanguageFilter(Locale locale) {
|
||||
return locale == null || locale.getLanguage().isEmpty() ? new String[0] : new String[] { getSubLanguageID(locale) };
|
||||
}
|
||||
|
||||
protected String getSubLanguageID(String languageName, boolean allowMultiLanguageID) {
|
||||
protected String getSubLanguageID(Locale locale) {
|
||||
if (locale == null || locale.getLanguage().isEmpty()) {
|
||||
return "all";
|
||||
}
|
||||
|
||||
String subLanguageID = null;
|
||||
try {
|
||||
String subLanguageID = getSubLanguageMap().get(languageName.toLowerCase());
|
||||
if (subLanguageID == null) {
|
||||
throw new IllegalArgumentException(String.format("SubLanguageID for '%s' not found", languageName));
|
||||
}
|
||||
if (!allowMultiLanguageID && subLanguageID.contains(",")) {
|
||||
subLanguageID = subLanguageID.substring(0, subLanguageID.indexOf(","));
|
||||
}
|
||||
return subLanguageID;
|
||||
subLanguageID = getSubLanguageMap().get(locale.getLanguage());
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected String getLanguageName(String subLanguageID) throws Exception {
|
||||
for (Entry<String, String> it : getSubLanguageMap().entrySet()) {
|
||||
if (it.getValue().equals(subLanguageID.toLowerCase()))
|
||||
return it.getKey();
|
||||
throw new IllegalStateException("Failed to retrieve subtitle language map", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
if (subLanguageID == null) {
|
||||
throw new IllegalArgumentException("SubLanguageID not found: " + locale);
|
||||
}
|
||||
|
||||
return subLanguageID;
|
||||
}
|
||||
|
||||
public Cache getCache(String section) {
|
||||
|
|
|
@ -318,7 +318,7 @@ public class OpenSubtitlesXmlRpc {
|
|||
Map<String, String> subLanguageMap = new HashMap<String, String>();
|
||||
|
||||
for (Map<String, String> language : response.get("data")) {
|
||||
subLanguageMap.put(language.get("SubLanguageID"), language.get("LanguageName"));
|
||||
subLanguageMap.put(language.get("SubLanguageID"), language.get("ISO639"));
|
||||
}
|
||||
|
||||
return subLanguageMap;
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
|
@ -32,9 +33,6 @@ import net.filebot.ResourceManager;
|
|||
|
||||
public class ShooterSubtitles implements VideoHashSubtitleService {
|
||||
|
||||
private static final String LANGUAGE_CHINESE = "Chinese";
|
||||
private static final String LANGUAGE_ENGLISH = "English";
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "射手网";
|
||||
|
@ -60,10 +58,10 @@ public class ShooterSubtitles implements VideoHashSubtitleService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<File, List<SubtitleDescriptor>> getSubtitleList(File[] videoFiles, String languageName) throws Exception {
|
||||
public Map<File, List<SubtitleDescriptor>> getSubtitleList(File[] videoFiles, Locale locale) throws Exception {
|
||||
Map<File, List<SubtitleDescriptor>> result = new HashMap<File, List<SubtitleDescriptor>>();
|
||||
for (File it : videoFiles) {
|
||||
result.put(it, getSubtitleList(it, languageName));
|
||||
result.put(it, getSubtitleList(it, locale));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -79,10 +77,11 @@ public class ShooterSubtitles implements VideoHashSubtitleService {
|
|||
/**
|
||||
* @see https://docs.google.com/document/d/1ufdzy6jbornkXxsD-OGl3kgWa4P9WO5NZb6_QYZiGI0/preview
|
||||
*/
|
||||
public synchronized List<SubtitleDescriptor> getSubtitleList(File file, String languageName) throws Exception {
|
||||
if (!LANGUAGE_CHINESE.equals(languageName) && !LANGUAGE_ENGLISH.equals(languageName)) {
|
||||
throw new IllegalArgumentException("Language not supported: " + languageName);
|
||||
public synchronized List<SubtitleDescriptor> getSubtitleList(File file, Locale locale) throws Exception {
|
||||
if (Stream.of(Locale.CHINESE, Locale.ENGLISH).noneMatch(l -> l.getLanguage().equals(locale.getLanguage()))) {
|
||||
throw new IllegalArgumentException("Language not supported: " + locale);
|
||||
}
|
||||
|
||||
if (file.length() < 8192) {
|
||||
return emptyList();
|
||||
}
|
||||
|
@ -92,7 +91,7 @@ public class ShooterSubtitles implements VideoHashSubtitleService {
|
|||
param.put("filehash", computeFileHash(file));
|
||||
param.put("pathinfo", file.getPath());
|
||||
param.put("format", "json");
|
||||
param.put("lang", LANGUAGE_CHINESE.equals(languageName) ? "Chn" : "Eng");
|
||||
param.put("lang", Locale.CHINESE.getLanguage().equals(locale.getLanguage()) ? "Chn" : "Eng");
|
||||
|
||||
// use the first best option and ignore the rest
|
||||
return getCache().castList(SubtitleDescriptor.class).computeIfAbsent(param.toString(), it -> {
|
||||
|
@ -108,7 +107,7 @@ public class ShooterSubtitles implements VideoHashSubtitleService {
|
|||
return streamJsonObjects(response).flatMap(n -> streamJsonObjects(n, "Files")).map(f -> {
|
||||
String type = getString(f, "Ext");
|
||||
String link = getString(f, "Link");
|
||||
return new ShooterSubtitleDescriptor(name, type, link, languageName);
|
||||
return new ShooterSubtitleDescriptor(name, type, link, locale.getDisplayLanguage(Locale.ENGLISH));
|
||||
}).limit(1).collect(toList());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package net.filebot.web;
|
|||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public interface SubtitleProvider extends Datasource {
|
||||
|
||||
|
@ -9,9 +10,9 @@ public interface SubtitleProvider extends Datasource {
|
|||
|
||||
public List<SubtitleSearchResult> guess(String tag) throws Exception;
|
||||
|
||||
public List<SubtitleDescriptor> getSubtitleList(SubtitleSearchResult searchResult, int[][] episodeFilter, String languageName) throws Exception;
|
||||
public List<SubtitleDescriptor> getSubtitleList(SubtitleSearchResult searchResult, int[][] episodeFilter, Locale locale) throws Exception;
|
||||
|
||||
public URI getSubtitleListLink(SubtitleSearchResult searchResult, String languageName);
|
||||
public URI getSubtitleListLink(SubtitleSearchResult searchResult, Locale locale);
|
||||
|
||||
public URI getLink();
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import javax.swing.Icon;
|
|||
import net.filebot.Cache;
|
||||
import net.filebot.CacheType;
|
||||
import net.filebot.CachedResource.Transform;
|
||||
import net.filebot.Language;
|
||||
import net.filebot.ResourceManager;
|
||||
|
||||
public class TMDbClient implements MovieIdentificationService, ArtworkProvider {
|
||||
|
@ -367,25 +366,26 @@ public class TMDbClient implements MovieIdentificationService, ArtworkProvider {
|
|||
protected Object request(String resource, Map<String, Object> parameters, Locale locale) throws Exception {
|
||||
// default parameters
|
||||
String key = parameters.isEmpty() ? resource : resource + '?' + encodeParameters(parameters, true);
|
||||
String cacheName = locale.getLanguage().isEmpty() ? getName() : getName() + "_" + locale;
|
||||
String language = getLanguageCode(locale);
|
||||
String cacheName = language == null ? getName() : getName() + "_" + language;
|
||||
|
||||
Cache cache = Cache.getCache(cacheName, CacheType.Monthly);
|
||||
Object json = cache.json(key, k -> getResource(k, locale)).fetch(withPermit(fetchIfNoneMatch(url -> key, cache), r -> REQUEST_LIMIT.acquirePermit())).expire(Cache.ONE_WEEK).get();
|
||||
Object json = cache.json(key, k -> getResource(k, language)).fetch(withPermit(fetchIfNoneMatch(url -> key, cache), r -> REQUEST_LIMIT.acquirePermit())).expire(Cache.ONE_WEEK).get();
|
||||
|
||||
if (asMap(json).isEmpty()) {
|
||||
throw new FileNotFoundException(String.format("Resource is empty: %s => %s", json, getResource(key, locale)));
|
||||
throw new FileNotFoundException(String.format("Resource is empty: %s => %s", json, getResource(key, language)));
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
protected URL getResource(String path, Locale locale) throws Exception {
|
||||
protected URL getResource(String path, String language) throws Exception {
|
||||
StringBuilder file = new StringBuilder();
|
||||
file.append('/').append(version);
|
||||
file.append('/').append(path);
|
||||
file.append(path.lastIndexOf('?') < 0 ? '?' : '&');
|
||||
|
||||
if (locale.getLanguage().length() > 0) {
|
||||
file.append("language=").append(getLanguageCode(locale)).append('&');
|
||||
if (language != null) {
|
||||
file.append("language=").append(language).append('&');
|
||||
}
|
||||
file.append("api_key=").append(apikey);
|
||||
|
||||
|
@ -402,12 +402,7 @@ public class TMDbClient implements MovieIdentificationService, ArtworkProvider {
|
|||
return locale.getLanguage(); // e.g. en
|
||||
}
|
||||
|
||||
Language lang = Language.getLanguage(locale);
|
||||
if (lang != null) {
|
||||
return lang.getISO2();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Illegal language code: " + language);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static enum MovieProperty {
|
||||
|
|
|
@ -63,24 +63,22 @@ public class TheTVDBClientV1 extends AbstractEpisodeListProvider implements Artw
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map locale to TheTVDB language code
|
||||
*/
|
||||
public String getLanguageCode(Locale locale) {
|
||||
// Note: ISO 639 is not a stable standard— some languages' codes have changed.
|
||||
// Locale's constructor recognizes both the new and the old codes for the languages whose codes have changed,
|
||||
// but this function always returns the old code.
|
||||
String code = locale.getLanguage();
|
||||
|
||||
// sanity check
|
||||
if (code.length() != 2) {
|
||||
// see http://thetvdb.com/api/BA864DEE427E384A/languages.xml
|
||||
throw new IllegalArgumentException("Expecting 2-letter language code: " + code);
|
||||
}
|
||||
|
||||
// Java language code => TheTVDB language code
|
||||
if (code.equals("iw")) // Hebrew
|
||||
return "he";
|
||||
if (code.equals("hi")) // Hungarian
|
||||
return "hu";
|
||||
if (code.equals("in")) // Indonesian
|
||||
return "id";
|
||||
if (code.equals("ro")) // Russian
|
||||
return "ru";
|
||||
switch (code) {
|
||||
case "iw":
|
||||
return "he"; // Hebrew
|
||||
case "in":
|
||||
return "id"; // Indonesian
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
@ -203,13 +201,13 @@ public class TheTVDBClientV1 extends AbstractEpisodeListProvider implements Artw
|
|||
return new SeriesData(seriesInfo, episodes);
|
||||
}
|
||||
|
||||
public SearchResult lookupByID(int id, Locale language) throws Exception {
|
||||
public SearchResult lookupByID(int id, Locale locale) throws Exception {
|
||||
if (id <= 0) {
|
||||
throw new IllegalArgumentException("Illegal TheTVDB ID: " + id);
|
||||
}
|
||||
|
||||
return getLookupCache("id", language).computeIfAbsent(id, it -> {
|
||||
Document dom = getXmlResource(MirrorType.XML, "series/" + id + "/all/" + getLanguageCode(language) + ".xml");
|
||||
return getLookupCache("id", locale).computeIfAbsent(id, it -> {
|
||||
Document dom = getXmlResource(MirrorType.XML, "series/" + id + "/all/" + getLanguageCode(locale) + ".xml");
|
||||
String name = selectString("//SeriesName", dom);
|
||||
|
||||
return new SearchResult(id, name);
|
||||
|
|
|
@ -8,7 +8,7 @@ import java.util.Map;
|
|||
|
||||
public interface VideoHashSubtitleService extends Datasource {
|
||||
|
||||
public Map<File, List<SubtitleDescriptor>> getSubtitleList(File[] videoFiles, String languageName) throws Exception;
|
||||
public Map<File, List<SubtitleDescriptor>> getSubtitleList(File[] videoFiles, Locale locale) throws Exception;
|
||||
|
||||
public URI getLink();
|
||||
|
||||
|
|