Initial work on keyword search
This commit is contained in:
parent
5149259970
commit
7eeb7d9bae
7 changed files with 234 additions and 32 deletions
|
|
@ -8,7 +8,6 @@ import java.io.FileInputStream;
|
|||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
|
|
@ -22,14 +21,13 @@ import org.forkalsrud.album.db.DirectoryProps;
|
|||
/**
|
||||
* @author knut
|
||||
*/
|
||||
public class DirectoryEntry extends Entry {
|
||||
public class DirectoryEntry extends EntryWithChildren {
|
||||
|
||||
final static String CACHE_FILE = "cache.properties";
|
||||
final static String OVERRIDE_FILE = "album.properties";
|
||||
|
||||
DirectoryDatabase db;
|
||||
DirectoryProps cache;
|
||||
List<Entry> children = new ArrayList<Entry>();
|
||||
boolean childrenLoaded = false;
|
||||
Comparator<Entry> sort = null;
|
||||
Date earliest = null;
|
||||
|
|
@ -53,14 +51,10 @@ public class DirectoryEntry extends Entry {
|
|||
|
||||
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Entry> getContents() {
|
||||
|
||||
loadChildren();
|
||||
return children;
|
||||
return super.getContents();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -75,18 +69,10 @@ public class DirectoryEntry extends Entry {
|
|||
return super.getCaption();
|
||||
}
|
||||
|
||||
public void addContents(Entry entry) {
|
||||
children.add(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry get(File f) {
|
||||
loadChildren();
|
||||
for (Entry e : children) {
|
||||
if (f.equals(e.file)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return super.get(f);
|
||||
}
|
||||
|
||||
protected synchronized void loadChildren() {
|
||||
|
|
@ -139,20 +125,6 @@ public class DirectoryEntry extends Entry {
|
|||
Collections.sort(children, sort);
|
||||
}
|
||||
|
||||
void fillLinkedList() {
|
||||
|
||||
Entry prev = null;
|
||||
for (Entry e : children) {
|
||||
e.prev = prev;
|
||||
if (prev != null) {
|
||||
prev.next = e;
|
||||
}
|
||||
prev = e;
|
||||
}
|
||||
if (prev != null) {
|
||||
prev.next = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void populate(DirectoryProps props) throws ParseException {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,18 @@ public abstract class Entry {
|
|||
this.file = file;
|
||||
}
|
||||
|
||||
protected Entry(Entry other) {
|
||||
this(other.file);
|
||||
this.thumbnail = other.thumbnail;
|
||||
this.caption = other.caption;
|
||||
this.date = other.date;
|
||||
/*
|
||||
this.next = other.next;
|
||||
this.prev = other.prev;
|
||||
this.parent = other.parent;
|
||||
*/
|
||||
}
|
||||
|
||||
public abstract boolean isFile();
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.forkalsrud.album.exif;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author knut
|
||||
*
|
||||
*/
|
||||
public class EntryWithChildren extends Entry {
|
||||
|
||||
protected List<Entry> children = new ArrayList<Entry>();
|
||||
|
||||
protected EntryWithChildren(Entry root) {
|
||||
super(root);
|
||||
}
|
||||
|
||||
protected EntryWithChildren(File path) {
|
||||
super(path);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.forkalsrud.album.exif.Entry#isFile()
|
||||
*/
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void fillLinkedList() {
|
||||
|
||||
Entry prev = null;
|
||||
for (Entry e : children) {
|
||||
e.prev = prev;
|
||||
if (prev != null) {
|
||||
prev.next = e;
|
||||
}
|
||||
prev = e;
|
||||
}
|
||||
if (prev != null) {
|
||||
prev.next = null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Entry> getContents() {
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
public void addContents(Entry entry) {
|
||||
children.add(entry);
|
||||
}
|
||||
|
||||
public Entry get(File f) {
|
||||
for (Entry e : children) {
|
||||
if (f.equals(e.file)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
58
src/main/java/org/forkalsrud/album/exif/SearchEngine.java
Normal file
58
src/main/java/org/forkalsrud/album/exif/SearchEngine.java
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package org.forkalsrud.album.exif;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class SearchEngine {
|
||||
|
||||
DirectoryEntry root;
|
||||
SearchResults results;
|
||||
LinkedList<DirectoryEntry> queue;
|
||||
|
||||
|
||||
public SearchEngine(DirectoryEntry root) {
|
||||
this.root = root;
|
||||
this.results = new SearchResults(root);
|
||||
this.queue = new LinkedList<DirectoryEntry>();
|
||||
this.queue.add(root);
|
||||
}
|
||||
|
||||
public SearchResults search(String query) {
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
DirectoryEntry next = queue.removeFirst();
|
||||
processDirectory(next, query);
|
||||
}
|
||||
results.fillLinkedList();
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
void processDirectory(DirectoryEntry dir, String query) {
|
||||
|
||||
tryAttribute(dir, dir.getName(), query);
|
||||
tryAttribute(dir, dir.getCaption(), query);
|
||||
tryAttribute(dir, dir.getPath().getAbsolutePath(), query);
|
||||
|
||||
for (Entry e : dir.getContents()) {
|
||||
if (!e.isFile()) {
|
||||
queue.add((DirectoryEntry)e);
|
||||
continue;
|
||||
}
|
||||
FileEntry file = (FileEntry)e;
|
||||
tryAttribute(file, file.getName(), query);
|
||||
tryAttribute(file, file.getCaption(), query);
|
||||
tryAttribute(file, file.getPath().getAbsolutePath(), query);
|
||||
}
|
||||
}
|
||||
|
||||
void tryAttribute(Entry entry, String attr, String query) {
|
||||
if (isMatch(attr, query)) {
|
||||
results.addMatch(entry);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isMatch(String candidate, String query) {
|
||||
return candidate != null && candidate.indexOf(query) >= 0;
|
||||
}
|
||||
|
||||
}
|
||||
23
src/main/java/org/forkalsrud/album/exif/SearchEntry.java
Normal file
23
src/main/java/org/forkalsrud/album/exif/SearchEntry.java
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package org.forkalsrud.album.exif;
|
||||
|
||||
|
||||
public class SearchEntry extends Entry {
|
||||
|
||||
protected int score;
|
||||
|
||||
protected SearchEntry(SearchResults parent, Entry entry) {
|
||||
super(entry);
|
||||
this.parent = parent;
|
||||
this.score = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addScore() {
|
||||
this.score += 1;
|
||||
}
|
||||
|
||||
}
|
||||
39
src/main/java/org/forkalsrud/album/exif/SearchResults.java
Normal file
39
src/main/java/org/forkalsrud/album/exif/SearchResults.java
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package org.forkalsrud.album.exif;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
public class SearchResults extends EntryWithChildren {
|
||||
|
||||
protected HashMap<File, SearchEntry> dupes = new HashMap<File, SearchEntry>();
|
||||
Comparator<SearchEntry> sort = new Comparator<SearchEntry>() {
|
||||
|
||||
public int compare(SearchEntry e1, SearchEntry e2) {
|
||||
|
||||
return Integer.valueOf(e2.score).compareTo(e1.score);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
protected SearchResults(DirectoryEntry root) {
|
||||
super(root);
|
||||
}
|
||||
|
||||
public void addMatch(Entry entry) {
|
||||
|
||||
File path = entry.getPath();
|
||||
SearchEntry existing = dupes.get(path);
|
||||
if (existing == null) {
|
||||
existing = new SearchEntry(this, entry);
|
||||
dupes.put(path, existing);
|
||||
children.add(existing);
|
||||
} else {
|
||||
existing.addScore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -27,6 +27,8 @@ import org.forkalsrud.album.db.ThumbnailDatabase;
|
|||
import org.forkalsrud.album.exif.DirectoryEntry;
|
||||
import org.forkalsrud.album.exif.Entry;
|
||||
import org.forkalsrud.album.exif.FileEntry;
|
||||
import org.forkalsrud.album.exif.SearchEngine;
|
||||
import org.forkalsrud.album.exif.SearchResults;
|
||||
import org.forkalsrud.album.exif.Thumbnail;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
|
|
@ -207,6 +209,12 @@ public class AlbumServlet
|
|||
handleEdit(req, res, (FileEntry)resolveEntry(pathInfo));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pathInfo.endsWith(".search")) {
|
||||
pathInfo = pathInfo.substring(0, pathInfo.length() - ".search".length());
|
||||
handleSearch(req, res, (DirectoryEntry)resolveEntry(pathInfo));
|
||||
return;
|
||||
}
|
||||
|
||||
File file = new File(base, pathInfo);
|
||||
if (!file.canRead()) {
|
||||
|
|
@ -283,6 +291,27 @@ public class AlbumServlet
|
|||
}
|
||||
}
|
||||
|
||||
void handleSearch(HttpServletRequest req, HttpServletResponse res, DirectoryEntry entry) {
|
||||
try {
|
||||
String query = req.getParameter("q");
|
||||
|
||||
SearchEngine search = new SearchEngine(entry);
|
||||
SearchResults results = search.search(query);
|
||||
|
||||
res.setContentType("text/html");
|
||||
req.setAttribute("entry", results);
|
||||
req.setAttribute("thmb", new Integer(250));
|
||||
req.setAttribute("full", new Integer(800));
|
||||
RequestDispatcher rd = req.getRequestDispatcher("/WEB-INF/velocity/photo.vm");
|
||||
rd.forward(req, res);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("sadness", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
boolean etagMatches(HttpServletRequest req, String fileEtag) {
|
||||
|
||||
String cacheControl = req.getHeader("Cache-Control");
|
||||
|
|
@ -401,6 +430,9 @@ public class AlbumServlet
|
|||
Calendar cal = Calendar.getInstance();
|
||||
|
||||
public String year(Date d) {
|
||||
if (d == null) {
|
||||
return "";
|
||||
}
|
||||
cal.setTime(d);
|
||||
return String.valueOf(cal.get(Calendar.YEAR));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue