import be.nikiroo.fanfix.data.Story;
import be.nikiroo.fanfix.library.web.WebLibraryServerIndex;
import be.nikiroo.fanfix.reader.TextOutput;
-import be.nikiroo.utils.CookieUtils;
import be.nikiroo.utils.IOUtils;
import be.nikiroo.utils.Image;
+import be.nikiroo.utils.LoginResult;
import be.nikiroo.utils.NanoHTTPD;
import be.nikiroo.utils.NanoHTTPD.IHTTPSession;
import be.nikiroo.utils.NanoHTTPD.Response;
import be.nikiroo.utils.Version;
public class WebLibraryServer implements Runnable {
- static private String VIEWER_URL_BASE = "/view/story/";
- static private String VIEWER_URL = VIEWER_URL_BASE + "{luid}/{chap}/{para}";
- static private String STORY_URL_BASE = "/story/";
- static private String STORY_URL = STORY_URL_BASE + "{luid}/{chap}/{para}";
- static private String STORY_URL_COVER = STORY_URL_BASE + "{luid}/cover";
- static private String LIST_URL = "/list/";
-
- private class LoginResult {
- private boolean success;
+ private class WLoginResult extends LoginResult {
private boolean rw;
private boolean wl;
- private String wookie;
- private String token;
- private boolean badLogin;
- private boolean badToken;
-
- public LoginResult(String who, String key, String subkey,
- boolean success, boolean rw, boolean wl) {
- this.success = success;
+ private boolean bl;
+
+ public WLoginResult(boolean badLogin, boolean badCookie) {
+ super(badLogin, badCookie);
+ }
+
+ public WLoginResult(String who, String key, String subkey, boolean rw,
+ boolean wl, boolean bl) {
+ super(who, key, subkey, (rw ? "|rw" : "") + (wl ? "|wl" : "")
+ + (bl ? "|bl" : "") + "|");
this.rw = rw;
this.wl = wl;
- this.wookie = CookieUtils.generateCookie(who + key, 0);
-
- String opts = "";
- if (rw)
- opts += "|rw";
- if (!wl)
- opts += "|wl";
-
- this.token = wookie + "~"
- + CookieUtils.generateCookie(wookie + subkey + opts, 0)
- + "~" + opts;
- this.badLogin = !success;
+ this.bl = bl;
}
- public LoginResult(String token, String who, String key,
+ public WLoginResult(String cookie, String who, String key,
List<String> subkeys) {
-
- if (token != null) {
- String hashes[] = token.split("~");
- if (hashes.length >= 2) {
- String wookie = hashes[0];
- String rehashed = hashes[1];
- String opts = hashes.length > 2 ? hashes[2] : "";
-
- if (CookieUtils.validateCookie(who + key, wookie)) {
- if (subkeys == null) {
- subkeys = new ArrayList<String>();
- }
- subkeys = new ArrayList<String>(subkeys);
- subkeys.add("");
-
- for (String subkey : subkeys) {
- if (CookieUtils.validateCookie(
- wookie + subkey + opts, rehashed)) {
- this.wookie = wookie;
- this.token = token;
- this.success = true;
-
- this.rw = opts.contains("|rw");
- this.wl = !opts.contains("|wl");
- }
- }
- }
- }
-
- this.badToken = !success;
- }
-
- // No token -> no bad token
- }
-
- public boolean isSuccess() {
- return success;
+ super(cookie, who, key, subkeys,
+ subkeys == null || subkeys.isEmpty());
}
public boolean isRw() {
- return rw;
+ return getOption().contains("|rw|");
}
public boolean isWl() {
- return wl;
+ return getOption().contains("|wl|");
}
- public String getToken() {
- return token;
- }
-
- public boolean isBadLogin() {
- return badLogin;
- }
-
- public boolean isBadToken() {
- return badToken;
+ public boolean isBl() {
+ return getOption().contains("|bl|");
}
}
private long maxStoryCacheSize;
private TraceHandler tracer = new TraceHandler();
+ private List<String> whitelist;
+ private List<String> blacklist;
+
public WebLibraryServer(boolean secure) throws IOException {
Integer port = Instance.getInstance().getConfig()
.getInteger(Config.SERVER_PORT);
setTraceHandler(Instance.getInstance().getTraceHandler());
+ whitelist = Instance.getInstance().getConfig()
+ .getList(Config.SERVER_WHITELIST, new ArrayList<String>());
+ blacklist = Instance.getInstance().getConfig()
+ .getList(Config.SERVER_BLACKLIST, new ArrayList<String>());
+
SSLServerSocketFactory ssf = null;
if (secure) {
String keystorePath = Instance.getInstance().getConfig()
cookies.put(cookie, session.getCookies().read(cookie));
}
- List<String> whitelist = Instance.getInstance().getConfig()
- .getList(Config.SERVER_WHITELIST);
- if (whitelist == null) {
- whitelist = new ArrayList<String>();
- }
-
- LoginResult login = null;
+ WLoginResult login = null;
Map<String, String> params = session.getParms();
String who = session.getRemoteHostName()
+ session.getRemoteIpAddress();
if (params.get("login") != null) {
login = login(who, params.get("password"),
- params.get("login"), whitelist);
+ params.get("login"));
} else {
- String token = cookies.get("token");
- login = login(who, token, Instance.getInstance().getConfig()
- .getList(Config.SERVER_ALLOWED_SUBKEYS));
+ String cookie = cookies.get("cookie");
+ login = login(who, cookie);
}
if (login.isSuccess()) {
- if (!login.isWl()) {
- whitelist.clear();
- }
-
- // refresh token
- session.getCookies().set(new Cookie("token",
- login.getToken(), "30; path=/"));
+ // refresh cookie
+ session.getCookies().set(new Cookie("cookie",
+ login.getCookie(), "30; path=/"));
// set options
String optionName = params.get("optionName");
if (optionName != null && !optionName.isEmpty()) {
+ String optionNo = params.get("optionNo");
String optionValue = params.get("optionValue");
- if (optionValue == null || optionValue.isEmpty()) {
+ if (optionNo != null || optionValue == null
+ || optionValue.isEmpty()) {
session.getCookies().delete(optionName);
cookies.remove(optionName);
} else {
}
Response rep = null;
- if (!login.isSuccess() && (uri.equals("/") //
- || uri.startsWith(STORY_URL_BASE) //
- || uri.startsWith(VIEWER_URL_BASE) //
- || uri.startsWith(LIST_URL))) {
+ if (!login.isSuccess() && WebLibraryUrls.isSupportedUrl(uri)) {
rep = loginPage(login, uri);
}
if (rep == null) {
try {
- if (uri.equals("/")) {
- rep = root(session, cookies, whitelist);
- } else if (uri.startsWith(LIST_URL)) {
- rep = getList(uri, whitelist);
- } else if (uri.startsWith(STORY_URL_BASE)) {
- rep = getStoryPart(uri, whitelist);
- } else if (uri.startsWith(VIEWER_URL_BASE)) {
- rep = getViewer(cookies, uri, whitelist);
- } else if (uri.equals("/logout")) {
- session.getCookies().delete("token");
- cookies.remove("token");
- rep = loginPage(login, uri);
+ if (WebLibraryUrls.isSupportedUrl(uri)) {
+ if (WebLibraryUrls.INDEX_URL.equals(uri)) {
+ rep = root(session, cookies, login);
+ } else if (WebLibraryUrls.VERSION_URL.equals(uri)) {
+ rep = newFixedLengthResponse(Status.OK,
+ MIME_PLAINTEXT,
+ Version.getCurrentVersion().toString());
+ } else if (WebLibraryUrls.isListUrl(uri)) {
+ rep = getList(uri, login);
+ } else if (WebLibraryUrls.isStoryUrl(uri)) {
+ rep = getStoryPart(uri, login);
+ } else if (WebLibraryUrls.isViewUrl(uri)) {
+ rep = getViewer(cookies, uri, login);
+ } else if (WebLibraryUrls.LOGOUT_URL.equals(uri)) {
+ session.getCookies().delete("cookie");
+ cookies.remove("cookie");
+ rep = loginPage(new WLoginResult(false, false),
+ uri);
+ } else {
+ getTraceHandler().error(
+ "Supported URL was not processed: "
+ + uri);
+ rep = newFixedLengthResponse(
+ Status.INTERNAL_ERROR,
+ NanoHTTPD.MIME_PLAINTEXT,
+ "An error happened");
+ }
} else {
if (uri.startsWith("/"))
uri = uri.substring(1);
}
rep = newChunkedResponse(Status.OK, mimeType,
in);
- } else {
- getTraceHandler().trace("404: " + uri);
}
- }
- if (rep == null) {
- rep = newFixedLengthResponse(Status.NOT_FOUND,
- NanoHTTPD.MIME_PLAINTEXT, "Not Found");
+ if (rep == null) {
+ getTraceHandler().trace("404: " + uri);
+ rep = newFixedLengthResponse(Status.NOT_FOUND,
+ NanoHTTPD.MIME_PLAINTEXT, "Not Found");
+ }
}
} catch (Exception e) {
Instance.getInstance().getTraceHandler().error(
}
return rep;
-
- // Get status: for story, use "luid" + active map of current
- // luids
- // map must use a addRef/removeRef and delete at 0
-
- // http://localhost:2000/?token=ok
-
- //
- // MetaData meta = new MetaData();
- // meta.setTitle("Title");
- // meta.setLuid("000");
- //
- // JSONObject json = new JSONObject();
- // json.put("", MetaData.class.getName());
- // json.put("title", meta.getTitle());
- // json.put("luid", meta.getLuid());
- //
- // return newFixedLengthResponse(json.toString());
}
};
this.tracer = tracer;
}
- private LoginResult login(String who, String token, List<String> subkeys) {
+ private WLoginResult login(String who, String cookie) {
+ List<String> subkeys = Instance.getInstance().getConfig()
+ .getList(Config.SERVER_ALLOWED_SUBKEYS);
String realKey = Instance.getInstance().getConfig()
.getString(Config.SERVER_KEY);
- realKey = realKey == null ? "" : realKey;
- return new LoginResult(token, who, realKey, subkeys);
+
+ return new WLoginResult(cookie, who, realKey, subkeys);
}
// allow rw/wl
- private LoginResult login(String who, String key, String subkey,
- List<String> whitelist) {
+ private WLoginResult login(String who, String key, String subkey) {
String realKey = Instance.getInstance().getConfig()
- .getString(Config.SERVER_KEY);
+ .getString(Config.SERVER_KEY, "");
// I don't like NULLs...
- realKey = realKey == null ? "" : realKey;
key = key == null ? "" : key;
subkey = subkey == null ? "" : subkey;
if (!realKey.equals(key)) {
- return new LoginResult(null, null, null, false, false, false);
+ return new WLoginResult(true, false);
}
- // defaults are positive (as previous versions without the feature)
+ // defaults are true (as previous versions without the feature)
boolean rw = true;
boolean wl = true;
-
- if (whitelist.isEmpty()) {
- wl = false;
- }
+ boolean bl = true;
rw = Instance.getInstance().getConfig().getBoolean(Config.SERVER_RW,
rw);
- if (!subkey.isEmpty()) {
- List<String> allowed = Instance.getInstance().getConfig()
- .getList(Config.SERVER_ALLOWED_SUBKEYS);
- if (allowed != null && allowed.contains(subkey)) {
- if ((subkey + "|").contains("|rw|")) {
- rw = true;
- }
- if ((subkey + "|").contains("|wl|")) {
- wl = false; // |wl| = bypass whitelist
- }
- } else {
- return new LoginResult(null, null, null, false, false, false);
+
+ List<String> allowed = Instance.getInstance().getConfig().getList(
+ Config.SERVER_ALLOWED_SUBKEYS, new ArrayList<String>());
+
+ if (!allowed.isEmpty()) {
+ if (!allowed.contains(subkey)) {
+ return new WLoginResult(true, false);
+ }
+
+ if ((subkey + "|").contains("|rw|")) {
+ rw = true;
+ }
+ if ((subkey + "|").contains("|wl|")) {
+ wl = false; // |wl| = bypass whitelist
+ }
+ if ((subkey + "|").contains("|bl|")) {
+ bl = false; // |bl| = bypass blacklist
}
}
- return new LoginResult(who, key, subkey, true, rw, wl);
+ return new WLoginResult(who, key, subkey, rw, wl, bl);
}
- private Response loginPage(LoginResult login, String uri) {
+ private Response loginPage(WLoginResult login, String uri) {
StringBuilder builder = new StringBuilder();
appendPreHtml(builder, true);
if (login.isBadLogin()) {
builder.append("<div class='error'>Bad login or password</div>");
- } else if (login.isBadToken()) {
+ } else if (login.isBadCookie()) {
builder.append("<div class='error'>Your session timed out</div>");
}
- if (uri.equals("/logout")) {
- uri = "/";
+ if (WebLibraryUrls.LOGOUT_URL.equals(uri)) {
+ uri = WebLibraryUrls.INDEX_URL;
}
builder.append(
NanoHTTPD.MIME_HTML, builder.toString());
}
- protected Response getList(String uri, List<String> whitelist)
+ protected Response getList(String uri, WLoginResult login)
throws IOException {
- if (uri.equals("/list/luids")) {
- BasicLibrary lib = Instance.getInstance().getLibrary();
- List<MetaData> metas = lib.getList().filter(whitelist, null, null);
+ if (WebLibraryUrls.LIST_URL_METADATA.equals(uri)) {
List<JSONObject> jsons = new ArrayList<JSONObject>();
- for (MetaData meta : metas) {
+ for (MetaData meta : metas(login)) {
jsons.add(JsonIO.toJson(meta));
}
}
private Response root(IHTTPSession session, Map<String, String> cookies,
- List<String> whitelist) throws IOException {
+ WLoginResult login) throws IOException {
BasicLibrary lib = Instance.getInstance().getLibrary();
- MetaResultList result = lib.getList();
- result = new MetaResultList(result.filter(whitelist, null, null));
+ MetaResultList result = new MetaResultList(metas(login));
StringBuilder builder = new StringBuilder();
appendPreHtml(builder, true);
+ Map<String, String> params = session.getParms();
+
String filter = cookies.get("filter");
+ if (params.get("optionNo") != null)
+ filter = null;
if (filter == null) {
filter = "";
}
- Map<String, String> params = session.getParms();
String browser = params.get("browser") == null ? ""
: params.get("browser");
String browser2 = params.get("browser2") == null ? ""
// TODO: javascript in realtime, using visible=false + hide [submit]
builder.append("<div class='filter'>\n");
- builder.append("\tFilter: \n");
+ builder.append("\t<span class='label'>Filter: </span>\n");
builder.append(
"\t<input name='optionName' type='hidden' value='filter' />\n");
builder.append("\t<input name='optionValue' type='text' value='"
+ filter + "' place-holder='...' />\n");
+ builder.append("\t<input name='optionNo' type='submit' value='x' />");
builder.append(
"\t<input name='submit' type='submit' value='Filter' />\n");
builder.append("</div>\n");
builder.append("<div class='book_line'>");
builder.append("<a href='");
- builder.append(getViewUrl(meta.getLuid(), 0, null));
+ builder.append(
+ WebLibraryUrls.getViewUrl(meta.getLuid(), null, null));
builder.append("'");
builder.append(" class='link'>");
// /story/luid/cover <-- image
// /story/luid/metadata <-- json
// /story/luid/json <-- json, whole chapter (no images)
- private Response getStoryPart(String uri, List<String> whitelist) {
+ private Response getStoryPart(String uri, WLoginResult login) {
String[] cover = uri.split("/");
int off = 2;
// 1-based (0 = desc)
int chapter = 0;
if (chapterStr != null && !"cover".equals(chapterStr)
- && !"metadata".equals(chapterStr) && !"json".equals(chapterStr)) {
+ && !"metadata".equals(chapterStr)
+ && !"json".equals(chapterStr)) {
try {
chapter = Integer.parseInt(chapterStr);
if (chapter < 0) {
InputStream in = null;
try {
if ("cover".equals(chapterStr)) {
- Image img = getCover(luid, whitelist);
+ Image img = getCover(luid, login);
if (img != null) {
in = img.newInputStream();
}
+ // TODO: get correct image type
+ mimeType = "image/png";
} else if ("metadata".equals(chapterStr)) {
- MetaData meta = meta(luid, whitelist);
+ MetaData meta = meta(luid, login);
JSONObject json = JsonIO.toJson(meta);
mimeType = "application/json";
in = new ByteArrayInputStream(json.toString().getBytes());
- } else if ("json".equals(chapterStr)) {
- Story story = story(luid, whitelist);
+ } else if ("json".equals(chapterStr)) {
+ Story story = story(luid, login);
JSONObject json = JsonIO.toJson(story);
mimeType = "application/json";
in = new ByteArrayInputStream(json.toString().getBytes());
} else {
- Story story = story(luid, whitelist);
+ Story story = story(luid, login);
if (story != null) {
if (chapter == 0) {
StringBuilder builder = new StringBuilder();
}
private Response getViewer(Map<String, String> cookies, String uri,
- List<String> whitelist) {
+ WLoginResult login) {
String[] cover = uri.split("/");
int off = 2;
String paragraphStr = cover.length < off + 4 ? null : cover[off + 3];
// 1-based (0 = desc)
- int chapter = -1;
+ int chapter = 0;
if (chapterStr != null) {
try {
chapter = Integer.parseInt(chapterStr);
}
try {
- Story story = story(luid, whitelist);
+ Story story = story(luid, login);
if (story == null) {
return NanoHTTPD.newFixedLengthResponse(Status.NOT_FOUND,
NanoHTTPD.MIME_PLAINTEXT, "Story not found");
StringBuilder builder = new StringBuilder();
appendPreHtml(builder, false);
- if (chapter < 0) {
- builder.append(story);
- } else {
- if (chapter == 0) {
- // TODO: description
- chapter = 1;
- }
+ // For images documents, always go to the images if not chap 0 desc
+ if (story.getMeta().isImageDocument()) {
+ if (chapter > 0 && paragraph <= 0)
+ paragraph = 1;
+ }
- Chapter chap = null;
+ Chapter chap = null;
+ if (chapter <= 0) {
+ chap = story.getMeta().getResume();
+ } else {
try {
chap = story.getChapters().get(chapter - 1);
} catch (IndexOutOfBoundsException e) {
return NanoHTTPD.newFixedLengthResponse(Status.NOT_FOUND,
NanoHTTPD.MIME_PLAINTEXT, "Chapter not found");
}
+ }
- if (story.getMeta().isImageDocument() && paragraph <= 0) {
- paragraph = 1;
+ String first, previous, next, last;
+
+ StringBuilder content = new StringBuilder();
+
+ String disabledLeft = "";
+ String disabledRight = "";
+ String disabledZoomReal = "";
+ String disabledZoomWidth = "";
+ String disabledZoomHeight = "";
+
+ if (paragraph <= 0) {
+ first = WebLibraryUrls.getViewUrl(luid, 0, null);
+ previous = WebLibraryUrls.getViewUrl(luid,
+ (Math.max(chapter - 1, 0)), null);
+ next = WebLibraryUrls.getViewUrl(luid,
+ (Math.min(chapter + 1, story.getChapters().size())),
+ null);
+ last = WebLibraryUrls.getViewUrl(luid,
+ story.getChapters().size(), null);
+
+ StringBuilder desc = new StringBuilder();
+
+ if (chapter <= 0) {
+ desc.append("<h1 class='title'>");
+ desc.append(story.getMeta().getTitle());
+ desc.append("</h1>\n");
+ desc.append("<div class='desc'>\n");
+ desc.append("\t<a href='" + next + "' class='cover'>\n");
+ desc.append("\t\t<img src='/story/" + luid + "/cover'/>\n");
+ desc.append("\t</a>\n");
+ desc.append("\t<table class='details'>\n");
+ Map<String, String> details = BasicLibrary
+ .getMetaDesc(story.getMeta());
+ for (String key : details.keySet()) {
+ appendTableRow(desc, 2, key, details.get(key));
+ }
+ desc.append("\t</table>\n");
+ desc.append("</div>\n");
+ desc.append("<h1 class='title'>Description</h1>\n");
}
- String first, previous, next, last;
- String content;
+ content.append("<div class='viewer text'>\n");
+ content.append(desc);
+ String description = new TextOutput(false).convert(chap,
+ chapter > 0);
+ content.append(chap.getParagraphs().size() <= 0
+ ? "No content provided."
+ : description);
+ content.append("</div>\n");
+
+ if (chapter <= 0)
+ disabledLeft = " disabled='disbaled'";
+ if (chapter >= story.getChapters().size())
+ disabledRight = " disabled='disbaled'";
+ } else {
+ first = WebLibraryUrls.getViewUrl(luid, chapter, 1);
+ previous = WebLibraryUrls.getViewUrl(luid, chapter,
+ (Math.max(paragraph - 1, 1)));
+ next = WebLibraryUrls.getViewUrl(luid, chapter,
+ (Math.min(paragraph + 1, chap.getParagraphs().size())));
+ last = WebLibraryUrls.getViewUrl(luid, chapter,
+ chap.getParagraphs().size());
+
+ if (paragraph <= 1)
+ disabledLeft = " disabled='disbaled'";
+ if (paragraph >= chap.getParagraphs().size())
+ disabledRight = " disabled='disbaled'";
+
+ // First -> previous *chapter*
+ if (chapter > 0)
+ disabledLeft = "";
+ first = WebLibraryUrls.getViewUrl(luid,
+ (Math.max(chapter - 1, 0)), null);
+ if (paragraph <= 1) {
+ previous = first;
+ }
- if (paragraph <= 0) {
- first = getViewUrl(luid, 1, null);
- previous = getViewUrl(luid, (Math.max(chapter - 1, 1)),
- null);
- next = getViewUrl(luid,
- (Math.min(chapter + 1, story.getChapters().size())),
- null);
- last = getViewUrl(luid, story.getChapters().size(), null);
-
- content = "<div class='viewer text'>\n"
- + new TextOutput(false).convert(chap, true)
- + "</div>\n";
- } else {
- first = getViewUrl(luid, chapter, 1);
- previous = getViewUrl(luid, chapter,
- (Math.max(paragraph - 1, 1)));
- next = getViewUrl(luid, chapter, (Math.min(paragraph + 1,
- chap.getParagraphs().size())));
- last = getViewUrl(luid, chapter,
- chap.getParagraphs().size());
-
- Paragraph para = null;
- try {
- para = chap.getParagraphs().get(paragraph - 1);
- } catch (IndexOutOfBoundsException e) {
- return NanoHTTPD.newFixedLengthResponse(
- Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT,
- "Paragraph not found");
- }
+ Paragraph para = null;
+ try {
+ para = chap.getParagraphs().get(paragraph - 1);
+ } catch (IndexOutOfBoundsException e) {
+ return NanoHTTPD.newFixedLengthResponse(Status.NOT_FOUND,
+ NanoHTTPD.MIME_PLAINTEXT,
+ "Paragraph " + paragraph + " not found");
+ }
- if (para.getType() == ParagraphType.IMAGE) {
- String zoomStyle = "max-width: 100%;";
- String zoomOption = cookies.get("zoom");
- if (zoomOption != null && !zoomOption.isEmpty()) {
- if (zoomOption.equals("real")) {
- zoomStyle = "";
- } else if (zoomOption.equals("width")) {
- zoomStyle = "max-width: 100%;";
- } else if (zoomOption.equals("height")) {
- // see height of navbar + optionbar
- zoomStyle = "max-height: calc(100% - 128px);";
- }
+ if (para.getType() == ParagraphType.IMAGE) {
+ String zoomStyle = "max-width: 100%;";
+ disabledZoomWidth = " disabled='disabled'";
+ String zoomOption = cookies.get("zoom");
+ if (zoomOption != null && !zoomOption.isEmpty()) {
+ if (zoomOption.equals("real")) {
+ zoomStyle = "";
+ disabledZoomWidth = "";
+ disabledZoomReal = " disabled='disabled'";
+ } else if (zoomOption.equals("width")) {
+ zoomStyle = "max-width: 100%;";
+ } else if (zoomOption.equals("height")) {
+ // see height of navbar + optionbar
+ zoomStyle = "max-height: calc(100% - 128px);";
+ disabledZoomWidth = "";
+ disabledZoomHeight = " disabled='disabled'";
}
- content = String.format("" //
- + "<a class='viewer link' href='%s'>" //
- + "<img class='viewer img' style='%s' src='%s'/>"
- + "</a>", //
- next, //
- zoomStyle, //
- getStoryUrl(luid, chapter, paragraph));
- } else {
- content = para.getContent();
}
+ String javascript = "document.getElementById(\"previous\").click(); return false;";
+ content.append(String.format("" //
+ + "<a class='viewer link' oncontextmenu='%s' href='%s'>"
+ + "<img class='viewer img' style='%s' src='%s'/>"
+ + "</a>", //
+ javascript, //
+ next, //
+ zoomStyle, //
+ WebLibraryUrls.getStoryUrl(luid, chapter,
+ paragraph)));
+ } else {
+ content.append(String.format("" //
+ + "<div class='viewer text'>%s</div>", //
+ para.getContent()));
}
+ }
- builder.append(String.format("" //
- + "<div class='bar navbar'>\n" //
- + "\t<a class='button first' href='%s'><<</a>\n"//
- + "\t<a class='button previous' href='%s'><</a>\n"//
- + "\t<a class='button next' href='%s'>></a>\n"//
- + "\t<a class='button last' href='%s'>>></a>\n"//
- + "</div>\n" //
- + "%s", //
- first, //
- previous, //
- next, //
- last, //
- content //
- ));
-
- builder.append("<div class='bar optionbar ");
- if (paragraph > 0) {
- builder.append("s4");
- } else {
- builder.append("s1");
+ builder.append(String.format("" //
+ + "<div class='bar navbar'>\n" //
+ + "\t<a%s class='button first' href='%s'><<</a>\n"//
+ + "\t<a%s id='previous' class='button previous' href='%s'><</a>\n" //
+ + "\t<div class='gotobox itemsbox'>\n" //
+ + "\t\t<div class='button goto'>%d</div>\n" //
+ + "\t\t<div class='items goto'>\n", //
+ disabledLeft, first, //
+ disabledLeft, previous, //
+ paragraph > 0 ? paragraph : chapter //
+ ));
+
+ // List of chap/para links
+
+ appendItemA(builder, 3, WebLibraryUrls.getViewUrl(luid, 0, null),
+ "Description", paragraph == 0 && chapter == 0);
+ if (paragraph > 0) {
+ for (int i = 1; i <= chap.getParagraphs().size(); i++) {
+ appendItemA(builder, 3,
+ WebLibraryUrls.getViewUrl(luid, chapter, i),
+ "Image " + i, paragraph == i);
}
- builder.append("'>\n");
- builder.append(
- " <a class='button back' href='/'>BACK</a>\n");
-
- if (paragraph > 0) {
- builder.append(String.format("" //
- + "\t<a class='button zoomreal' href='%s'>REAL</a>\n"//
- + "\t<a class='button zoomwidth' href='%s'>WIDTH</a>\n"//
- + "\t<a class='button zoomheight' href='%s'>HEIGHT</a>\n"//
- + "</div>\n", //
- uri + "?optionName=zoom&optionValue=real", //
- uri + "?optionName=zoom&optionValue=width", //
- uri + "?optionName=zoom&optionValue=height" //
- ));
+ } else {
+ int i = 1;
+ for (Chapter c : story.getChapters()) {
+ String chapName = "Chapter " + c.getNumber();
+ if (c.getName() != null && !c.getName().isEmpty()) {
+ chapName += ": " + c.getName();
+ }
+
+ appendItemA(builder, 3,
+ WebLibraryUrls.getViewUrl(luid, i, null), chapName,
+ chapter == i);
+
+ i++;
}
}
+ builder.append(String.format("" //
+ + "\t\t</div>\n" //
+ + "\t</div>\n" //
+ + "\t<a%s class='button next' href='%s'>></a>\n" //
+ + "\t<a%s class='button last' href='%s'>>></a>\n"//
+ + "</div>\n", //
+ disabledRight, next, //
+ disabledRight, last //
+ ));
+
+ builder.append(content);
+
+ builder.append("<div class='bar optionbar ");
+ if (paragraph > 0) {
+ builder.append("s4");
+ } else {
+ builder.append("s1");
+ }
+ builder.append("'>\n");
+ builder.append(" <a class='button back' href='/'>BACK</a>\n");
+
+ if (paragraph > 0) {
+ builder.append(String.format("" //
+ + "\t<a%s class='button zoomreal' href='%s'>REAL</a>\n"//
+ + "\t<a%s class='button zoomwidth' href='%s'>WIDTH</a>\n"//
+ + "\t<a%s class='button zoomheight' href='%s'>HEIGHT</a>\n"//
+ + "</div>\n", //
+ disabledZoomReal,
+ uri + "?optionName=zoom&optionValue=real", //
+ disabledZoomWidth,
+ uri + "?optionName=zoom&optionValue=width", //
+ disabledZoomHeight,
+ uri + "?optionName=zoom&optionValue=height" //
+ ));
+ }
+
appendPostHtml(builder);
return NanoHTTPD.newFixedLengthResponse(Status.OK,
NanoHTTPD.MIME_HTML, builder.toString());
return "";
}
- private String getViewUrl(String luid, int chap, Integer para) {
- return VIEWER_URL //
- .replace("{luid}", luid) //
- .replace("{chap}", Integer.toString(chap)) //
- .replace("/{para}",
- para == null ? "" : "/" + Integer.toString(para));
- }
+ private boolean isAllowed(MetaData meta, WLoginResult login) {
+ if (login.isWl() && !whitelist.isEmpty()
+ && !whitelist.contains(meta.getSource())) {
+ return false;
+ }
+ if (login.isBl() && blacklist.contains(meta.getSource())) {
+ return false;
+ }
- private String getStoryUrl(String luid, int chap, Integer para) {
- return STORY_URL //
- .replace("{luid}", luid) //
- .replace("{chap}", Integer.toString(chap)) //
- .replace("{para}", para == null ? "" : Integer.toString(para));
+ return true;
}
- private String getStoryUrlCover(String luid) {
- return STORY_URL_COVER //
- .replace("{luid}", luid);
+ private List<MetaData> metas(WLoginResult login) throws IOException {
+ BasicLibrary lib = Instance.getInstance().getLibrary();
+ List<MetaData> metas = new ArrayList<MetaData>();
+ for (MetaData meta : lib.getList().getMetas()) {
+ if (isAllowed(meta, login)) {
+ metas.add(meta);
+ }
+ }
+
+ return metas;
}
- private MetaData meta(String luid, List<String> whitelist)
- throws IOException {
+ private MetaData meta(String luid, WLoginResult login) throws IOException {
BasicLibrary lib = Instance.getInstance().getLibrary();
MetaData meta = lib.getInfo(luid);
- if (!whitelist.isEmpty() && !whitelist.contains(meta.getSource())) {
+ if (!isAllowed(meta, login))
return null;
- }
return meta;
}
- private Image getCover(String luid, List<String> whitelist)
- throws IOException {
- MetaData meta = meta(luid, whitelist);
+ private Image getCover(String luid, WLoginResult login) throws IOException {
+ MetaData meta = meta(luid, login);
if (meta != null) {
- return meta.getCover();
+ BasicLibrary lib = Instance.getInstance().getLibrary();
+ return lib.getCover(meta.getLuid());
}
return null;
}
// NULL if not whitelist OK or if not found
- private Story story(String luid, List<String> whitelist)
- throws IOException {
+ private Story story(String luid, WLoginResult login) throws IOException {
synchronized (storyCache) {
if (storyCache.containsKey(luid)) {
Story story = storyCache.get(luid);
- if (!whitelist.isEmpty()
- && !whitelist.contains(story.getMeta().getSource())) {
+ if (!isAllowed(story.getMeta(), login))
return null;
- }
return story;
}
}
Story story = null;
- MetaData meta = meta(luid, whitelist);
+ MetaData meta = meta(luid, login);
if (meta != null) {
BasicLibrary lib = Instance.getInstance().getLibrary();
story = lib.getStory(luid, null);
if (banner) {
builder.append("<div class='banner'>\n");
- builder.append("\t<img class='ico' src='") //
+ builder.append("\t<img class='ico' src='/") //
.append(favicon) //
.append("'/>\n");
builder.append("\t<h1>Fanfix</h1>\n");
}
builder.append(">").append(name).append("</option>\n");
}
+
+ private void appendTableRow(StringBuilder builder, int depth,
+ String... tds) {
+ for (int i = 0; i < depth; i++) {
+ builder.append("\t");
+ }
+
+ int col = 1;
+ builder.append("<tr>");
+ for (String td : tds) {
+ builder.append("<td class='col");
+ builder.append(col++);
+ builder.append("'>");
+ builder.append(td);
+ builder.append("</td>");
+ }
+ builder.append("</tr>\n");
+ }
+
+ private void appendItemA(StringBuilder builder, int depth, String link,
+ String name, boolean selected) {
+ for (int i = 0; i < depth; i++) {
+ builder.append("\t");
+ }
+
+ builder.append("<a href='");
+ builder.append(link);
+ builder.append("' class='item goto");
+ if (selected) {
+ builder.append(" selected");
+ }
+ builder.append("'>");
+ builder.append(name);
+ builder.append("</a>\n");
+ }
+
+ public static void main(String[] args) throws IOException {
+ Instance.init();
+ WebLibraryServer web = new WebLibraryServer(false);
+ web.run();
+ }
}