* 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();
public static final String NAME = "FileBot";
public static final String VERSION = "2.0";
public static final String ROOT = "filebot";
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;
@ -19,16 +19,23 @@ import javax.swing.SwingUtilities;
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));
setOpaque(false);
label = new JLabel("", SwingConstants.LEFT);
label = new JLabel(title, SwingConstants.LEFT);
label.setIcon(icon);
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 2));
add(label, BorderLayout.CENTER);
@ -52,8 +59,8 @@ class TabComponentWithClose extends JPanel {
public void close() {
JTabbedPane tabs = (JTabbedPane) SwingUtilities.getAncestorOfClass(JTabbedPane.class, TabComponentWithClose.this);
tabs.removeTabAt(tabs.indexOfTabComponent(TabComponentWithClose.this));
JTabbedPane tabs = (JTabbedPane) SwingUtilities.getAncestorOfClass(JTabbedPane.class, FileBotTabComponent.this);
tabs.removeTabAt(tabs.indexOfTabComponent(FileBotTabComponent.this));
}
private final AbstractAction tabCloseAction = new AbstractAction(null, null) {

View File

@ -40,7 +40,7 @@ public class FileBotWindow extends JFrame implements ListSelectionListener {
public FileBotWindow() {
super("FileBot");
super(Settings.NAME);
setLocationByPlatform(true);
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.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;
@ -22,7 +23,7 @@ class EpisodeListPanel extends FileBotList {
}
public TabComponentWithClose getTabComponent() {
public FileBotTabComponent getTabComponent() {
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.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
@ -36,6 +34,7 @@ import net.sourceforge.filebot.FileBotUtil;
import net.sourceforge.filebot.Settings;
import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.filebot.ui.FileBotPanel;
import net.sourceforge.filebot.ui.HistoryPanel;
import net.sourceforge.filebot.ui.MessageManager;
import net.sourceforge.filebot.ui.SelectDialog;
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 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);
@ -60,8 +59,6 @@ public class SearchPanel extends FileBotPanel {
private TextCompletion searchFieldCompletion;
private JSpinner seasonSpinner;
public SearchPanel() {
super("Search", ResourceManager.getIcon("panel.search"));
@ -85,7 +82,7 @@ public class SearchPanel extends FileBotPanel {
Box searchBox = Box.createHorizontalBox();
searchBox.setBorder(new EmptyBorder(5, 5, 5, 5));
seasonSpinner = new JSpinner(seasonSpinnerModel);
JSpinner seasonSpinner = new JSpinner(seasonSpinnerModel);
seasonSpinner.setEditor(new SeasonSpinnerEditor(seasonSpinner));
searchField.setMaximumSize(searchField.getPreferredSize());
seasonSpinner.setMaximumSize(seasonSpinner.getPreferredSize());
@ -110,11 +107,7 @@ public class SearchPanel extends FileBotPanel {
centerPanel.add(tabbedPane, BorderLayout.CENTER);
centerPanel.add(buttonBox, BorderLayout.SOUTH);
JScrollPane sp = new JScrollPane(history);
sp.setBorder(BorderFactory.createEmptyBorder());
sp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
tabbedPane.addTab("History", ResourceManager.getIcon("tab.history"), sp);
tabbedPane.addTab("History", ResourceManager.getIcon("tab.history"), historyPanel);
mainPanel.add(searchBox, BorderLayout.NORTH);
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("UP"), upAction);
FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("DOWN"), downAction);
FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift UP"), new SpinSearchEngineAction(-1));
FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift DOWN"), new SpinSearchEngineAction(1));
FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift UP"), new SpinClientAction(-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;
public SpinSearchEngineAction(int spin) {
super("Spin Search Engine");
public SpinClientAction(int spin) {
this.spin = spin;
}
@ -232,36 +224,21 @@ public class SearchPanel extends FileBotPanel {
private class SearchTask extends SwingWorker<List<String>, Object> {
private String searchTerm;
private EpisodeListClient searchEngine;
private String query;
private EpisodeListClient client;
private int numberOfSeason;
public SearchTask(EpisodeListClient searchEngine, String searchterm, int numberOfSeason) {
searchTerm = searchterm;
this.searchEngine = searchEngine;
public SearchTask(EpisodeListClient client, String query, int numberOfSeason) {
this.query = query;
this.client = client;
this.numberOfSeason = numberOfSeason;
}
public String getSearchTerm() {
return searchTerm;
}
public int getNumberOfSeason() {
return numberOfSeason;
}
public EpisodeListClient getSearchEngine() {
return searchEngine;
}
@Override
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();
String title = task.getSearchTerm();
String title = task.query;
if (task.getNumberOfSeason() != SeasonSpinnerEditor.ALL_SEASONS) {
title += String.format(" - Season %d", task.getNumberOfSeason());
if (task.numberOfSeason != SeasonSpinnerEditor.ALL_SEASONS) {
title += String.format(" - Season %d", task.numberOfSeason);
}
episodeList.setTitle(title);
episodeList.setIcon(task.getSearchEngine().getIcon());
episodeList.setIcon(task.client.getIcon());
tabbedPane.addTab(title, episodeList);
tabbedPane.setTabComponentAt(tabbedPane.indexOfComponent(episodeList), episodeList.getTabComponent());
@ -319,9 +296,9 @@ public class SearchPanel extends FileBotPanel {
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
showname = task.getSearchEngine().getFoundName(task.getSearchTerm());
showname = task.client.getFoundName(task.query);
} else if (shows.size() == 1) {
// only one show found, select this one
showname = shows.get(0);
@ -337,7 +314,7 @@ public class SearchPanel extends FileBotPanel {
showname = select.getSelectedValue();
} else {
MessageManager.showWarning("\"" + task.getSearchTerm() + "\" has not been found.");
MessageManager.showWarning("\"" + task.query + "\" has not been found.");
}
if (showname == null) {
@ -350,13 +327,13 @@ public class SearchPanel extends FileBotPanel {
String title = showname;
if (task.getNumberOfSeason() != SeasonSpinnerEditor.ALL_SEASONS) {
title += String.format(" - Season %d", task.getNumberOfSeason());
if (task.numberOfSeason != SeasonSpinnerEditor.ALL_SEASONS) {
title += String.format(" - Season %d", task.numberOfSeason);
}
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.execute();
@ -387,13 +364,14 @@ public class SearchPanel extends FileBotPanel {
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)
tabbedPane.remove(episodeList);
else {
episodeList.setLoading(false);
episodeList.getModel().addAll(episodes);
}
} catch (Exception e) {
@ -403,7 +381,6 @@ public class SearchPanel extends FileBotPanel {
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;
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.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 {
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() {
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);
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 {
private String title;
private Integer imdbId;
private final String title;
private final Integer imdbId;
private Integer year;
private URL imdbUrl;
private final Integer year;
private final URL imdbUrl;
public MovieDescriptor(String description) {
this(description, null);
}
public MovieDescriptor(String description, Integer imdbId) {
this(description, imdbId, null, null);
}

View File

@ -8,15 +8,17 @@ import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sourceforge.tuned.DownloadTask;
/**
* Describes a subtitle on OpenSubtitles.
*
* @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 {
@ -60,13 +62,19 @@ public class OpenSubtitleDescriptor {
}
public Map<String, String> getPropertyMap() {
return properties;
public String getProperty(Properties property) {
return properties.get(property.name());
}
public String getProperty(Properties property) {
return properties.get(property.name());
@Override
public String getName() {
return getProperty(Properties.SubFileName);
}
public String getLanguageName() {
return getProperty(Properties.LanguageName);
}
@ -76,7 +84,7 @@ public class OpenSubtitleDescriptor {
public URL getDownloadLink() {
String link = getProperty(Properties.SubDownloadLink);
String link = getProperty(Properties.ZipDownloadLink);
try {
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
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.Pattern;
import net.sourceforge.filebot.Settings;
import net.sourceforge.filebot.resources.ResourceManager;
import redstone.xmlrpc.XmlRpcClient;
import redstone.xmlrpc.XmlRpcException;
import redstone.xmlrpc.XmlRpcFault;
@ -23,7 +25,18 @@ import redstone.xmlrpc.XmlRpcFault;
* 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>
@ -39,11 +52,11 @@ public class OpenSubtitlesClient {
*/
private String url = "http://www.opensubtitles.org/xml-rpc";
private String username;
private String password;
private String language;
private String username = "";
private String password = "";
private String language = "en";
private String useragent;
private String useragent = String.format("%s v%s", Settings.NAME, Settings.VERSION);
private String token = null;
@ -55,56 +68,8 @@ public class OpenSubtitlesClient {
private static final int KEEP_ALIVE_INTERVAL = 12 * 60 * 1000; // 12 minutes
public OpenSubtitlesClient(String useragent) {
this.useragent = useragent;
}
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;
public OpenSubtitlesClient() {
super("OpenSubtitles", ResourceManager.getIcon("search.opensubtitles"));
}
@ -113,9 +78,6 @@ public class OpenSubtitlesClient {
if (isActive())
return;
if (!isLoggedOn())
throw new IllegalStateException("User is not logged on");
Map<String, String> response = (Map<String, String>) invoke("LogIn", username, password, language, useragent);
checkStatus(response.get("status"));
@ -262,13 +224,11 @@ public class OpenSubtitlesClient {
@Override
public void run() {
Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
if (!noOperation()) {
logger.log(Level.INFO, "Connection lost");
deactivate();
if (noOperation()) {
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.INFO, "Connection is OK");
} 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.Pattern;
import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.tuned.XPathUtil;
import org.w3c.dom.Document;
@ -24,20 +25,26 @@ import org.w3c.dom.Node;
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));
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) {
String title = XPathUtil.selectString("text()", node);
@ -46,22 +53,21 @@ public class SubsceneClient {
try {
URL url = new URL("http", host, href);
cache.put(title, url);
titles.add(title);
MovieDescriptor descriptor = new MovieDescriptor(title);
cache.put(descriptor, url);
results.add(descriptor);
} catch (MalformedURLException 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 {
URL url = cache.get(title);
if (url == null)
throw new IllegalArgumentException("Unknown title: " + title);
@Override
public List<SubsceneSubtitleDescriptor> getSubtitleList(MovieDescriptor descriptor) throws IOException, SAXException {
URL url = cache.get(descriptor);
Document dom = HtmlUtil.getHtmlDocument(url);

View File

@ -8,15 +8,15 @@ import java.util.Map;
import net.sourceforge.tuned.DownloadTask;
public class SubsceneSubtitleDescriptor {
public class SubsceneSubtitleDescriptor implements SubtitleDescriptor {
private String title;
private String language;
private int numberOfCDs;
private String author;
private final String title;
private final String language;
private final int numberOfCDs;
private final String author;
private Map<String, String> downloadParameters;
private URL downloadUrl;
private final Map<String, String> downloadParameters;
private final URL downloadUrl;
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;
}
public String getLanguage() {
public String getLanguageName() {
return language;
}
@ -50,13 +50,13 @@ public class SubsceneSubtitleDescriptor {
}
public String getArchiveType() {
return downloadParameters.get("typeId");
public DownloadTask createDownloadTask() {
return new DownloadTask(downloadUrl, downloadParameters);
}
public DownloadTask createDownloadTask() {
return new DownloadTask(downloadUrl, downloadParameters);
public String getArchiveType() {
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) {
this.setLayout(new BorderLayout());
this.margin = margin;
Border border = null;
if (padding != null)
@ -67,8 +65,12 @@ public abstract class AbstractFancyListCellRenderer extends JComponent implement
if (borderColor != null)
border = new CompoundBorder(new LineBorder(borderColor, 1), border);
if (margin != null)
if (margin != null) {
this.margin = margin;
border = new CompoundBorder(new EmptyBorder(margin), border);
} else {
this.margin = new Insets(0, 0, 0, 0);
}
setBorder(border);
setOpaque(false);