some refactoring, new icons, imdb search engine

This commit is contained in:
Reinhard Pointner 2008-02-09 17:53:08 +00:00
parent 11b4034a9e
commit f3d1cc50c0
19 changed files with 217 additions and 126 deletions

BIN
fw/search.imdb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
fw/search.opensubtitles.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
fw/search.subscene.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -13,71 +13,19 @@ import javax.swing.ImageIcon;
public class ResourceManager {
private static HashMap<String, URL> resourceMap = new HashMap<String, URL>();
private static HashMap<String, String> aliasMap = new HashMap<String, String>();
static {
putResource("window.icon.small", "window.icon.small.png");
putResource("window.icon.big", "window.icon.big.png");
aliasMap.put("tab.loading", "tab.loading.gif");
aliasMap.put("tab.history", "action.find.png");
putResource("panel.analyze", "panel.analyze.png");
putResource("panel.rename", "panel.rename.png");
putResource("panel.create", "panel.create.png");
putResource("panel.list", "panel.list.png");
putResource("panel.search", "panel.search.png");
putResource("tree.open", "tree.open.png");
putResource("tree.closed", "tree.closed.png");
putResource("tree.leaf", "tree.leaf.png");
putResource("action.rename", "action.rename.png");
putResource("action.down", "action.down.png");
putResource("action.up", "action.up.png");
putResource("action.save", "action.save.png");
putResource("action.load", "action.load.png");
putResource("action.clear", "action.clear.png");
putResource("action.find", "action.find.png");
putResource("action.match.file2name", "action.match.file2name.png");
putResource("action.match.name2file", "action.match.name2file.png");
putResource("message.info", "message.info.png");
putResource("message.warning", "message.warning.png");
putResource("search.anidb", "search.anidb.png");
putResource("search.tvdotcom", "search.tvdotcom.png");
putResource("search.tvrage", "search.tvrage.png");
putResource("tab.close", "tab.close.png");
putResource("tab.close.hover", "tab.close.hover.png");
putResource("tab.loading", "tab.loading.gif");
putResource("tab.history", "action.find.png");
putResource("loading", "loading.gif");
putResource("tree.expand", "tree.expand.png");
putResource("tree.collapse", "tree.collapse.png");
putResource("panel.sfv", "panel.sfv.png");
putResource("status.error", "status.error.png");
putResource("status.ok", "status.ok.png");
putResource("status.unknown", "status.unknown.png");
putResource("status.warning", "status.warning.png");
putResource("decoration.header", "decoration.header.png");
aliasMap.put("loading", "loading.gif");
}
private static void putResource(String name, String file) {
resourceMap.put(name, ResourceManager.class.getResource(file));
}
public static Image getImage(String name) {
if (!resourceMap.containsKey(name))
return null;
try {
return ImageIO.read(resourceMap.get(name));
return ImageIO.read(getResource(name));
} catch (IOException e) {
return null;
}
@ -85,7 +33,18 @@ public class ResourceManager {
public static ImageIcon getIcon(String name) {
return new ImageIcon(resourceMap.get(name));
return new ImageIcon(getResource(name));
}
private static URL getResource(String name) {
String resource = null;
if (aliasMap.containsKey(name))
resource = aliasMap.get(name);
else
resource = name + ".png";
return ResourceManager.class.getResource(resource);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

View File

@ -7,18 +7,18 @@ import java.util.List;
import javax.swing.SwingWorker;
import net.sourceforge.filebot.web.Episode;
import net.sourceforge.filebot.web.SearchEngine;
import net.sourceforge.filebot.web.EpisodeListClient;
public class FetchEpisodesTask extends SwingWorker<List<Episode>, Object> {
private String showName;
private SearchEngine searchEngine;
private EpisodeListClient searchEngine;
private int numberOfSeason;
private long duration;
public FetchEpisodesTask(SearchEngine searchEngine, String showname, int numberOfSeason) {
public FetchEpisodesTask(EpisodeListClient searchEngine, String showname, int numberOfSeason) {
showName = showname;
this.searchEngine = searchEngine;
this.numberOfSeason = numberOfSeason;
@ -51,7 +51,7 @@ public class FetchEpisodesTask extends SwingWorker<List<Episode>, Object> {
}
public SearchEngine getSearchEngine() {
public EpisodeListClient getSearchEngine() {
return searchEngine;
}

View File

@ -38,11 +38,11 @@ import net.sourceforge.filebot.ui.FileBotPanel;
import net.sourceforge.filebot.ui.FileBotUtil;
import net.sourceforge.filebot.ui.MessageManager;
import net.sourceforge.filebot.ui.transfer.SaveAction;
import net.sourceforge.filebot.web.AnidbSearchEngine;
import net.sourceforge.filebot.web.AnidbClient;
import net.sourceforge.filebot.web.Episode;
import net.sourceforge.filebot.web.SearchEngine;
import net.sourceforge.filebot.web.TVRageSearchEngine;
import net.sourceforge.filebot.web.TvdotcomSearchEngine;
import net.sourceforge.filebot.web.EpisodeListClient;
import net.sourceforge.filebot.web.TVRageClient;
import net.sourceforge.filebot.web.TvdotcomClient;
import net.sourceforge.tuned.ui.SelectButton;
import net.sourceforge.tuned.ui.SelectDialog;
import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter;
@ -58,11 +58,11 @@ public class SearchPanel extends FileBotPanel {
private SpinnerNumberModel seasonSpinnerModel = new SpinnerNumberModel(SeasonSpinnerEditor.ALL_SEASONS, SeasonSpinnerEditor.ALL_SEASONS, Integer.MAX_VALUE, 1);
private TextFieldWithSelect<SearchEngine> searchField;
private TextFieldWithSelect<EpisodeListClient> searchField;
private TextCompletion searchFieldCompletion;
private List<SearchEngine> searchEngineList = new ArrayList<SearchEngine>();
private List<EpisodeListClient> episodeListClients = new ArrayList<EpisodeListClient>();
private JSpinner seasonSpinner;
@ -70,17 +70,17 @@ public class SearchPanel extends FileBotPanel {
public SearchPanel() {
super("Search", ResourceManager.getIcon("panel.search"));
searchEngineList.add(new TvdotcomSearchEngine());
searchEngineList.add(new AnidbSearchEngine());
searchEngineList.add(new TVRageSearchEngine());
episodeListClients.add(new TvdotcomClient());
episodeListClients.add(new AnidbClient());
episodeListClients.add(new TVRageClient());
HashMap<SearchEngine, ImageIcon> icons = new HashMap<SearchEngine, ImageIcon>();
HashMap<EpisodeListClient, ImageIcon> icons = new HashMap<EpisodeListClient, ImageIcon>();
for (SearchEngine searchEngine : searchEngineList) {
for (EpisodeListClient searchEngine : episodeListClients) {
icons.put(searchEngine, searchEngine.getIcon());
}
searchField = new TextFieldWithSelect<SearchEngine>(searchEngineList, icons);
searchField = new TextFieldWithSelect<EpisodeListClient>(episodeListClients, icons);
searchField.getSelectButton().addPropertyChangeListener(SelectButton.SELECTED_VALUE_PROPERTY, searchFieldListener);
searchField.getTextField().setColumns(25);
@ -142,7 +142,7 @@ public class SearchPanel extends FileBotPanel {
private final PropertyChangeListener searchFieldListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
SearchEngine se = searchField.getSelectedValue();
EpisodeListClient se = searchField.getSelectedValue();
if (!se.isSingleSeasonSupported()) {
seasonSpinnerModel.setMaximum(SeasonSpinnerEditor.ALL_SEASONS);
@ -160,7 +160,7 @@ public class SearchPanel extends FileBotPanel {
public void actionPerformed(ActionEvent e) {
searchField.clearTextSelection();
SearchEngine searchEngine = searchField.getSelectedValue();
EpisodeListClient searchEngine = searchField.getSelectedValue();
SearchTask task = new SearchTask(searchEngine, searchField.getTextField().getText(), seasonSpinnerModel.getNumber().intValue());
task.addPropertyChangeListener(new SearchTaskListener());
@ -230,17 +230,17 @@ public class SearchPanel extends FileBotPanel {
public void actionPerformed(ActionEvent e) {
SearchEngine current = searchField.getSelectedValue();
EpisodeListClient current = searchField.getSelectedValue();
int nextIndex = searchEngineList.indexOf(current) + spinOffset;
int maxIndex = searchEngineList.size() - 1;
int nextIndex = episodeListClients.indexOf(current) + spinOffset;
int maxIndex = episodeListClients.size() - 1;
if (nextIndex < 0)
nextIndex = maxIndex;
else if (nextIndex > maxIndex)
nextIndex = 0;
searchField.getSelectButton().setSelectedValue(searchEngineList.get(nextIndex));
searchField.getSelectButton().setSelectedValue(episodeListClients.get(nextIndex));
}
}
@ -248,11 +248,11 @@ public class SearchPanel extends FileBotPanel {
private class SearchTask extends SwingWorker<List<String>, Object> {
private String searchTerm;
private SearchEngine searchEngine;
private EpisodeListClient searchEngine;
private int numberOfSeason;
public SearchTask(SearchEngine searchEngine, String searchterm, int numberOfSeason) {
public SearchTask(EpisodeListClient searchEngine, String searchterm, int numberOfSeason) {
searchTerm = searchterm;
this.searchEngine = searchEngine;
this.numberOfSeason = numberOfSeason;
@ -269,7 +269,7 @@ public class SearchPanel extends FileBotPanel {
}
public SearchEngine getSearchEngine() {
public EpisodeListClient getSearchEngine() {
return searchEngine;
}

View File

@ -48,15 +48,7 @@ public class Checksum {
public String getChecksumString() {
StringBuffer buffer = new StringBuffer(8);
buffer.append(Long.toHexString(checksum).toUpperCase());
while (buffer.length() < 8) {
buffer.insert(0, "0");
}
return buffer.toString();
return String.format("%08x", checksum).toUpperCase();
}

View File

@ -12,6 +12,8 @@ import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public abstract class FileTransferablePolicy extends TransferablePolicy {
@ -32,7 +34,8 @@ public abstract class FileTransferablePolicy extends TransferablePolicy {
protected List<File> getFilesFromTransferable(Transferable tr) {
List<File> files = getFilesFromFileTransferable(tr);
// if there is no file transferable, look if there is a string transferable that contains file uris
// if there is no file transferable, look if there is a string transferable that
// contains file uris
if (files == null)
files = getFilesFromStringTransferable(tr);
@ -83,7 +86,7 @@ public abstract class FileTransferablePolicy extends TransferablePolicy {
if (file.exists())
files.add(file);
} catch (URISyntaxException e) {
System.err.println(e);
Logger.getAnonymousLogger().log(Level.WARNING, "Invalid file url: " + line, e);
}
}

View File

@ -14,6 +14,8 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.tuned.XPathUtil;
@ -23,14 +25,14 @@ import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class AnidbSearchEngine extends SearchEngine {
public class AnidbClient extends EpisodeListClient {
private Map<String, URL> cache = Collections.synchronizedMap(new TreeMap<String, URL>());
private String host = "anidb.info";
public AnidbSearchEngine() {
public AnidbClient() {
super("AniDB", ResourceManager.getIcon("search.anidb"), false);
};
@ -65,7 +67,7 @@ public class AnidbSearchEngine extends SearchEngine {
cache.put(title, url);
shows.add(title);
} catch (MalformedURLException e) {
System.err.println("Invalid href: " + href);
Logger.getAnonymousLogger().log(Level.WARNING, "Invalid href: " + href, e);
}
}
}

View File

@ -8,13 +8,15 @@ import java.util.List;
import javax.swing.ImageIcon;
public abstract class SearchEngine {
public abstract class EpisodeListClient {
/**
* List of shows
*/
public abstract List<String> search(String searchterm) throws Exception;
/**
*
* @param showname
* @param season number of season, 0 for all seasons
* @return
@ -35,7 +37,7 @@ public abstract class SearchEngine {
private ImageIcon icon;
public SearchEngine(String name, ImageIcon icon, boolean singleSeasonSupported) {
public EpisodeListClient(String name, ImageIcon icon, boolean singleSeasonSupported) {
this.name = name;
this.icon = icon;
this.singleSeasonSupported = singleSeasonSupported;

View File

@ -0,0 +1,96 @@
package net.sourceforge.filebot.web;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.ImageIcon;
import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.tuned.XPathUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class ImdbSearchEngine {
private String host = "www.imdb.com";
public List<Movie> search(String searchterm) throws IOException, SAXException {
Document dom = HtmlUtil.getHtmlDocument(getSearchUrl(searchterm));
List<Node> nodes = XPathUtil.selectNodes("id('outerbody')//TABLE//P[position() >= 2 and position() <=3 ]//A[count(child::IMG) <= 0]/..", dom);
ArrayList<Movie> movies = new ArrayList<Movie>();
for (Node node : nodes) {
try {
movies.add(parseMovie(node));
} catch (Exception e) {
Logger.getAnonymousLogger().log(Level.WARNING, "Invalid movie node", e);
}
}
return movies;
}
private Movie parseMovie(Node node) {
// ignore javascript links
Node linkNode = XPathUtil.selectFirstNode("./A[count(@onclick) <= 0]", node);
String title = XPathUtil.selectString("text()", linkNode);
String href = XPathUtil.selectString("@href", linkNode);
// match /title/tt0379786/
Matcher idMatcher = Pattern.compile(".*/tt(\\d+)/.*").matcher(href);
Integer imdbID = null;
if (idMatcher.matches()) {
imdbID = new Integer(idMatcher.group(1));
} else {
throw new IllegalArgumentException("Cannot match imdb id: " + href);
}
String yearString = XPathUtil.selectString("text()[1]", node);
// match (2005)
Matcher yearMatcher = Pattern.compile(".*\\((\\d+)\\).*").matcher(yearString);
Integer year = null;
if (yearMatcher.matches()) {
year = new Integer(yearMatcher.group(1));
} else {
throw new IllegalArgumentException("Cannot match year: " + yearString);
}
return new Movie(title, year, imdbID);
}
private URL getSearchUrl(String searchterm) throws UnsupportedEncodingException, MalformedURLException {
String qs = URLEncoder.encode(searchterm, "UTF-8");
String file = "/find?q=" + qs + ";s=tt";
return new URL("http", host, file);
}
public ImageIcon getIcon() {
return ResourceManager.getIcon("search.imdb");
}
}

View File

@ -0,0 +1,43 @@
package net.sourceforge.filebot.web;
public class Movie {
private String title;
private Integer year;
private Integer imdbID;
public Movie(String title, Integer year, Integer imdbID) {
this.title = title;
this.imdbID = imdbID;
this.year = year;
}
public String getTitle() {
return title;
}
public Integer getImdbID() {
return imdbID;
}
public Integer getYear() {
return year;
}
@Override
public String toString() {
if (year == null)
return title;
return String.format("%s (%d)", title, year);
}
}

View File

@ -16,7 +16,7 @@ import java.nio.channels.FileChannel.MapMode;
* checksum of the first and last 64k (even if they overlap because the file is smaller than
* 128k).
*/
class OpenSubtitlesHasher {
public class OpenSubtitlesHasher {
/**
* Size of the chunks that will be hashed in bytes (64 KB)
@ -44,7 +44,8 @@ class OpenSubtitlesHasher {
BigInteger bigHash = BigInteger.valueOf(size).add(head.add(tail));
byte[] hash = getTrailingBytes(bigHash.toByteArray(), HASH_SIZE);
return format(new BigInteger(1, hash));
return String.format("%0" + HASH_SIZE * 2 + "x", new BigInteger(1, hash));
}
@ -65,22 +66,6 @@ class OpenSubtitlesHasher {
}
private static String format(BigInteger hash) {
// 1 byte -> 2 hex digits
int minLength = HASH_SIZE * 2;
StringBuffer sb = new StringBuffer(minLength);
sb.append(hash.toString(16));
while (sb.length() < minLength) {
sb.insert(0, "0");
}
return sb.toString();
}
/**
* copy the last n bytes to a new array
*

View File

@ -13,6 +13,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -24,14 +26,14 @@ import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class TVRageSearchEngine extends SearchEngine {
public class TVRageClient extends EpisodeListClient {
private Map<String, URL> cache = Collections.synchronizedMap(new TreeMap<String, URL>());
private String host = "www.tvrage.com";
public TVRageSearchEngine() {
public TVRageClient() {
super("TVRage", ResourceManager.getIcon("search.tvrage"), true);
}
@ -44,7 +46,7 @@ public class TVRageSearchEngine extends SearchEngine {
Document dom = HtmlUtil.getHtmlDocument(getSearchUrl(searchterm));
List<Node> nodes = XPathUtil.selectNodes("//DIV[@id='search_begin']//TABLE[1]/*/TR/TD/A[1]", dom);
List<Node> nodes = XPathUtil.selectNodes("id('search_begin')//TABLE[1]/*/TR/TD/A[1]", dom);
ArrayList<String> shows = new ArrayList<String>(nodes.size());
@ -57,7 +59,7 @@ public class TVRageSearchEngine extends SearchEngine {
cache.put(title, url);
shows.add(title);
} catch (MalformedURLException e) {
System.err.println("Invalid href: " + href);
Logger.getAnonymousLogger().log(Level.WARNING, "Invalid href: " + href, e);
}
}

View File

@ -14,6 +14,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sourceforge.filebot.resources.ResourceManager;
import net.sourceforge.tuned.XPathUtil;
@ -23,14 +25,14 @@ import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class TvdotcomSearchEngine extends SearchEngine {
public class TvdotcomClient extends EpisodeListClient {
private Map<String, URL> cache = Collections.synchronizedMap(new TreeMap<String, URL>());
private String host = "www.tv.com";
public TvdotcomSearchEngine() {
public TvdotcomClient() {
super("TV.com", ResourceManager.getIcon("search.tvdotcom"), true);
}
@ -43,7 +45,7 @@ public class TvdotcomSearchEngine extends SearchEngine {
Document dom = HtmlUtil.getHtmlDocument(getSearchUrl(searchterm));
List<Node> nodes = XPathUtil.selectNodes("//TABLE[@id='search-results']//SPAN/A", dom);
List<Node> nodes = XPathUtil.selectNodes("id('search-results')//SPAN/A", dom);
ArrayList<String> shows = new ArrayList<String>(nodes.size());
@ -61,7 +63,7 @@ public class TvdotcomSearchEngine extends SearchEngine {
cache.put(title, url);
shows.add(title);
} catch (MalformedURLException e) {
System.err.println("Invalid href: " + href);
Logger.getAnonymousLogger().log(Level.WARNING, "Invalid href: " + href, e);
}
}
}

View File

@ -26,6 +26,11 @@ public class XPathUtil {
}
public static Node selectFirstNode(String xpath, Object node) {
return selectNodes(xpath, node).get(0);
}
public static List<Node> selectNodes(String xpath, Object node) {
try {
XPath xp = XPathFactory.newInstance().newXPath();