From fd69647f9b69d8862c1be0910e877b8cbbb98272 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Tue, 9 Apr 2019 23:26:44 +0200 Subject: [PATCH] BasicSearchable --- .../fanfix/searchable/BasicSearchable.java | 199 ++++++++++++++++++ .../fanfix/searchable/SearchableTag.java | 178 ++++++++++++++++ 2 files changed, 377 insertions(+) create mode 100644 src/be/nikiroo/fanfix/searchable/BasicSearchable.java create mode 100644 src/be/nikiroo/fanfix/searchable/SearchableTag.java diff --git a/src/be/nikiroo/fanfix/searchable/BasicSearchable.java b/src/be/nikiroo/fanfix/searchable/BasicSearchable.java new file mode 100644 index 0000000..25c388a --- /dev/null +++ b/src/be/nikiroo/fanfix/searchable/BasicSearchable.java @@ -0,0 +1,199 @@ +package be.nikiroo.fanfix.searchable; + +import java.io.IOException; +import java.net.URL; +import java.util.List; + +import org.jsoup.helper.DataUtil; +import org.jsoup.nodes.Document; + +import be.nikiroo.fanfix.Instance; +import be.nikiroo.fanfix.data.MetaData; +import be.nikiroo.fanfix.supported.BasicSupport; +import be.nikiroo.fanfix.supported.SupportType; + +/** + * This class supports browsing through stories on the supported websites. It + * will fetch some {@link MetaData} that satisfy a search query or some tags if + * supported. + * + * @author niki + */ +public abstract class BasicSearchable { + private SupportType type; + private BasicSupport support; + + /** + * Create a new {@link BasicSearchable} of the given type. + * + * @param type + * the type, must not be NULL + */ + public BasicSearchable(SupportType type) { + setType(type); + support = BasicSupport.getSupport(getType(), null); + } + + /** + * The support type. + * + * @return the type + */ + public SupportType getType() { + return type; + } + + /** + * The support type. + * + * @param type + * the new type + */ + protected void setType(SupportType type) { + this.type = type; + } + + /** + * The associated {@link BasicSupport}. + *

+ * Mostly used to download content. + * + * @return the support + */ + protected BasicSupport getSupport() { + return support; + } + + /** + * Get a list of tags that can be browsed here. + * + * @return the list of tags + * + * @throws IOException + * in case of I/O error + */ + abstract public List getTags() throws IOException; + + /** + * Fill the tag (set it 'complete') with more information from the support. + * + * @param tag + * the tag to fill + * + * @throws IOException + * in case of I/O error + */ + abstract protected void fillTag(SearchableTag tag) throws IOException; + + /** + * Search for the given term and return a list of stories satisfying this + * search term. + *

+ * Not that the returned stories will NOT be complete, but will only + * contain enough information to present them to the user and retrieve them. + *

+ * URL is guaranteed to be usable, LUID will always be NULL. + * + * @param search + * the term to search for + * + * @return a list of stories that satisfy that search term + * + * @throws IOException + * in case of I/O error + */ + abstract public List search(String search) throws IOException; + + /** + * Search for the given tag and return a list of stories satisfying this + * tag. + *

+ * Not that the returned stories will NOT be complete, but will only + * contain enough information to present them to the user and retrieve them. + *

+ * URL is guaranteed to be usable, LUID will always be NULL. + * + * @param tagId + * the tag to search for + * + * @return a list of stories that satisfy that search term + * + * @throws IOException + * in case of I/O error + */ + abstract public List search(SearchableTag tag) throws IOException; + + /** + * Load a document from its url. + * + * @param url + * the URL to load + * @return the document + * + * @throws IOException + * in case of I/O error + */ + protected Document load(String url) throws IOException { + return load(new URL(url)); + } + + /** + * Load a document from its url. + * + * @param url + * the URL to load + * @return the document + * + * @throws IOException + * in case of I/O error + */ + protected Document load(URL url) throws IOException { + return DataUtil.load(Instance.getCache().open(url, support, false), + "UTF-8", url.toString()); + } + + /** + * Return a {@link BasicSearchable} implementation supporting the given + * type, or NULL if it does not exist. + * + * @param type + * the type, must not be NULL + * + * @return an implementation that supports it, or NULL + */ + public static BasicSearchable getSearchable(SupportType type) { + BasicSearchable support = null; + + switch (type) { + case FIMFICTION: + // TODO + break; + case FANFICTION: + support = new Fanfiction(type); + break; + case MANGAFOX: + // TODO + break; + case E621: + // TODO + break; + case YIFFSTAR: + // TODO + break; + case E_HENTAI: + // TODO + break; + case MANGA_LEL: + // TODO + break; + case CBZ: + case HTML: + case INFO_TEXT: + case TEXT: + case EPUB: + break; + } + + return support; + } +} diff --git a/src/be/nikiroo/fanfix/searchable/SearchableTag.java b/src/be/nikiroo/fanfix/searchable/SearchableTag.java new file mode 100644 index 0000000..c877bd7 --- /dev/null +++ b/src/be/nikiroo/fanfix/searchable/SearchableTag.java @@ -0,0 +1,178 @@ +package be.nikiroo.fanfix.searchable; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents a tag that can be searched on a supported website. + * + * @author niki + */ +public class SearchableTag { + private String id; + private String name; + private boolean complete; + private long count; + private List children; + + /** + * Create a new {@link SearchableTag}. + * + * @param id + * the ID (usually a way to find the linked stories later on) + * @param name + * the tag name, which can be displayed to the user + * @param complete + * TRUE for a {@link SearchableTag} that cannot be "filled" by + * the {@link BasicSearchable} in order to get (more?) subtag + * children + */ + public SearchableTag(String id, String name, boolean complete) { + this.id = id; + this.name = name; + this.complete = complete; + + children = new ArrayList(); + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + /** + * This tag can still be completed via a "fill" tag operation from a + * {@link BasicSearchable}, in order to gain (more?) subtag children. + * + * @return TRUE if it can + */ + public boolean isComplete() { + return complete; + } + + /** + * This tag can still be completed via a "fill" tag operation from a + * {@link BasicSearchable}, in order to gain (more?) subtag children. + * + * @param complete + * TRUE if it can + */ + public void setComplete(boolean complete) { + this.complete = complete; + } + + /** + * The number of items that can be found with this tag if it is searched. + *

+ * Will report the number of subtags by default. + * + * @return the number of items + */ + public long getCount() { + long count = this.count; + if (count <= 0) { + count = children.size(); + } + + return count; + } + + /** + * The number of items that can be found with this tag if it is searched, + * displayable format. + *

+ * Will report the number of subtags by default. + * + * @return the number of items + */ + public String getCountDisplay() { + long count = this.count; + if (count <= 0) { + count = children.size(); + } + + if (count > 999999) { + return count / 1000000 + "M"; + } + + if (count > 2000) { + return count / 1000 + "k"; + } + + return Long.toString(count); + } + + /** + * The number of items that can be found with this tag if it is searched. + * + * @param count + * the new count + */ + public void setCount(long count) { + this.count = count; + } + + /** + * The subtag children of this {@link SearchableTag}. + *

+ * Never NULL. + *

+ * Note that if {@link SearchableTag#isComplete()} returns false, you can + * still fill (more?) subtag children with a {@link BasicSearchable}. + * + * @return the subtag children, never NULL + */ + public List getChildren() { + return children; + } + + /** + * Add the given {@link SearchableTag} as a subtag child. + * + * @param tag + * the tag to add + */ + public void add(SearchableTag tag) { + children.add(tag); + } + + /** + * Display a DEBUG {@link String} representation of this object. + */ + @Override + public String toString() { + String rep = name + " [" + id + "]"; + if (!complete) { + rep += "*"; + } + + if (getCount() > 0) { + rep += " (" + getCountDisplay() + ")"; + } + + if (!children.isEmpty()) { + String tags = ""; + int i = 1; + for (SearchableTag tag : children) { + if (!tags.isEmpty()) { + tags += ", "; + } + + if (i > 10) { + tags += "..."; + break; + } + + tags += tag; + i++; + } + + rep += ": " + tags; + } + + return rep; + } +} -- 2.27.0