* support manual input of movie/series title (as fallback if auto-detection fails or if forced via SHIFT-clicking the data source)
* fixed movie mode issues (osdb title/year parsing problem, nfo file imdbid parser problem)
This commit is contained in:
parent
8ab04ba075
commit
379f0a9cc1
|
@ -11,5 +11,5 @@ import net.sourceforge.filebot.similarity.Match;
|
|||
|
||||
interface AutoCompleteMatcher {
|
||||
|
||||
List<Match<File, ?>> match(List<File> files, Locale locale) throws Exception;
|
||||
List<Match<File, ?>> match(List<File> files, Locale locale, boolean autodetection) throws Exception;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
package net.sourceforge.filebot.ui.panel.rename;
|
||||
|
||||
|
||||
import static java.util.Collections.*;
|
||||
import static javax.swing.JOptionPane.*;
|
||||
import static net.sourceforge.filebot.MediaTypes.*;
|
||||
import static net.sourceforge.tuned.FileUtilities.*;
|
||||
import static net.sourceforge.tuned.ui.TunedUtilities.*;
|
||||
|
@ -48,12 +50,23 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
}
|
||||
|
||||
|
||||
protected Collection<String> detectSeriesNames(Collection<File> files) {
|
||||
// detect series name(s) from files
|
||||
Collection<String> names = new SeriesNameMatcher().matchAll(files.toArray(new File[0]));
|
||||
protected Collection<String> grabSeriesNames(Collection<File> files, boolean autodetect) {
|
||||
Collection<String> names = null;
|
||||
|
||||
if (names.isEmpty())
|
||||
throw new IllegalArgumentException("Cannot determine series name.");
|
||||
// auto-detect series name(s) from files
|
||||
if (autodetect) {
|
||||
names = new SeriesNameMatcher().matchAll(files.toArray(new File[0]));
|
||||
}
|
||||
|
||||
// require user input if auto-detection fails
|
||||
if (names == null || names.isEmpty()) {
|
||||
String suggestion = new SeriesNameMatcher().matchBySeasonEpisodePattern(getName(files.iterator().next()));
|
||||
String input = showInputDialog(null, "Enter series name:", suggestion);
|
||||
|
||||
if (input != null) {
|
||||
names = singleton(input);
|
||||
}
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
@ -159,12 +172,12 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
|
||||
|
||||
@Override
|
||||
public List<Match<File, ?>> match(final List<File> files, Locale locale) throws Exception {
|
||||
public List<Match<File, ?>> match(final List<File> files, Locale locale, boolean autodetection) throws Exception {
|
||||
// focus on movie and subtitle files
|
||||
List<File> mediaFiles = FileUtilities.filter(files, VIDEO_FILES, SUBTITLE_FILES);
|
||||
|
||||
// detect series name and fetch episode list
|
||||
Set<Episode> episodes = fetchEpisodeSet(detectSeriesNames(mediaFiles), locale);
|
||||
Set<Episode> episodes = fetchEpisodeSet(grabSeriesNames(mediaFiles, autodetection), locale);
|
||||
|
||||
List<Match<File, ?>> matches = new ArrayList<Match<File, ?>>();
|
||||
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
package net.sourceforge.filebot.ui.panel.rename;
|
||||
|
||||
|
||||
import static javax.swing.JOptionPane.*;
|
||||
import static net.sourceforge.filebot.MediaTypes.*;
|
||||
import static net.sourceforge.tuned.FileUtilities.*;
|
||||
import static net.sourceforge.tuned.ui.TunedUtilities.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -45,21 +47,26 @@ class MovieHashMatcher implements AutoCompleteMatcher {
|
|||
|
||||
|
||||
@Override
|
||||
public List<Match<File, ?>> match(final List<File> files, Locale locale) throws Exception {
|
||||
public List<Match<File, ?>> match(final List<File> files, Locale locale, boolean autodetect) throws Exception {
|
||||
// handle movie files
|
||||
File[] movieFiles = filter(files, VIDEO_FILES).toArray(new File[0]);
|
||||
MovieDescriptor[] movieDescriptors = service.getMovieDescriptors(movieFiles, locale);
|
||||
MovieDescriptor[] movieByFileHash = new MovieDescriptor[movieFiles.length];
|
||||
|
||||
// match movie hashes online
|
||||
if (autodetect) {
|
||||
movieByFileHash = service.getMovieDescriptors(movieFiles, locale);
|
||||
}
|
||||
|
||||
// map movies to (possibly multiple) files (in natural order)
|
||||
Map<MovieDescriptor, SortedSet<File>> filesByMovie = new HashMap<MovieDescriptor, SortedSet<File>>();
|
||||
|
||||
// map all files by movie
|
||||
for (int i = 0; i < movieFiles.length; i++) {
|
||||
MovieDescriptor movie = movieDescriptors[i];
|
||||
MovieDescriptor movie = movieByFileHash[i];
|
||||
|
||||
// unknown hash, try via imdb id from nfo file
|
||||
if (movie == null) {
|
||||
movie = determineMovie(movieFiles[i], locale);
|
||||
movie = grabMovieName(movieFiles[i], locale, autodetect);
|
||||
}
|
||||
|
||||
// check if we managed to lookup the movie descriptor
|
||||
|
@ -119,17 +126,17 @@ class MovieHashMatcher implements AutoCompleteMatcher {
|
|||
}
|
||||
|
||||
|
||||
protected Set<Integer> grepImdbId(File... files) throws IOException {
|
||||
private Set<Integer> grepImdbId(File... files) throws IOException {
|
||||
Set<Integer> collection = new HashSet<Integer>();
|
||||
|
||||
for (File file : files) {
|
||||
Scanner scanner = new Scanner(file);
|
||||
Scanner scanner = new Scanner(new FileInputStream(file));
|
||||
|
||||
try {
|
||||
// scan for imdb id patterns like tt1234567
|
||||
String imdb = null;
|
||||
|
||||
while ((imdb = scanner.findWithinHorizon("(?<=tt)\\d{7}", 32 * 1024)) != null) {
|
||||
while ((imdb = scanner.findWithinHorizon("(?<=tt)\\d{7}", 64 * 1024)) != null) {
|
||||
collection.add(Integer.parseInt(imdb));
|
||||
}
|
||||
} finally {
|
||||
|
@ -141,7 +148,12 @@ class MovieHashMatcher implements AutoCompleteMatcher {
|
|||
}
|
||||
|
||||
|
||||
protected MovieDescriptor determineMovie(File movieFile, Locale locale) throws Exception {
|
||||
private String normalizeMovieName(File movie) {
|
||||
return getName(movie).replaceAll("\\p{Punct}+", " ").trim();
|
||||
}
|
||||
|
||||
|
||||
protected MovieDescriptor grabMovieName(File movieFile, Locale locale, boolean autodetect) throws Exception {
|
||||
List<MovieDescriptor> options = new ArrayList<MovieDescriptor>();
|
||||
|
||||
// try to grep imdb id from nfo files
|
||||
|
@ -153,15 +165,20 @@ class MovieHashMatcher implements AutoCompleteMatcher {
|
|||
}
|
||||
}
|
||||
|
||||
// search by file name
|
||||
if (options.isEmpty()) {
|
||||
String query = getName(movieFile).replaceAll("\\p{Punct}+", " ").trim();
|
||||
options = service.searchMovie(query, locale);
|
||||
// search by file name or folder name
|
||||
for (File it : new File[] { movieFile, movieFile.getParentFile() }) {
|
||||
if (autodetect && options.isEmpty()) {
|
||||
options = service.searchMovie(normalizeMovieName(it), locale);
|
||||
}
|
||||
}
|
||||
|
||||
// search by folder name
|
||||
if (options.isEmpty()) {
|
||||
query = getName(movieFile.getParentFile()).replaceAll("\\p{Punct}+", " ").trim();
|
||||
options = service.searchMovie(query, locale);
|
||||
// allow manual user input
|
||||
if (options.isEmpty() || !autodetect) {
|
||||
String suggestion = options.isEmpty() ? normalizeMovieName(movieFile) : options.get(0).getName();
|
||||
String input = showInputDialog(null, "Enter movie name:", suggestion);
|
||||
|
||||
if (input != null) {
|
||||
options = service.searchMovie(input, locale);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -327,7 +327,7 @@ public class RenamePanel extends JComponent {
|
|||
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
public void actionPerformed(final ActionEvent evt) {
|
||||
// auto-match in progress
|
||||
namesList.firePropertyChange(LOADING_PROPERTY, false, true);
|
||||
|
||||
|
@ -338,11 +338,12 @@ public class RenamePanel extends JComponent {
|
|||
|
||||
private final List<File> remainingFiles = new LinkedList<File>(renameModel.files());
|
||||
private final Locale locale = new Locale(persistentPreferredLanguage.getValue());
|
||||
private final boolean autodetection = !isShiftDown(evt); // skip name auto-detection if SHIFT is pressed
|
||||
|
||||
|
||||
@Override
|
||||
protected List<Match<File, ?>> doInBackground() throws Exception {
|
||||
List<Match<File, ?>> matches = matcher.match(remainingFiles, locale);
|
||||
List<Match<File, ?>> matches = matcher.match(remainingFiles, locale, autodetection);
|
||||
|
||||
// remove matched files
|
||||
for (Match<File, ?> match : matches) {
|
||||
|
|
|
@ -11,11 +11,6 @@ public class MovieDescriptor extends SearchResult {
|
|||
private final int imdbId;
|
||||
|
||||
|
||||
public MovieDescriptor(String name, int imdbId) {
|
||||
this(name, -1, imdbId);
|
||||
}
|
||||
|
||||
|
||||
public MovieDescriptor(String name, int year, int imdbId) {
|
||||
super(name);
|
||||
|
||||
|
|
|
@ -18,6 +18,10 @@ import java.util.Map;
|
|||
import java.util.NoSuchElementException;
|
||||
import java.util.Scanner;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.DeflaterInputStream;
|
||||
|
||||
import redstone.xmlrpc.XmlRpcClient;
|
||||
|
@ -123,11 +127,22 @@ public class OpenSubtitlesXmlRpc {
|
|||
List<Map<String, String>> movieData = (List<Map<String, String>>) response.get("data");
|
||||
List<MovieDescriptor> movies = new ArrayList<MovieDescriptor>();
|
||||
|
||||
for (Map<String, String> movie : movieData) {
|
||||
// get non-aka title (aka titles were separated by Â, and then aka later on)
|
||||
Scanner titleScanner = new Scanner(movie.get("title")).useDelimiter("(\u00C2)|(\\s+aka\\s+)");
|
||||
// title pattern
|
||||
Pattern pattern = Pattern.compile("(.+)[(](\\d{4})[)]");
|
||||
|
||||
movies.add(new MovieDescriptor(titleScanner.next().trim(), Integer.parseInt(movie.get("id"))));
|
||||
for (Map<String, String> movie : movieData) {
|
||||
// match movie name and movie year from search result
|
||||
Matcher matcher = pattern.matcher(movie.get("title"));
|
||||
|
||||
if (matcher.find()) {
|
||||
String name = matcher.group(1).trim();
|
||||
int year = Integer.parseInt(matcher.group(2));
|
||||
int imdbid = Integer.parseInt(movie.get("id"));
|
||||
|
||||
movies.add(new MovieDescriptor(name, year, imdbid));
|
||||
} else {
|
||||
Logger.getLogger(OpenSubtitlesXmlRpc.class.getName()).log(Level.WARNING, "Error parsing title: " + movie);
|
||||
}
|
||||
}
|
||||
|
||||
return movies;
|
||||
|
|
|
@ -49,6 +49,16 @@ public final class TunedUtilities {
|
|||
}
|
||||
|
||||
|
||||
public static boolean isShiftDown(ActionEvent evt) {
|
||||
return checkModifiers(evt.getModifiers(), ActionEvent.SHIFT_MASK);
|
||||
}
|
||||
|
||||
|
||||
public static boolean checkModifiers(int modifiers, int mask) {
|
||||
return ((modifiers & mask) == mask);
|
||||
}
|
||||
|
||||
|
||||
public static JButton createImageButton(Action action) {
|
||||
JButton button = new JButton(action);
|
||||
button.setHideActionText(true);
|
||||
|
|
|
@ -35,11 +35,11 @@ public class OpenSubtitlesXmlRpcTest {
|
|||
@Test
|
||||
public void search() throws Exception {
|
||||
List<MovieDescriptor> list = xmlrpc.searchMoviesOnIMDB("babylon 5");
|
||||
|
||||
MovieDescriptor sample = (MovieDescriptor) list.get(0);
|
||||
|
||||
// check sample entry
|
||||
assertEquals("\"Babylon 5\" (1994)", sample.getName());
|
||||
assertEquals("\"Babylon 5\"", sample.getName());
|
||||
assertEquals(1994, sample.getYear());
|
||||
assertEquals(105946, sample.getImdbId());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue