Support Query->SearchResult persistent memory in Episode mode
This commit is contained in:
parent
6f7169e255
commit
74569a405f
|
@ -3,7 +3,7 @@
|
|||
Persistent disk store location
|
||||
-->
|
||||
<diskStore path="ehcache.disk.store.dir" />
|
||||
|
||||
|
||||
<!--
|
||||
Mandatory Default Cache configuration. These settings will be applied to caches
|
||||
created pragmatically using CacheManager.add(String cacheName)
|
||||
|
@ -17,7 +17,7 @@
|
|||
diskPersistent="false"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
|
||||
<!--
|
||||
Short-lived (24 hours) persistent disk cache for web responses
|
||||
-->
|
||||
|
@ -31,7 +31,7 @@
|
|||
diskPersistent="true"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
|
||||
<!--
|
||||
Long-lived (2 weeks) persistent disk cache for web responses
|
||||
-->
|
||||
|
@ -45,7 +45,7 @@
|
|||
diskPersistent="true"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
|
||||
<!--
|
||||
Long-lived (2 months) persistent disk cache for web responses (that can be updated via If-Modified or If-None-Match)
|
||||
-->
|
||||
|
@ -59,7 +59,7 @@
|
|||
diskPersistent="true"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
|
||||
<!--
|
||||
Very long-lived cache (4 months) anime/series lists, movie index, etc
|
||||
-->
|
||||
|
@ -73,11 +73,25 @@
|
|||
diskPersistent="true"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
|
||||
<!--
|
||||
Simple memory cache. Time to live is 4 months.
|
||||
-->
|
||||
<cache name="persistent-memory"
|
||||
maxElementsInMemory="100"
|
||||
maxElementsOnDisk="50000"
|
||||
eternal="false"
|
||||
timeToIdleSeconds="10512000"
|
||||
timeToLiveSeconds="10512000"
|
||||
overflowToDisk="true"
|
||||
diskPersistent="true"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Simple memory cache. Time to live is 2 hours.
|
||||
-->
|
||||
<cache name="ephemeral"
|
||||
<cache name="ephemeral-memory"
|
||||
maxElementsInMemory="50000"
|
||||
eternal="false"
|
||||
timeToIdleSeconds="7200"
|
||||
|
@ -86,5 +100,5 @@
|
|||
diskPersistent="false"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
|
||||
</ehcache>
|
||||
|
|
|
@ -10,7 +10,8 @@ import net.sf.ehcache.Element;
|
|||
|
||||
public class Cache {
|
||||
|
||||
public static final String EPHEMERAL = "ephemeral";
|
||||
public static final String EPHEMERAL = "ephemeral-memory";
|
||||
public static final String PERSISTENT = "persistent-memory";
|
||||
|
||||
public static Cache getCache(String name) {
|
||||
return new Cache(CacheManager.getInstance().getCache(name));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package net.filebot.ui;
|
||||
|
||||
import static java.awt.Cursor.*;
|
||||
import static net.filebot.util.ui.SwingUI.*;
|
||||
|
||||
import java.awt.Component;
|
||||
|
@ -13,6 +14,7 @@ import java.util.Collection;
|
|||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
|
@ -30,12 +32,17 @@ import net.miginfocom.swing.MigLayout;
|
|||
public class SelectDialog<T> extends JDialog {
|
||||
|
||||
private JLabel headerLabel = new JLabel();
|
||||
private JCheckBox autoRepeatCheckBox = new JCheckBox();
|
||||
|
||||
private JList list;
|
||||
|
||||
private Action selectedAction = null;
|
||||
|
||||
public SelectDialog(Component parent, Collection<? extends T> options) {
|
||||
this(parent, options, false, false);
|
||||
}
|
||||
|
||||
public SelectDialog(Component parent, Collection<? extends T> options, boolean autoRepeatEnabled, boolean autoRepeatSelected) {
|
||||
super(getWindow(parent), "Select", ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
|
@ -70,6 +77,16 @@ public class SelectDialog<T> extends JDialog {
|
|||
c.add(new JButton(selectAction), "align center, id select");
|
||||
c.add(new JButton(cancelAction), "gap unrel, id cancel");
|
||||
|
||||
// add repeat button
|
||||
if (autoRepeatEnabled) {
|
||||
autoRepeatCheckBox.setSelected(autoRepeatSelected);
|
||||
autoRepeatCheckBox.setToolTipText("Remember");
|
||||
autoRepeatCheckBox.setCursor(getPredefinedCursor(HAND_CURSOR));
|
||||
autoRepeatCheckBox.setIcon(ResourceManager.getIcon("button.repeat"));
|
||||
autoRepeatCheckBox.setSelectedIcon(ResourceManager.getIcon("button.repeat.selected"));
|
||||
c.add(autoRepeatCheckBox, "pos 1al select.y n select.y2");
|
||||
}
|
||||
|
||||
// set default size and location
|
||||
setMinimumSize(new Dimension(220, 240));
|
||||
setSize(new Dimension(240, 260));
|
||||
|
@ -86,6 +103,10 @@ public class SelectDialog<T> extends JDialog {
|
|||
return headerLabel;
|
||||
}
|
||||
|
||||
public JCheckBox getAutoRepeatCheckBox() {
|
||||
return autoRepeatCheckBox;
|
||||
}
|
||||
|
||||
public Action getSelectedAction() {
|
||||
return selectedAction;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import java.util.concurrent.RunnableFuture;
|
|||
import javax.swing.Action;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import net.filebot.Cache;
|
||||
import net.filebot.Settings;
|
||||
import net.filebot.similarity.CommonSequenceMatcher;
|
||||
import net.filebot.similarity.EpisodeMatcher;
|
||||
|
@ -58,13 +59,16 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
// only allow one fetch session at a time so later requests can make use of cached results
|
||||
private final Object providerLock = new Object();
|
||||
|
||||
// remember user selections
|
||||
private final Cache persistentSelectionMemory = Cache.getCache(Cache.PERSISTENT);
|
||||
|
||||
public EpisodeListMatcher(EpisodeListProvider provider, boolean useSeriesIndex, boolean useAnimeIndex) {
|
||||
this.provider = provider;
|
||||
this.useSeriesIndex = useSeriesIndex;
|
||||
this.useAnimeIndex = useAnimeIndex;
|
||||
}
|
||||
|
||||
protected SearchResult selectSearchResult(final String query, final List<SearchResult> searchResults, Map<String, SearchResult> selectionMemory, final Component parent) throws Exception {
|
||||
protected SearchResult selectSearchResult(final String query, final List<SearchResult> searchResults, Map<String, SearchResult> selectionMemory, boolean autodetection, final Component parent) throws Exception {
|
||||
if (searchResults.size() == 1) {
|
||||
return searchResults.get(0);
|
||||
}
|
||||
|
@ -83,7 +87,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
@Override
|
||||
public SearchResult call() throws Exception {
|
||||
// multiple results have been found, user must select one
|
||||
SelectDialog<SearchResult> selectDialog = new SelectDialog<SearchResult>(parent, searchResults);
|
||||
SelectDialog<SearchResult> selectDialog = new SelectDialog<SearchResult>(parent, searchResults, true, false);
|
||||
|
||||
selectDialog.getHeaderLabel().setText(String.format("Shows matching '%s':", query));
|
||||
selectDialog.getCancelAction().putValue(Action.NAME, "Ignore");
|
||||
|
@ -107,6 +111,11 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
throw new CancellationException("Cancelled by user");
|
||||
}
|
||||
|
||||
// remember if we should auto-repeat the chosen action in the future
|
||||
if (selectDialog.getAutoRepeatCheckBox().isSelected() && selectDialog.getSelectedValue() != null) {
|
||||
persistentSelectionMemory.put(query, selectDialog.getSelectedValue());
|
||||
}
|
||||
|
||||
// selected value or null if the dialog was canceled by the user
|
||||
return selectDialog.getSelectedValue();
|
||||
}
|
||||
|
@ -119,16 +128,26 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
return selectionMemory.get(query);
|
||||
}
|
||||
|
||||
SwingUtilities.invokeAndWait(showSelectDialog);
|
||||
// check persistent memory
|
||||
if (autodetection) {
|
||||
SearchResult persistentSelection = persistentSelectionMemory.get(query, SearchResult.class);
|
||||
if (persistentSelection != null) {
|
||||
return persistentSelection;
|
||||
}
|
||||
}
|
||||
|
||||
// cache selected value
|
||||
selectionMemory.put(query, showSelectDialog.get());
|
||||
return showSelectDialog.get();
|
||||
// ask user
|
||||
SwingUtilities.invokeAndWait(showSelectDialog);
|
||||
SearchResult userSelection = showSelectDialog.get();
|
||||
|
||||
// remember selected value
|
||||
selectionMemory.put(query, userSelection);
|
||||
return userSelection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Set<Episode> fetchEpisodeSet(Collection<String> seriesNames, final SortOrder sortOrder, final Locale locale, final Map<String, SearchResult> selectionMemory, final Component parent) throws Exception {
|
||||
protected Set<Episode> fetchEpisodeSet(Collection<String> seriesNames, final SortOrder sortOrder, final Locale locale, final Map<String, SearchResult> selectionMemory, final boolean autodetection, final Component parent) throws Exception {
|
||||
List<Callable<List<Episode>>> tasks = new ArrayList<Callable<List<Episode>>>();
|
||||
|
||||
// detect series names and create episode list fetch tasks
|
||||
|
@ -141,7 +160,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
|
||||
// select search result
|
||||
if (results.size() > 0) {
|
||||
SearchResult selectedSearchResult = selectSearchResult(query, results, selectionMemory, parent);
|
||||
SearchResult selectedSearchResult = selectSearchResult(query, results, selectionMemory, autodetection, parent);
|
||||
|
||||
if (selectedSearchResult != null) {
|
||||
return provider.getEpisodeList(selectedSearchResult, sortOrder, locale);
|
||||
|
@ -278,7 +297,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
if (queries != null && queries.size() > 0) {
|
||||
// only allow one fetch session at a time so later requests can make use of cached results
|
||||
synchronized (providerLock) {
|
||||
episodes = fetchEpisodeSet(queries, sortOrder, locale, selectionMemory, parent);
|
||||
episodes = fetchEpisodeSet(queries, sortOrder, locale, selectionMemory, autodetection, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -301,7 +320,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
if (input != null && input.size() > 0) {
|
||||
// only allow one fetch session at a time so later requests can make use of cached results
|
||||
synchronized (providerLock) {
|
||||
episodes = fetchEpisodeSet(input, sortOrder, locale, new HashMap<String, SearchResult>(), parent);
|
||||
episodes = fetchEpisodeSet(input, sortOrder, locale, new HashMap<String, SearchResult>(), false, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -374,7 +393,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
|
|||
List<Match<File, ?>> matches = new ArrayList<Match<File, ?>>();
|
||||
if (input.size() > 0) {
|
||||
synchronized (providerLock) {
|
||||
Set<Episode> episodes = fetchEpisodeSet(input, sortOrder, locale, new HashMap<String, SearchResult>(), parent);
|
||||
Set<Episode> episodes = fetchEpisodeSet(input, sortOrder, locale, new HashMap<String, SearchResult>(), false, parent);
|
||||
for (Episode it : episodes) {
|
||||
matches.add(new Match<File, Episode>(null, it));
|
||||
}
|
||||
|
|
|
@ -404,21 +404,12 @@ class MovieHashMatcher implements AutoCompleteMatcher {
|
|||
@Override
|
||||
public Movie call() throws Exception {
|
||||
// multiple results have been found, user must select one
|
||||
SelectDialog<Movie> selectDialog = new SelectDialog<Movie>(parent, options);
|
||||
SelectDialog<Movie> selectDialog = new SelectDialog<Movie>(parent, options, true, false);
|
||||
|
||||
selectDialog.setTitle(folderQuery.isEmpty() ? fileQuery : String.format("%s / %s", folderQuery, fileQuery));
|
||||
selectDialog.getHeaderLabel().setText(String.format("Movies matching '%s':", fileQuery.length() >= 2 || folderQuery.length() <= 2 ? fileQuery : folderQuery));
|
||||
selectDialog.getCancelAction().putValue(Action.NAME, "Ignore");
|
||||
|
||||
// add repeat button
|
||||
JCheckBox checkBox = new JCheckBox();
|
||||
checkBox.setToolTipText("Select / Ignore for all");
|
||||
checkBox.setCursor(getPredefinedCursor(HAND_CURSOR));
|
||||
checkBox.setIcon(ResourceManager.getIcon("button.repeat"));
|
||||
checkBox.setSelectedIcon(ResourceManager.getIcon("button.repeat.selected"));
|
||||
JComponent c = (JComponent) selectDialog.getContentPane();
|
||||
c.add(checkBox, "pos 1al select.y n select.y2");
|
||||
|
||||
// restore original dialog size
|
||||
Settings prefs = Settings.forPackage(MovieHashMatcher.class);
|
||||
int w = Integer.parseInt(prefs.get("dialog.select.w", "280"));
|
||||
|
@ -435,7 +426,7 @@ class MovieHashMatcher implements AutoCompleteMatcher {
|
|||
prefs.put("dialog.select.h", Integer.toString(selectDialog.getHeight()));
|
||||
|
||||
// remember if we should auto-repeat the chosen action in the future
|
||||
if (checkBox.isSelected() || selectDialog.getSelectedAction() == null) {
|
||||
if (selectDialog.getAutoRepeatCheckBox().isSelected() || selectDialog.getSelectedAction() == null) {
|
||||
memory.put("repeat", selectDialog.getSelectedValue() != null ? "select" : "ignore");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue