* created SubtitleDescriptor/Client class hierarchy

* refactoring
This commit is contained in:
Reinhard Pointner 2008-03-31 22:53:54 +00:00
parent aa7a236b6b
commit b9906b6a0d
21 changed files with 613 additions and 1151 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -18,6 +18,9 @@ public class Settings {
private static Settings settings = new Settings(); private static Settings settings = new Settings();
public static final String NAME = "FileBot";
public static final String VERSION = "2.0";
public static final String ROOT = "filebot"; public static final String ROOT = "filebot";
public static final String SELECTED_PANEL = "panel"; public static final String SELECTED_PANEL = "panel";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 643 B

View File

@ -1,5 +1,5 @@
package net.sourceforge.filebot.ui.panel.search; package net.sourceforge.filebot.ui;
import java.awt.BorderLayout; import java.awt.BorderLayout;
@ -19,16 +19,23 @@ import javax.swing.SwingUtilities;
import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.filebot.resources.ResourceManager;
class TabComponentWithClose extends JPanel { public class FileBotTabComponent extends JPanel {
private JLabel label; private final JLabel label;
public TabComponentWithClose() { public FileBotTabComponent() {
this("", null);
}
public FileBotTabComponent(String title, Icon icon) {
super(new BorderLayout(0, 0)); super(new BorderLayout(0, 0));
setOpaque(false); setOpaque(false);
label = new JLabel("", SwingConstants.LEFT); label = new JLabel(title, SwingConstants.LEFT);
label.setIcon(icon);
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 2)); label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 2));
add(label, BorderLayout.CENTER); add(label, BorderLayout.CENTER);
@ -52,8 +59,8 @@ class TabComponentWithClose extends JPanel {
public void close() { public void close() {
JTabbedPane tabs = (JTabbedPane) SwingUtilities.getAncestorOfClass(JTabbedPane.class, TabComponentWithClose.this); JTabbedPane tabs = (JTabbedPane) SwingUtilities.getAncestorOfClass(JTabbedPane.class, FileBotTabComponent.this);
tabs.removeTabAt(tabs.indexOfTabComponent(TabComponentWithClose.this)); tabs.removeTabAt(tabs.indexOfTabComponent(FileBotTabComponent.this));
} }
private final AbstractAction tabCloseAction = new AbstractAction(null, null) { private final AbstractAction tabCloseAction = new AbstractAction(null, null) {

View File

@ -40,7 +40,7 @@ public class FileBotWindow extends JFrame implements ListSelectionListener {
public FileBotWindow() { public FileBotWindow() {
super("FileBot"); super(Settings.NAME);
setLocationByPlatform(true); setLocationByPlatform(true);
setDefaultCloseOperation(EXIT_ON_CLOSE); setDefaultCloseOperation(EXIT_ON_CLOSE);

View File

@ -0,0 +1,85 @@
package net.sourceforge.filebot.ui;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.net.URL;
import java.text.NumberFormat;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import net.sourceforge.tuned.ui.HyperlinkLabel;
public class HistoryPanel extends JPanel {
private JPanel grid = new JPanel(new GridLayout(0, 3, 15, 10));
public HistoryPanel(String titleHeader, String infoHeader) {
setLayout(new FlowLayout(FlowLayout.CENTER));
JScrollPane scrollPane = new JScrollPane(grid, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
add(grid);
setBackground(Color.WHITE);
setOpaque(true);
grid.setOpaque(false);
JLabel titleLabel = new JLabel(titleHeader);
JLabel infoLabel = new JLabel(infoHeader);
JLabel durationLabel = new JLabel("Duration");
Font font = titleLabel.getFont().deriveFont(Font.BOLD);
titleLabel.setHorizontalAlignment(SwingConstants.CENTER);
infoLabel.setHorizontalAlignment(SwingConstants.CENTER);
durationLabel.setHorizontalAlignment(SwingConstants.RIGHT);
titleLabel.setFont(font);
infoLabel.setFont(font);
durationLabel.setFont(font);
grid.add(titleLabel);
grid.add(infoLabel);
grid.add(durationLabel);
}
private final Border infoBorder = BorderFactory.createEmptyBorder(0, 0, 0, 10);
public void add(String title, URL url, String info, long duration, Icon icon) {
String durationString = NumberFormat.getInstance().format(duration) + " ms";
JLabel titleLabel = (url != null) ? new HyperlinkLabel(title, url) : new JLabel(title);
JLabel infoLabel = new JLabel(info);
JLabel durationLabel = new JLabel(durationString);
infoLabel.setBorder(infoBorder);
titleLabel.setHorizontalAlignment(SwingConstants.LEFT);
infoLabel.setHorizontalAlignment(SwingConstants.RIGHT);
durationLabel.setHorizontalAlignment(SwingConstants.RIGHT);
titleLabel.setIcon(icon);
titleLabel.setIconTextGap(7);
grid.add(titleLabel);
grid.add(infoLabel);
grid.add(durationLabel);
}
}

View File

@ -6,11 +6,12 @@ import javax.swing.ImageIcon;
import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.filebot.ui.FileBotList; import net.sourceforge.filebot.ui.FileBotList;
import net.sourceforge.filebot.ui.FileBotTabComponent;
class EpisodeListPanel extends FileBotList { public class EpisodeListPanel extends FileBotList {
private final TabComponentWithClose tabComponent = new TabComponentWithClose(); private final FileBotTabComponent tabComponent = new FileBotTabComponent();
private ImageIcon icon; private ImageIcon icon;
@ -22,7 +23,7 @@ class EpisodeListPanel extends FileBotList {
} }
public TabComponentWithClose getTabComponent() { public FileBotTabComponent getTabComponent() {
return tabComponent; return tabComponent;
} }

View File

@ -1,86 +0,0 @@
package net.sourceforge.filebot.ui.panel.search;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.net.URL;
import java.text.NumberFormat;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import net.sourceforge.tuned.ui.HyperlinkLabel;
class HistoryPanel extends JPanel {
private JPanel grid = new JPanel(new GridLayout(0, 3, 15, 10));
public HistoryPanel() {
setLayout(new FlowLayout(FlowLayout.CENTER));
add(grid);
setBackground(Color.WHITE);
setOpaque(true);
grid.setOpaque(false);
JLabel linkLabel = new JLabel("Show");
JLabel numberLabel = new JLabel("Number of Episodes");
JLabel durationLabel = new JLabel("Duration");
Font font = linkLabel.getFont().deriveFont(Font.BOLD);
linkLabel.setHorizontalAlignment(SwingConstants.CENTER);
numberLabel.setHorizontalAlignment(SwingConstants.CENTER);
durationLabel.setHorizontalAlignment(SwingConstants.RIGHT);
linkLabel.setFont(font);
numberLabel.setFont(font);
durationLabel.setFont(font);
grid.add(linkLabel);
grid.add(numberLabel);
grid.add(durationLabel);
}
private Border numberBorder = BorderFactory.createEmptyBorder(0, 0, 0, 10);
public void add(String show, URL url, int number, long duration, Icon searchEngineIcon) {
String numberString = null;
if (number > 0)
numberString = Integer.toString(number) + " episodes";
else
numberString = "No episodes found";
String durationString = NumberFormat.getInstance().format(duration) + " ms";
JLabel linkLabel = new HyperlinkLabel(show, url);
JLabel numberLabel = new JLabel(numberString);
JLabel durationLabel = new JLabel(durationString);
numberLabel.setBorder(numberBorder);
linkLabel.setHorizontalAlignment(SwingConstants.LEFT);
numberLabel.setHorizontalAlignment(SwingConstants.RIGHT);
durationLabel.setHorizontalAlignment(SwingConstants.RIGHT);
linkLabel.setIcon(searchEngineIcon);
linkLabel.setIconTextGap(7);
grid.add(linkLabel);
grid.add(numberLabel);
grid.add(durationLabel);
}
}

View File

@ -21,11 +21,9 @@ import javax.swing.BorderFactory;
import javax.swing.Box; import javax.swing.Box;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner; import javax.swing.JSpinner;
import javax.swing.JTabbedPane; import javax.swing.JTabbedPane;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.SpinnerNumberModel; import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
@ -36,6 +34,7 @@ import net.sourceforge.filebot.FileBotUtil;
import net.sourceforge.filebot.Settings; import net.sourceforge.filebot.Settings;
import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.filebot.ui.FileBotPanel; import net.sourceforge.filebot.ui.FileBotPanel;
import net.sourceforge.filebot.ui.HistoryPanel;
import net.sourceforge.filebot.ui.MessageManager; import net.sourceforge.filebot.ui.MessageManager;
import net.sourceforge.filebot.ui.SelectDialog; import net.sourceforge.filebot.ui.SelectDialog;
import net.sourceforge.filebot.ui.transfer.SaveAction; import net.sourceforge.filebot.ui.transfer.SaveAction;
@ -52,7 +51,7 @@ public class SearchPanel extends FileBotPanel {
private JTabbedPane tabbedPane = new JTabbedPane(SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT); private JTabbedPane tabbedPane = new JTabbedPane(SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
private HistoryPanel history = new HistoryPanel(); private HistoryPanel historyPanel = new HistoryPanel("Show", "Number of Episodes");
private SpinnerNumberModel seasonSpinnerModel = new SpinnerNumberModel(SeasonSpinnerEditor.ALL_SEASONS, SeasonSpinnerEditor.ALL_SEASONS, Integer.MAX_VALUE, 1); private SpinnerNumberModel seasonSpinnerModel = new SpinnerNumberModel(SeasonSpinnerEditor.ALL_SEASONS, SeasonSpinnerEditor.ALL_SEASONS, Integer.MAX_VALUE, 1);
@ -60,8 +59,6 @@ public class SearchPanel extends FileBotPanel {
private TextCompletion searchFieldCompletion; private TextCompletion searchFieldCompletion;
private JSpinner seasonSpinner;
public SearchPanel() { public SearchPanel() {
super("Search", ResourceManager.getIcon("panel.search")); super("Search", ResourceManager.getIcon("panel.search"));
@ -85,7 +82,7 @@ public class SearchPanel extends FileBotPanel {
Box searchBox = Box.createHorizontalBox(); Box searchBox = Box.createHorizontalBox();
searchBox.setBorder(new EmptyBorder(5, 5, 5, 5)); searchBox.setBorder(new EmptyBorder(5, 5, 5, 5));
seasonSpinner = new JSpinner(seasonSpinnerModel); JSpinner seasonSpinner = new JSpinner(seasonSpinnerModel);
seasonSpinner.setEditor(new SeasonSpinnerEditor(seasonSpinner)); seasonSpinner.setEditor(new SeasonSpinnerEditor(seasonSpinner));
searchField.setMaximumSize(searchField.getPreferredSize()); searchField.setMaximumSize(searchField.getPreferredSize());
seasonSpinner.setMaximumSize(seasonSpinner.getPreferredSize()); seasonSpinner.setMaximumSize(seasonSpinner.getPreferredSize());
@ -110,11 +107,7 @@ public class SearchPanel extends FileBotPanel {
centerPanel.add(tabbedPane, BorderLayout.CENTER); centerPanel.add(tabbedPane, BorderLayout.CENTER);
centerPanel.add(buttonBox, BorderLayout.SOUTH); centerPanel.add(buttonBox, BorderLayout.SOUTH);
JScrollPane sp = new JScrollPane(history); tabbedPane.addTab("History", ResourceManager.getIcon("tab.history"), historyPanel);
sp.setBorder(BorderFactory.createEmptyBorder());
sp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
tabbedPane.addTab("History", ResourceManager.getIcon("tab.history"), sp);
mainPanel.add(searchBox, BorderLayout.NORTH); mainPanel.add(searchBox, BorderLayout.NORTH);
mainPanel.add(centerPanel, BorderLayout.CENTER); mainPanel.add(centerPanel, BorderLayout.CENTER);
@ -124,8 +117,8 @@ public class SearchPanel extends FileBotPanel {
FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction); FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("UP"), upAction); FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("UP"), upAction);
FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("DOWN"), downAction); FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("DOWN"), downAction);
FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift UP"), new SpinSearchEngineAction(-1)); FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift UP"), new SpinClientAction(-1));
FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift DOWN"), new SpinSearchEngineAction(1)); FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift DOWN"), new SpinClientAction(1));
} }
@ -213,13 +206,12 @@ public class SearchPanel extends FileBotPanel {
}; };
private class SpinSearchEngineAction extends AbstractAction { private class SpinClientAction extends AbstractAction {
private int spin; private int spin;
public SpinSearchEngineAction(int spin) { public SpinClientAction(int spin) {
super("Spin Search Engine");
this.spin = spin; this.spin = spin;
} }
@ -232,36 +224,21 @@ public class SearchPanel extends FileBotPanel {
private class SearchTask extends SwingWorker<List<String>, Object> { private class SearchTask extends SwingWorker<List<String>, Object> {
private String searchTerm; private String query;
private EpisodeListClient searchEngine; private EpisodeListClient client;
private int numberOfSeason; private int numberOfSeason;
public SearchTask(EpisodeListClient searchEngine, String searchterm, int numberOfSeason) { public SearchTask(EpisodeListClient client, String query, int numberOfSeason) {
searchTerm = searchterm; this.query = query;
this.searchEngine = searchEngine; this.client = client;
this.numberOfSeason = numberOfSeason; this.numberOfSeason = numberOfSeason;
} }
public String getSearchTerm() {
return searchTerm;
}
public int getNumberOfSeason() {
return numberOfSeason;
}
public EpisodeListClient getSearchEngine() {
return searchEngine;
}
@Override @Override
protected List<String> doInBackground() throws Exception { protected List<String> doInBackground() throws Exception {
return searchEngine.search(searchTerm); return client.search(query);
} }
} }
@ -278,14 +255,14 @@ public class SearchPanel extends FileBotPanel {
episodeList = new EpisodeListPanel(); episodeList = new EpisodeListPanel();
String title = task.getSearchTerm(); String title = task.query;
if (task.getNumberOfSeason() != SeasonSpinnerEditor.ALL_SEASONS) { if (task.numberOfSeason != SeasonSpinnerEditor.ALL_SEASONS) {
title += String.format(" - Season %d", task.getNumberOfSeason()); title += String.format(" - Season %d", task.numberOfSeason);
} }
episodeList.setTitle(title); episodeList.setTitle(title);
episodeList.setIcon(task.getSearchEngine().getIcon()); episodeList.setIcon(task.client.getIcon());
tabbedPane.addTab(title, episodeList); tabbedPane.addTab(title, episodeList);
tabbedPane.setTabComponentAt(tabbedPane.indexOfComponent(episodeList), episodeList.getTabComponent()); tabbedPane.setTabComponentAt(tabbedPane.indexOfComponent(episodeList), episodeList.getTabComponent());
@ -319,9 +296,9 @@ public class SearchPanel extends FileBotPanel {
String showname = null; String showname = null;
if (task.getSearchEngine().getFoundName(task.getSearchTerm()) != null) { if (task.client.getFoundName(task.query) != null) {
// a show matching the search term exactly has already been found // a show matching the search term exactly has already been found
showname = task.getSearchEngine().getFoundName(task.getSearchTerm()); showname = task.client.getFoundName(task.query);
} else if (shows.size() == 1) { } else if (shows.size() == 1) {
// only one show found, select this one // only one show found, select this one
showname = shows.get(0); showname = shows.get(0);
@ -337,7 +314,7 @@ public class SearchPanel extends FileBotPanel {
showname = select.getSelectedValue(); showname = select.getSelectedValue();
} else { } else {
MessageManager.showWarning("\"" + task.getSearchTerm() + "\" has not been found."); MessageManager.showWarning("\"" + task.query + "\" has not been found.");
} }
if (showname == null) { if (showname == null) {
@ -350,13 +327,13 @@ public class SearchPanel extends FileBotPanel {
String title = showname; String title = showname;
if (task.getNumberOfSeason() != SeasonSpinnerEditor.ALL_SEASONS) { if (task.numberOfSeason != SeasonSpinnerEditor.ALL_SEASONS) {
title += String.format(" - Season %d", task.getNumberOfSeason()); title += String.format(" - Season %d", task.numberOfSeason);
} }
episodeList.setTitle(title); episodeList.setTitle(title);
FetchEpisodeListTask getEpisodesTask = new FetchEpisodeListTask(task.getSearchEngine(), showname, task.getNumberOfSeason()); FetchEpisodeListTask getEpisodesTask = new FetchEpisodeListTask(task.client, showname, task.numberOfSeason);
getEpisodesTask.addPropertyChangeListener(new FetchEpisodeListTaskListener(episodeList)); getEpisodesTask.addPropertyChangeListener(new FetchEpisodeListTaskListener(episodeList));
getEpisodesTask.execute(); getEpisodesTask.execute();
@ -387,13 +364,14 @@ public class SearchPanel extends FileBotPanel {
Collection<Episode> episodes = task.get(); Collection<Episode> episodes = task.get();
history.add(episodeList.getTitle(), url, episodes.size(), task.getDuration(), episodeList.getIcon()); String info = (episodes.size() > 0) ? String.format("%d episodes", episodes.size()) : "No episodes found";
historyPanel.add(episodeList.getTitle(), url, info, task.getDuration(), episodeList.getIcon());
if (episodes.size() <= 0) if (episodes.size() <= 0)
tabbedPane.remove(episodeList); tabbedPane.remove(episodeList);
else { else {
episodeList.setLoading(false); episodeList.setLoading(false);
episodeList.getModel().addAll(episodes); episodeList.getModel().addAll(episodes);
} }
} catch (Exception e) { } catch (Exception e) {
@ -403,7 +381,6 @@ public class SearchPanel extends FileBotPanel {
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e); Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
} }
} }
} }
} }

View File

@ -1,121 +0,0 @@
package net.sourceforge.filebot.ui.panel.subtitle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class Language {
public static List<Language> languages = null;
public static synchronized List<Language> getLanguages() {
if (languages == null) {
languages = parseLanguages();
}
return Collections.unmodifiableList(languages);
}
public static Language forName(String name) {
for (Language language : getLanguages()) {
for (String languageName : language.getNames()) {
if (name.equalsIgnoreCase(languageName))
return language;
}
}
return null;
}
public static Language forCountryCode(String countryCode) {
for (Language language : getLanguages()) {
if (countryCode.equalsIgnoreCase(language.getCountryCode()))
return language;
}
return null;
}
private static List<Language> parseLanguages() {
List<Language> languages = new ArrayList<Language>();
try {
Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(Language.class.getResourceAsStream("languages.xml"));
NodeList languageNodes = dom.getDocumentElement().getChildNodes();
for (int i = 0; i < languageNodes.getLength(); i++) {
Node languageNode = languageNodes.item(i);
if (!languageNode.getNodeName().equals("language"))
continue;
String countryCode = null;
ArrayList<String> names = new ArrayList<String>();
NodeList nodes = languageNode.getChildNodes();
for (int j = 0; j < nodes.getLength(); j++) {
Node node = nodes.item(j);
if ((countryCode == null) && node.getNodeName().equals("code"))
countryCode = node.getTextContent();
else if (node.getNodeName().equals("name"))
names.add(node.getTextContent());
}
languages.add(new Language(countryCode, names));
}
} catch (Exception e) {
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
}
return languages;
}
private List<String> names;
private String countryCode;
public Language(String countryCode, Collection<String> names) {
if (names.isEmpty())
throw new IllegalArgumentException("List must not be empty");
this.countryCode = countryCode;
this.names = new ArrayList<String>(names);
}
public String getCountryCode() {
return countryCode;
}
public Iterable<String> getNames() {
return names;
}
@Override
public String toString() {
return String.format("[%s] %s", countryCode, names.get(0));
}
}

View File

@ -2,15 +2,318 @@
package net.sourceforge.filebot.ui.panel.subtitle; package net.sourceforge.filebot.ui.panel.subtitle;
import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import net.sourceforge.filebot.FileBotUtil;
import net.sourceforge.filebot.Settings;
import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.filebot.ui.FileBotPanel; import net.sourceforge.filebot.ui.FileBotPanel;
import net.sourceforge.filebot.ui.FileBotTabComponent;
import net.sourceforge.filebot.ui.HistoryPanel;
import net.sourceforge.filebot.ui.MessageManager;
import net.sourceforge.filebot.ui.SelectDialog;
import net.sourceforge.filebot.web.MovieDescriptor;
import net.sourceforge.filebot.web.SubtitleClient;
import net.sourceforge.filebot.web.SubtitleDescriptor;
import net.sourceforge.tuned.ui.SelectButton;
import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter;
import net.sourceforge.tuned.ui.TextCompletion;
import net.sourceforge.tuned.ui.TextFieldWithSelect;
public class SubtitlePanel extends FileBotPanel { public class SubtitlePanel extends FileBotPanel {
private JTabbedPane tabbedPane = new JTabbedPane(SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
private HistoryPanel historyPanel = new HistoryPanel("Show / Movie", "Number of Subtitles");
private TextFieldWithSelect<SubtitleClient> searchField;
private TextCompletion searchFieldCompletion;
public SubtitlePanel() { public SubtitlePanel() {
super("Subtitle", ResourceManager.getIcon("panel.subtitle")); super("Subtitle", ResourceManager.getIcon("panel.subtitle"));
List<SelectButton.Entry<SubtitleClient>> clients = new ArrayList<SelectButton.Entry<SubtitleClient>>();
for (SubtitleClient client : SubtitleClient.getAvailableSubtitleClients()) {
clients.add(new SelectButton.Entry<SubtitleClient>(client, client.getIcon()));
}
searchField = new TextFieldWithSelect<SubtitleClient>(clients);
searchField.getTextField().setColumns(25);
searchFieldCompletion = new TextCompletion(searchField.getTextField());
searchFieldCompletion.addTerms(Settings.getSettings().getStringList(Settings.SUBTITLE_HISTORY));
searchFieldCompletion.hook();
JPanel mainPanel = new JPanel(new BorderLayout(5, 5));
Box searchBox = Box.createHorizontalBox();
searchBox.setBorder(new EmptyBorder(5, 5, 5, 5));
searchField.setMaximumSize(searchField.getPreferredSize());
searchBox.add(Box.createHorizontalGlue());
searchBox.add(searchField);
searchBox.add(Box.createHorizontalStrut(15));
searchBox.add(new JButton(searchAction));
searchBox.add(Box.createHorizontalGlue());
JPanel centerPanel = new JPanel(new BorderLayout());
centerPanel.setBorder(BorderFactory.createTitledBorder("Search Results"));
Box buttonBox = Box.createHorizontalBox();
buttonBox.setBorder(new EmptyBorder(5, 5, 5, 5));
buttonBox.add(Box.createHorizontalGlue());
buttonBox.add(new JButton(saveAction));
buttonBox.add(Box.createHorizontalGlue());
centerPanel.add(tabbedPane, BorderLayout.CENTER);
centerPanel.add(buttonBox, BorderLayout.SOUTH);
tabbedPane.addTab("History", ResourceManager.getIcon("tab.history"), historyPanel);
mainPanel.add(searchBox, BorderLayout.NORTH);
mainPanel.add(centerPanel, BorderLayout.CENTER);
this.add(mainPanel, BorderLayout.CENTER);
FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift UP"), new SpinClientAction(-1));
FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift DOWN"), new SpinClientAction(1));
}
private class SpinClientAction extends AbstractAction {
private int spin;
public SpinClientAction(int spin) {
this.spin = spin;
}
public void actionPerformed(ActionEvent e) {
searchField.getSelectButton().spinValue(spin);
}
}
private final AbstractAction searchAction = new AbstractAction("Find", ResourceManager.getIcon("action.find")) {
public void actionPerformed(ActionEvent e) {
searchField.clearTextSelection();
SearchTask searchTask = new SearchTask(searchField.getSelectedValue(), searchField.getTextField().getText());
searchTask.addPropertyChangeListener(new SearchTaskListener());
searchTask.execute();
}
};
private final AbstractAction saveAction = new AbstractAction("Down") {
public void actionPerformed(ActionEvent e) {
//TODO save action
}
};
private class SearchTask extends SwingWorker<List<MovieDescriptor>, Object> {
private final String query;
private final SubtitleClient client;
public SearchTask(SubtitleClient client, String query) {
this.client = client;
this.query = query;
}
@Override
protected List<MovieDescriptor> doInBackground() throws Exception {
return client.search(query);
}
}
private class SearchTaskListener extends SwingWorkerPropertyChangeAdapter {
private SubtitleListPanel subtitleSearchResultPanel;
private FileBotTabComponent tabComponent;
@Override
public void started(PropertyChangeEvent evt) {
SearchTask task = (SearchTask) evt.getSource();
subtitleSearchResultPanel = new SubtitleListPanel();
tabComponent = new FileBotTabComponent(task.query, ResourceManager.getIcon("tab.loading"));
tabbedPane.addTab(task.query, subtitleSearchResultPanel);
tabbedPane.setTabComponentAt(tabbedPane.indexOfComponent(subtitleSearchResultPanel), tabComponent);
}
@Override
public void done(PropertyChangeEvent evt) {
// tab might have been closed
if (tabbedPane.indexOfComponent(subtitleSearchResultPanel) < 0)
return;
SearchTask searchTask = (SearchTask) evt.getSource();
try {
List<MovieDescriptor> desriptors = searchTask.get();
MovieDescriptor descriptor = selectDescriptor(desriptors, searchTask.client);
if (descriptor == null) {
if (desriptors.isEmpty()) {
MessageManager.showWarning(String.format("\"%s\" has not been found.", searchTask.query));
}
tabbedPane.remove(subtitleSearchResultPanel);
return;
}
fetchSubtitles(descriptor, searchTask.client);
} catch (Exception e) {
tabbedPane.remove(subtitleSearchResultPanel);
Throwable cause = FileBotUtil.getRootCause(e);
MessageManager.showWarning(cause.getMessage());
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, cause.toString());
}
}
private MovieDescriptor selectDescriptor(List<MovieDescriptor> descriptors, SubtitleClient client) {
switch (descriptors.size()) {
case 0:
return null;
case 1:
return descriptors.get(0);
}
// multiple shows found, let user selected one
Window window = SwingUtilities.getWindowAncestor(SubtitlePanel.this);
SelectDialog<MovieDescriptor> selectDialog = new SelectDialog<MovieDescriptor>(window, descriptors);
selectDialog.setText("Select a Show / Movie:");
selectDialog.setIconImage(client.getIcon().getImage());
selectDialog.setVisible(true);
// selected value or null if cancelled by the user
return selectDialog.getSelectedValue();
}
private void fetchSubtitles(MovieDescriptor descriptor, SubtitleClient client) {
Settings.getSettings().putStringList(Settings.SUBTITLE_HISTORY, searchFieldCompletion.getTerms());
searchFieldCompletion.addTerm(descriptor.getTitle());
tabComponent.setText(descriptor.getTitle());
FetchSubtitleListTask fetchListTask = new FetchSubtitleListTask(descriptor, client);
fetchListTask.addPropertyChangeListener(new FetchSubtitleListTaskListener(subtitleSearchResultPanel, tabComponent));
fetchListTask.execute();
}
}
private class FetchSubtitleListTask extends SwingWorker<List<? extends SubtitleDescriptor>, Object> {
private final SubtitleClient client;
private final MovieDescriptor descriptor;
public FetchSubtitleListTask(MovieDescriptor descriptor, SubtitleClient client) {
this.descriptor = descriptor;
this.client = client;
}
@Override
protected List<? extends SubtitleDescriptor> doInBackground() throws Exception {
return client.getSubtitleList(descriptor);
}
}
private class FetchSubtitleListTaskListener extends SwingWorkerPropertyChangeAdapter {
private final SubtitleListPanel subtitleSearchResultPanel;
private final FileBotTabComponent tabComponent;
public FetchSubtitleListTaskListener(SubtitleListPanel subtitleSearchResultPanel, FileBotTabComponent tabComponent) {
this.subtitleSearchResultPanel = subtitleSearchResultPanel;
this.tabComponent = tabComponent;
}
@Override
public void done(PropertyChangeEvent evt) {
// tab might have been closed
if (tabbedPane.indexOfComponent(subtitleSearchResultPanel) < 0)
return;
FetchSubtitleListTask task = (FetchSubtitleListTask) evt.getSource();
try {
List<? extends SubtitleDescriptor> subtitleDescriptors = task.get();
String info = (subtitleDescriptors.size() > 0) ? String.format("%d subtitles", subtitleDescriptors.size()) : "No subtitles found";
historyPanel.add(task.descriptor.toString(), null, info, 0, task.client.getIcon());
if (subtitleDescriptors.isEmpty()) {
tabbedPane.remove(subtitleSearchResultPanel);
return;
}
tabComponent.setIcon(task.client.getIcon());
//TODO icon view
//TODO sysout
System.out.println(subtitleDescriptors);
} catch (Exception e) {
tabbedPane.remove(subtitleSearchResultPanel);
MessageManager.showWarning(FileBotUtil.getRootCause(e).getMessage());
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
}
}
} }
} }

View File

@ -1,777 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<languages>
<language>
<code>aa</code>
<name>Afar</name>
</language>
<language>
<code>ab</code>
<name>Abkhazian</name>
</language>
<language>
<code>af</code>
<name>Afrikaans</name>
</language>
<language>
<code>ak</code>
<name>Akan</name>
</language>
<language>
<code>sq</code>
<name>Albanian</name>
</language>
<language>
<code>am</code>
<name>Amharic</name>
</language>
<language>
<code>ar</code>
<name>Arabic</name>
</language>
<language>
<code>an</code>
<name>Aragonese</name>
</language>
<language>
<code>hy</code>
<name>Armenian</name>
</language>
<language>
<code>as</code>
<name>Assamese</name>
</language>
<language>
<code>av</code>
<name>Avaric</name>
</language>
<language>
<code>ae</code>
<name>Avestan</name>
</language>
<language>
<code>ay</code>
<name>Aymara</name>
</language>
<language>
<code>az</code>
<name>Azerbaijani</name>
</language>
<language>
<code>ba</code>
<name>Bashkir</name>
</language>
<language>
<code>bm</code>
<name>Bambara</name>
</language>
<language>
<code>eu</code>
<name>Basque</name>
</language>
<language>
<code>be</code>
<name>Belarusian</name>
</language>
<language>
<code>bn</code>
<name>Bengali</name>
</language>
<language>
<code>bh</code>
<name>Bihari</name>
</language>
<language>
<code>bi</code>
<name>Bislama</name>
</language>
<language>
<code>bs</code>
<name>Bosnian</name>
</language>
<language>
<code>br</code>
<name>Breton</name>
</language>
<language>
<code>bg</code>
<name>Bulgarian</name>
</language>
<language>
<code>my</code>
<name>Burmese</name>
</language>
<language>
<code>ca</code>
<name>Catalan</name>
<name>Valencian</name>
</language>
<language>
<code>ch</code>
<name>Chamorro</name>
</language>
<language>
<code>ce</code>
<name>Chechen</name>
</language>
<language>
<code>zh</code>
<name>Chinese</name>
</language>
<language>
<code>cu</code>
<name>Church Slavic</name>
<name>Old Slavonic</name>
<name>Church Slavonic</name>
<name>Old Bulgarian</name>
<name>Old Church Slavonic</name>
</language>
<language>
<code>cv</code>
<name>Chuvash</name>
</language>
<language>
<code>kw</code>
<name>Cornish</name>
</language>
<language>
<code>co</code>
<name>Corsican</name>
</language>
<language>
<code>cr</code>
<name>Cree</name>
</language>
<language>
<code>cs</code>
<name>Czech</name>
</language>
<language>
<code>da</code>
<name>Danish</name>
</language>
<language>
<code>dv</code>
<name>Divehi</name>
<name>Dhivehi</name>
<name>Maldivian</name>
</language>
<language>
<code>nl</code>
<name>Dutch</name>
<name>Flemish</name>
</language>
<language>
<code>dz</code>
<name>Dzongkha</name>
</language>
<language>
<code>en</code>
<name>English</name>
</language>
<language>
<code>eo</code>
<name>Esperanto</name>
</language>
<language>
<code>et</code>
<name>Estonian</name>
</language>
<language>
<code>ee</code>
<name>Ewe</name>
</language>
<language>
<code>fo</code>
<name>Faroese</name>
</language>
<language>
<code>fj</code>
<name>Fijian</name>
</language>
<language>
<code>fi</code>
<name>Finnish</name>
</language>
<language>
<code>fr</code>
<name>French</name>
</language>
<language>
<code>fy</code>
<name>Western Frisian</name>
</language>
<language>
<code>ff</code>
<name>Fulah</name>
</language>
<language>
<code>ka</code>
<name>Georgian</name>
</language>
<language>
<code>de</code>
<name>German</name>
</language>
<language>
<code>gd</code>
<name>Gaelic</name>
<name>Scottish Gaelic</name>
</language>
<language>
<code>ga</code>
<name>Irish</name>
</language>
<language>
<code>gl</code>
<name>Galician</name>
</language>
<language>
<code>gv</code>
<name>Manx</name>
</language>
<language>
<code>el</code>
<name>Greek</name>
</language>
<language>
<code>gn</code>
<name>Guarani</name>
</language>
<language>
<code>gu</code>
<name>Gujarati</name>
</language>
<language>
<code>ht</code>
<name>Haitian</name>
<name>Haitian Creole</name>
</language>
<language>
<code>ha</code>
<name>Hausa</name>
</language>
<language>
<code>he</code>
<name>Hebrew</name>
</language>
<language>
<code>hz</code>
<name>Herero</name>
</language>
<language>
<code>hi</code>
<name>Hindi</name>
</language>
<language>
<code>ho</code>
<name>Hiri Motu</name>
</language>
<language>
<code>hu</code>
<name>Hungarian</name>
</language>
<language>
<code>ig</code>
<name>Igbo</name>
</language>
<language>
<code>is</code>
<name>Icelandic</name>
</language>
<language>
<code>io</code>
<name>Ido</name>
</language>
<language>
<code>ii</code>
<name>Sichuan Yi</name>
<name>Nuosu</name>
</language>
<language>
<code>iu</code>
<name>Inuktitut</name>
</language>
<language>
<code>ie</code>
<name>Interlingue</name>
<name>Occidental</name>
</language>
<language>
<code>ia</code>
<name>Interlingua</name>
</language>
<language>
<code>id</code>
<name>Indonesian</name>
</language>
<language>
<code>ik</code>
<name>Inupiaq</name>
</language>
<language>
<code>it</code>
<name>Italian</name>
</language>
<language>
<code>jv</code>
<name>Javanese</name>
</language>
<language>
<code>ja</code>
<name>Japanese</name>
</language>
<language>
<code>kl</code>
<name>Kalaallisut</name>
<name>Greenlandic</name>
</language>
<language>
<code>kn</code>
<name>Kannada</name>
</language>
<language>
<code>ks</code>
<name>Kashmiri</name>
</language>
<language>
<code>kr</code>
<name>Kanuri</name>
</language>
<language>
<code>kk</code>
<name>Kazakh</name>
</language>
<language>
<code>km</code>
<name>Central Khmer</name>
</language>
<language>
<code>ki</code>
<name>Kikuyu</name>
<name>Gikuyu</name>
</language>
<language>
<code>rw</code>
<name>Kinyarwanda</name>
</language>
<language>
<code>ky</code>
<name>Kirghiz</name>
<name>Kyrgyz</name>
</language>
<language>
<code>kv</code>
<name>Komi</name>
</language>
<language>
<code>kg</code>
<name>Kongo</name>
</language>
<language>
<code>ko</code>
<name>Korean</name>
</language>
<language>
<code>kj</code>
<name>Kuanyama</name>
<name>Kwanyama</name>
</language>
<language>
<code>ku</code>
<name>Kurdish</name>
</language>
<language>
<code>lo</code>
<name>Lao</name>
</language>
<language>
<code>la</code>
<name>Latin</name>
</language>
<language>
<code>lv</code>
<name>Latvian</name>
</language>
<language>
<code>li</code>
<name>Limburgan</name>
<name>Limburger</name>
<name>Limburgish</name>
</language>
<language>
<code>ln</code>
<name>Lingala</name>
</language>
<language>
<code>lt</code>
<name>Lithuanian</name>
</language>
<language>
<code>lb</code>
<name>Luxembourgish</name>
<name>Letzeburgesch</name>
</language>
<language>
<code>lu</code>
<name>Luba-Katanga</name>
</language>
<language>
<code>lg</code>
<name>Ganda</name>
</language>
<language>
<code>mk</code>
<name>Macedonian</name>
</language>
<language>
<code>mh</code>
<name>Marshallese</name>
</language>
<language>
<code>ml</code>
<name>Malayalam</name>
</language>
<language>
<code>mi</code>
<name>Maori</name>
</language>
<language>
<code>mr</code>
<name>Marathi</name>
</language>
<language>
<code>ms</code>
<name>Malay</name>
</language>
<language>
<code>mg</code>
<name>Malagasy</name>
</language>
<language>
<code>mt</code>
<name>Maltese</name>
</language>
<language>
<code>mo</code>
<name>Moldavian</name>
</language>
<language>
<code>mn</code>
<name>Mongolian</name>
</language>
<language>
<code>na</code>
<name>Nauru</name>
</language>
<language>
<code>nv</code>
<name>Navajo</name>
<name>Navaho</name>
</language>
<language>
<code>nr</code>
<name>Ndebele, South</name>
<name>South Ndebele</name>
</language>
<language>
<code>nd</code>
<name>Ndebele, North</name>
<name>North Ndebele</name>
</language>
<language>
<code>ng</code>
<name>Ndonga</name>
</language>
<language>
<code>ne</code>
<name>Nepali</name>
</language>
<language>
<code>nn</code>
<name>Norwegian Nynorsk</name>
<name>Nynorsk, Norwegian</name>
</language>
<language>
<code>nb</code>
<name>Bokmål, Norwegian</name>
<name>Norwegian Bokmål</name>
</language>
<language>
<code>no</code>
<name>Norwegian</name>
</language>
<language>
<code>ny</code>
<name>Chichewa</name>
<name>Chewa</name>
<name>Nyanja</name>
</language>
<language>
<code>oc</code>
<name>Occitan</name>
<name>Provençal</name>
</language>
<language>
<code>oj</code>
<name>Ojibwa</name>
</language>
<language>
<code>or</code>
<name>Oriya</name>
</language>
<language>
<code>om</code>
<name>Oromo</name>
</language>
<language>
<code>os</code>
<name>Ossetian</name>
<name>Ossetic</name>
</language>
<language>
<code>pa</code>
<name>Panjabi</name>
<name>Punjabi</name>
</language>
<language>
<code>fa</code>
<name>Persian</name>
</language>
<language>
<code>pi</code>
<name>Pali</name>
</language>
<language>
<code>pl</code>
<name>Polish</name>
</language>
<language>
<code>pt</code>
<name>Portuguese</name>
</language>
<language>
<code>ps</code>
<name>Pushto</name>
<name>Pashto</name>
</language>
<language>
<code>qu</code>
<name>Quechua</name>
</language>
<language>
<code>rm</code>
<name>Romansh</name>
</language>
<language>
<code>ro</code>
<name>Romanian</name>
</language>
<language>
<code>rn</code>
<name>Rundi</name>
</language>
<language>
<code>ru</code>
<name>Russian</name>
</language>
<language>
<code>sg</code>
<name>Sango</name>
</language>
<language>
<code>sa</code>
<name>Sanskrit</name>
</language>
<language>
<code>sr</code>
<name>Serbian</name>
</language>
<language>
<code>hr</code>
<name>Croatian</name>
</language>
<language>
<code>si</code>
<name>Sinhala</name>
<name>Sinhalese</name>
</language>
<language>
<code>sk</code>
<name>Slovak</name>
</language>
<language>
<code>sl</code>
<name>Slovenian</name>
</language>
<language>
<code>se</code>
<name>Northern Sami</name>
</language>
<language>
<code>sm</code>
<name>Samoan</name>
</language>
<language>
<code>sn</code>
<name>Shona</name>
</language>
<language>
<code>sd</code>
<name>Sindhi</name>
</language>
<language>
<code>so</code>
<name>Somali</name>
</language>
<language>
<code>st</code>
<name>Sotho, Southern</name>
</language>
<language>
<code>es</code>
<name>Spanish</name>
<name>Castilian</name>
</language>
<language>
<code>sc</code>
<name>Sardinian</name>
</language>
<language>
<code>ss</code>
<name>Swati</name>
</language>
<language>
<code>su</code>
<name>Sundanese</name>
</language>
<language>
<code>sw</code>
<name>Swahili</name>
</language>
<language>
<code>sv</code>
<name>Swedish</name>
</language>
<language>
<code>ty</code>
<name>Tahitian</name>
</language>
<language>
<code>ta</code>
<name>Tamil</name>
</language>
<language>
<code>tt</code>
<name>Tatar</name>
</language>
<language>
<code>te</code>
<name>Telugu</name>
</language>
<language>
<code>tg</code>
<name>Tajik</name>
</language>
<language>
<code>tl</code>
<name>Tagalog</name>
</language>
<language>
<code>th</code>
<name>Thai</name>
</language>
<language>
<code>bo</code>
<name>Tibetan</name>
</language>
<language>
<code>ti</code>
<name>Tigrinya</name>
</language>
<language>
<code>to</code>
<name>Tonga</name>
</language>
<language>
<code>tn</code>
<name>Tswana</name>
</language>
<language>
<code>ts</code>
<name>Tsonga</name>
</language>
<language>
<code>tk</code>
<name>Turkmen</name>
</language>
<language>
<code>tr</code>
<name>Turkish</name>
</language>
<language>
<code>tw</code>
<name>Twi</name>
</language>
<language>
<code>ug</code>
<name>Uighur</name>
<name>Uyghur</name>
</language>
<language>
<code>uk</code>
<name>Ukrainian</name>
</language>
<language>
<code>ur</code>
<name>Urdu</name>
</language>
<language>
<code>uz</code>
<name>Uzbek</name>
</language>
<language>
<code>ve</code>
<name>Venda</name>
</language>
<language>
<code>vi</code>
<name>Vietnamese</name>
</language>
<language>
<code>vo</code>
<name>Volapük</name>
</language>
<language>
<code>cy</code>
<name>Welsh</name>
</language>
<language>
<code>wa</code>
<name>Walloon</name>
</language>
<language>
<code>wo</code>
<name>Wolof</name>
</language>
<language>
<code>xh</code>
<name>Xhosa</name>
</language>
<language>
<code>yi</code>
<name>Yiddish</name>
</language>
<language>
<code>yo</code>
<name>Yoruba</name>
</language>
<language>
<code>za</code>
<name>Zhuang</name>
<name>Chuang</name>
</language>
<language>
<code>zu</code>
<name>Zulu</name>
</language>
</languages>

View File

@ -78,7 +78,7 @@ public class ImdbSearchEngine {
URL imdbUrl = new URL("http", host, href); URL imdbUrl = new URL("http", host, href);
return new MovieDescriptor(title, year, imdbId, imdbUrl); return new MovieDescriptor(title, imdbId, year, imdbUrl);
} }

View File

@ -7,13 +7,18 @@ import java.net.URL;
public class MovieDescriptor { public class MovieDescriptor {
private String title; private final String title;
private Integer imdbId; private final Integer imdbId;
private Integer year; private final Integer year;
private URL imdbUrl; private final URL imdbUrl;
public MovieDescriptor(String description) {
this(description, null);
}
public MovieDescriptor(String description, Integer imdbId) { public MovieDescriptor(String description, Integer imdbId) {
this(description, imdbId, null, null); this(description, imdbId, null, null);
} }

View File

@ -8,15 +8,17 @@ import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import net.sourceforge.tuned.DownloadTask;
/** /**
* Describes a subtitle on OpenSubtitles. * Describes a subtitle on OpenSubtitles.
* *
* @see OpenSubtitlesClient * @see OpenSubtitlesClient
*/ */
public class OpenSubtitleDescriptor { public class OpenSubtitleDescriptor implements SubtitleDescriptor {
private Map<String, String> properties; private final Map<String, String> properties;
public static enum Properties { public static enum Properties {
@ -60,13 +62,19 @@ public class OpenSubtitleDescriptor {
} }
public Map<String, String> getPropertyMap() { public String getProperty(Properties property) {
return properties; return properties.get(property.name());
} }
public String getProperty(Properties property) { @Override
return properties.get(property.name()); public String getName() {
return getProperty(Properties.SubFileName);
}
public String getLanguageName() {
return getProperty(Properties.LanguageName);
} }
@ -76,7 +84,7 @@ public class OpenSubtitleDescriptor {
public URL getDownloadLink() { public URL getDownloadLink() {
String link = getProperty(Properties.SubDownloadLink); String link = getProperty(Properties.ZipDownloadLink);
try { try {
return new URL(link); return new URL(link);
@ -87,9 +95,21 @@ public class OpenSubtitleDescriptor {
} }
@Override
public DownloadTask createDownloadTask() {
return new DownloadTask(getDownloadLink());
}
@Override
public String getArchiveType() {
return "zip";
}
@Override @Override
public String toString() { public String toString() {
return String.format("%s [%s]", getProperty(Properties.SubFileName), getProperty(Properties.LanguageName)); return String.format("%s [%s]", getName(), getLanguageName());
} }
} }

View File

@ -14,6 +14,8 @@ import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import net.sourceforge.filebot.Settings;
import net.sourceforge.filebot.resources.ResourceManager;
import redstone.xmlrpc.XmlRpcClient; import redstone.xmlrpc.XmlRpcClient;
import redstone.xmlrpc.XmlRpcException; import redstone.xmlrpc.XmlRpcException;
import redstone.xmlrpc.XmlRpcFault; import redstone.xmlrpc.XmlRpcFault;
@ -23,7 +25,18 @@ import redstone.xmlrpc.XmlRpcFault;
* Client for the OpenSubtitles XML-RPC API. * Client for the OpenSubtitles XML-RPC API.
* *
*/ */
public class OpenSubtitlesClient { public class OpenSubtitlesClient extends SubtitleClient {
@Override
public List<MovieDescriptor> search(String query) throws Exception {
return searchMoviesOnIMDB(query);
}
@Override
public List<OpenSubtitleDescriptor> getSubtitleList(MovieDescriptor descriptor) throws Exception {
return searchSubtitles(descriptor.getImdbId());
}
/** /**
* <table> * <table>
@ -39,11 +52,11 @@ public class OpenSubtitlesClient {
*/ */
private String url = "http://www.opensubtitles.org/xml-rpc"; private String url = "http://www.opensubtitles.org/xml-rpc";
private String username; private String username = "";
private String password; private String password = "";
private String language; private String language = "en";
private String useragent; private String useragent = String.format("%s v%s", Settings.NAME, Settings.VERSION);
private String token = null; private String token = null;
@ -55,56 +68,8 @@ public class OpenSubtitlesClient {
private static final int KEEP_ALIVE_INTERVAL = 12 * 60 * 1000; // 12 minutes private static final int KEEP_ALIVE_INTERVAL = 12 * 60 * 1000; // 12 minutes
public OpenSubtitlesClient(String useragent) { public OpenSubtitlesClient() {
this.useragent = useragent; super("OpenSubtitles", ResourceManager.getIcon("search.opensubtitles"));
}
public boolean isLoggedOn() {
return username != null;
}
/**
* login as anonymous user
*/
public synchronized void login() throws XmlRpcFault {
this.login("", "", "en");
}
/**
* This will login user. This method should be called always when starting talking with
* server.
*
* @param username blank for anonymous user.
* @param password blank for anonymous user.
* @param language <a href="http://en.wikipedia.org/wiki/List_of_ISO_639-2_codes">ISO639</a>
* 2 letter codes as language and later communication will be done in this
* language if applicable (error codes and so on).
*/
public synchronized void login(String username, String password, String language) throws XmlRpcFault {
if (isLoggedOn())
throw new IllegalStateException("User is already logged on");
if ((username == null) || (password == null) || (language == null))
throw new IllegalArgumentException("Username, password and language must not be null");
this.username = username;
this.password = password;
this.language = language;
}
public synchronized void logout() {
if (!isLoggedOn())
throw new IllegalStateException("User is not logged on");
deactivate();
username = null;
password = null;
language = null;
} }
@ -113,9 +78,6 @@ public class OpenSubtitlesClient {
if (isActive()) if (isActive())
return; return;
if (!isLoggedOn())
throw new IllegalStateException("User is not logged on");
Map<String, String> response = (Map<String, String>) invoke("LogIn", username, password, language, useragent); Map<String, String> response = (Map<String, String>) invoke("LogIn", username, password, language, useragent);
checkStatus(response.get("status")); checkStatus(response.get("status"));
@ -262,13 +224,11 @@ public class OpenSubtitlesClient {
@Override @Override
public void run() { public void run() {
Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); if (noOperation()) {
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.INFO, "Connection is OK");
if (!noOperation()) {
logger.log(Level.INFO, "Connection lost");
deactivate();
} else { } else {
logger.log(Level.INFO, "Connection is OK"); Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.INFO, "Connection lost");
deactivate();
} }
}; };
}; };

View File

@ -17,6 +17,7 @@ import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.tuned.XPathUtil; import net.sourceforge.tuned.XPathUtil;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -24,20 +25,26 @@ import org.w3c.dom.Node;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
public class SubsceneClient { public class SubsceneClient extends SubtitleClient {
private Map<String, URL> cache = Collections.synchronizedMap(new HashMap<String, URL>()); private final Map<MovieDescriptor, URL> cache = Collections.synchronizedMap(new HashMap<MovieDescriptor, URL>());
private String host = "subscene.com"; private final String host = "subscene.com";
public List<String> search(String searchterm) throws IOException, SAXException { public SubsceneClient() {
super("Subscene", ResourceManager.getIcon("search.subscene"));
}
@Override
public List<MovieDescriptor> search(String searchterm) throws IOException, SAXException {
Document dom = HtmlUtil.getHtmlDocument(getSearchUrl(searchterm)); Document dom = HtmlUtil.getHtmlDocument(getSearchUrl(searchterm));
List<Node> nodes = XPathUtil.selectNodes("id('filmSearch')/A", dom); List<Node> nodes = XPathUtil.selectNodes("id('filmSearch')/A", dom);
ArrayList<String> titles = new ArrayList<String>(); ArrayList<MovieDescriptor> results = new ArrayList<MovieDescriptor>(nodes.size());
for (Node node : nodes) { for (Node node : nodes) {
String title = XPathUtil.selectString("text()", node); String title = XPathUtil.selectString("text()", node);
@ -46,22 +53,21 @@ public class SubsceneClient {
try { try {
URL url = new URL("http", host, href); URL url = new URL("http", host, href);
cache.put(title, url); MovieDescriptor descriptor = new MovieDescriptor(title);
titles.add(title); cache.put(descriptor, url);
results.add(descriptor);
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Invalid href: " + href, e); Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Invalid href: " + href, e);
} }
} }
return titles; return results;
} }
public List<SubsceneSubtitleDescriptor> getSubtitleList(String title) throws IOException, SAXException { @Override
URL url = cache.get(title); public List<SubsceneSubtitleDescriptor> getSubtitleList(MovieDescriptor descriptor) throws IOException, SAXException {
URL url = cache.get(descriptor);
if (url == null)
throw new IllegalArgumentException("Unknown title: " + title);
Document dom = HtmlUtil.getHtmlDocument(url); Document dom = HtmlUtil.getHtmlDocument(url);

View File

@ -8,15 +8,15 @@ import java.util.Map;
import net.sourceforge.tuned.DownloadTask; import net.sourceforge.tuned.DownloadTask;
public class SubsceneSubtitleDescriptor { public class SubsceneSubtitleDescriptor implements SubtitleDescriptor {
private String title; private final String title;
private String language; private final String language;
private int numberOfCDs; private final int numberOfCDs;
private String author; private final String author;
private Map<String, String> downloadParameters; private final Map<String, String> downloadParameters;
private URL downloadUrl; private final URL downloadUrl;
public SubsceneSubtitleDescriptor(String title, String language, int numberOfCDs, String author, URL downloadUrl, Map<String, String> downloadParameters) { public SubsceneSubtitleDescriptor(String title, String language, int numberOfCDs, String author, URL downloadUrl, Map<String, String> downloadParameters) {
@ -30,12 +30,12 @@ public class SubsceneSubtitleDescriptor {
} }
public String getTitle() { public String getName() {
return title; return title;
} }
public String getLanguage() { public String getLanguageName() {
return language; return language;
} }
@ -50,13 +50,13 @@ public class SubsceneSubtitleDescriptor {
} }
public String getArchiveType() { public DownloadTask createDownloadTask() {
return downloadParameters.get("typeId"); return new DownloadTask(downloadUrl, downloadParameters);
} }
public DownloadTask createDownloadTask() { public String getArchiveType() {
return new DownloadTask(downloadUrl, downloadParameters); return downloadParameters.get("typeId");
} }

View File

@ -0,0 +1,56 @@
package net.sourceforge.filebot.web;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.ImageIcon;
public abstract class SubtitleClient {
private static final List<SubtitleClient> registry = new ArrayList<SubtitleClient>();
static {
registry.add(new OpenSubtitlesClient());
registry.add(new SubsceneClient());
}
public static List<SubtitleClient> getAvailableSubtitleClients() {
return Collections.unmodifiableList(registry);
}
private String name;
private ImageIcon icon;
public SubtitleClient(String name, ImageIcon icon) {
this.name = name;
this.icon = icon;
}
public String getName() {
return name;
}
public ImageIcon getIcon() {
return icon;
}
public abstract List<MovieDescriptor> search(String query) throws Exception;
public abstract List<? extends SubtitleDescriptor> getSubtitleList(MovieDescriptor descriptor) throws Exception;
@Override
public String toString() {
return name;
}
}

View File

@ -0,0 +1,21 @@
package net.sourceforge.filebot.web;
import net.sourceforge.tuned.DownloadTask;
public interface SubtitleDescriptor {
public String getName();
public String getLanguageName();
public String getArchiveType();
public DownloadTask createDownloadTask();
}

View File

@ -57,8 +57,6 @@ public abstract class AbstractFancyListCellRenderer extends JComponent implement
public AbstractFancyListCellRenderer(Insets padding, Insets margin, Color borderColor) { public AbstractFancyListCellRenderer(Insets padding, Insets margin, Color borderColor) {
this.setLayout(new BorderLayout()); this.setLayout(new BorderLayout());
this.margin = margin;
Border border = null; Border border = null;
if (padding != null) if (padding != null)
@ -67,8 +65,12 @@ public abstract class AbstractFancyListCellRenderer extends JComponent implement
if (borderColor != null) if (borderColor != null)
border = new CompoundBorder(new LineBorder(borderColor, 1), border); border = new CompoundBorder(new LineBorder(borderColor, 1), border);
if (margin != null) if (margin != null) {
this.margin = margin;
border = new CompoundBorder(new EmptyBorder(margin), border); border = new CompoundBorder(new EmptyBorder(margin), border);
} else {
this.margin = new Insets(0, 0, 0, 0);
}
setBorder(border); setBorder(border);
setOpaque(false); setOpaque(false);