Generalize templates, Add post template
This commit is contained in:
parent
55e1792336
commit
4db5029118
@ -7,11 +7,11 @@ import java.nio.file.StandardWatchEventKinds;
|
|||||||
import java.nio.file.WatchKey;
|
import java.nio.file.WatchKey;
|
||||||
import java.nio.file.WatchService;
|
import java.nio.file.WatchService;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -19,6 +19,8 @@ import me.mrletsplay.mdblog.blog.Post;
|
|||||||
import me.mrletsplay.mdblog.blog.PostMetadata;
|
import me.mrletsplay.mdblog.blog.PostMetadata;
|
||||||
import me.mrletsplay.mdblog.markdown.MdParser;
|
import me.mrletsplay.mdblog.markdown.MdParser;
|
||||||
import me.mrletsplay.mdblog.markdown.MdRenderer;
|
import me.mrletsplay.mdblog.markdown.MdRenderer;
|
||||||
|
import me.mrletsplay.mdblog.template.Template;
|
||||||
|
import me.mrletsplay.mdblog.template.Templates;
|
||||||
import me.mrletsplay.mdblog.util.PostPath;
|
import me.mrletsplay.mdblog.util.PostPath;
|
||||||
import me.mrletsplay.mdblog.util.TimeFormatter;
|
import me.mrletsplay.mdblog.util.TimeFormatter;
|
||||||
import me.mrletsplay.mrcore.http.HttpUtils;
|
import me.mrletsplay.mrcore.http.HttpUtils;
|
||||||
@ -35,22 +37,14 @@ public class MdBlog {
|
|||||||
FILES_PATH = Path.of("files"),
|
FILES_PATH = Path.of("files"),
|
||||||
POSTS_PATH = FILES_PATH.resolve("posts");
|
POSTS_PATH = FILES_PATH.resolve("posts");
|
||||||
|
|
||||||
private static final String
|
|
||||||
INDEX_NAME = "index",
|
|
||||||
INDEX_POST_NAME = "index-post",
|
|
||||||
INDEX_SUB_BLOG_NAME = "index-sub-blog";
|
|
||||||
|
|
||||||
private static HttpServer server;
|
private static HttpServer server;
|
||||||
private static WatchService watchService;
|
private static WatchService watchService;
|
||||||
private static List<WatchKey> watchedDirectories;
|
private static List<WatchKey> watchedDirectories;
|
||||||
private static Map<PostPath, Post> posts;
|
private static Map<PostPath, Post> posts;
|
||||||
private static Map<PostPath, String> indexTemplates;
|
private static Map<PostPath, Templates> indexTemplates;
|
||||||
private static Map<PostPath, FileDocument> globalResources;
|
private static Map<PostPath, FileDocument> globalResources;
|
||||||
|
|
||||||
private static String
|
private static Templates defaultTemplates;
|
||||||
defaultIndexTemplate,
|
|
||||||
defaultIndexSubBlogTemplate,
|
|
||||||
defaultIndexPostTemplate;
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
server = new HttpServer(HttpServer.newConfigurationBuilder()
|
server = new HttpServer(HttpServer.newConfigurationBuilder()
|
||||||
@ -61,9 +55,10 @@ public class MdBlog {
|
|||||||
server.getDocumentProvider().register(HttpRequestMethod.GET, "/", () -> createPostsIndex(PostPath.root()));
|
server.getDocumentProvider().register(HttpRequestMethod.GET, "/", () -> createPostsIndex(PostPath.root()));
|
||||||
server.getDocumentProvider().registerPattern(HttpRequestMethod.GET, "/{path...}", () -> handleRequest(HttpRequestContext.getCurrentContext()));
|
server.getDocumentProvider().registerPattern(HttpRequestMethod.GET, "/{path...}", () -> handleRequest(HttpRequestContext.getCurrentContext()));
|
||||||
|
|
||||||
defaultIndexTemplate = Files.readString(extract("template/index.md"));
|
defaultTemplates = new Templates(null);
|
||||||
defaultIndexPostTemplate = Files.readString(extract("template/index-post.md"));
|
for(Template template : Template.values()) {
|
||||||
defaultIndexSubBlogTemplate = Files.readString(extract("template/index-sub-blog.md"));
|
defaultTemplates.put(template, Files.readString(extract("template/" + template.getName() + ".md")));
|
||||||
|
}
|
||||||
|
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
@ -123,9 +118,7 @@ public class MdBlog {
|
|||||||
|
|
||||||
String blogName = path.getName();
|
String blogName = path.getName();
|
||||||
|
|
||||||
String indexTemplate = indexTemplates.getOrDefault(path.concat(PostPath.parse(INDEX_NAME)), defaultIndexTemplate);
|
Templates templates = indexTemplates.getOrDefault(path, defaultTemplates);
|
||||||
String indexSubBlogTemplate = indexTemplates.getOrDefault(path.concat(PostPath.parse(INDEX_SUB_BLOG_NAME)), defaultIndexSubBlogTemplate);
|
|
||||||
String indexPostTemplate = indexTemplates.getOrDefault(path.concat(PostPath.parse(INDEX_POST_NAME)), defaultIndexPostTemplate);
|
|
||||||
|
|
||||||
HtmlDocument index = new HtmlDocument();
|
HtmlDocument index = new HtmlDocument();
|
||||||
index.setTitle("Index of " + blogName);
|
index.setTitle("Index of " + blogName);
|
||||||
@ -133,23 +126,19 @@ public class MdBlog {
|
|||||||
index.addStyleSheet("_/style/base.css");
|
index.addStyleSheet("_/style/base.css");
|
||||||
index.addStyleSheet("_/style/index.css");
|
index.addStyleSheet("_/style/index.css");
|
||||||
|
|
||||||
String indexMd = indexTemplate;
|
String indexMd = templates.render(Template.INDEX,
|
||||||
indexMd = indexMd.replace("{name}", blogName);
|
"name", blogName,
|
||||||
indexMd = indexMd.replace("{sub_blogs}", directories.stream()
|
"sub_blogs", directories.stream()
|
||||||
.map(p -> {
|
.map(p -> {
|
||||||
String subBlogMd = indexSubBlogTemplate;
|
|
||||||
|
|
||||||
HtmlElement name = new HtmlElement("a");
|
HtmlElement name = new HtmlElement("a");
|
||||||
name.setAttribute("href", p.toString());
|
name.setAttribute("href", p.toString());
|
||||||
name.setText(p.getName());
|
name.setText(p.getName());
|
||||||
subBlogMd = subBlogMd.replace("{name}", name.toString());
|
return templates.render(Template.INDEX_SUB_BLOG,
|
||||||
return subBlogMd;
|
"name", name.toString());
|
||||||
})
|
})
|
||||||
.collect(Collectors.joining("\n\n")));
|
.collect(Collectors.joining("\n\n")),
|
||||||
|
"posts", postsInDir.stream()
|
||||||
indexMd = indexMd.replace("{posts}", postsInDir.stream()
|
|
||||||
.map(p -> {
|
.map(p -> {
|
||||||
String postMd = indexPostTemplate;
|
|
||||||
Post post = posts.get(path == null ? p : path.concat(p));
|
Post post = posts.get(path == null ? p : path.concat(p));
|
||||||
PostMetadata meta = post.getMetadata();
|
PostMetadata meta = post.getMetadata();
|
||||||
if(tag != null && !meta.tags().contains(tag)) return null;
|
if(tag != null && !meta.tags().contains(tag)) return null;
|
||||||
@ -157,13 +146,15 @@ public class MdBlog {
|
|||||||
HtmlElement title = new HtmlElement("a");
|
HtmlElement title = new HtmlElement("a");
|
||||||
title.setAttribute("href", p.toString());
|
title.setAttribute("href", p.toString());
|
||||||
title.setText(meta.title());
|
title.setText(meta.title());
|
||||||
postMd = postMd.replace("{title}", title.toString());
|
|
||||||
|
|
||||||
postMd = postMd.replace("{author}", meta.author());
|
return templates.render(Template.INDEX_POST,
|
||||||
postMd = postMd.replace("{date}", TimeFormatter.toDateOnly(meta.date()));
|
"title", title.toString(),
|
||||||
postMd = postMd.replace("{date_time}", TimeFormatter.toDateAndTime(meta.date()));
|
"author", meta.author(),
|
||||||
postMd = postMd.replace("{date_relative}", TimeFormatter.toRelativeTime(meta.date()));
|
"date", TimeFormatter.toDateOnly(meta.date()),
|
||||||
postMd = postMd.replace("{tags}", meta.tags().stream()
|
"date_time", TimeFormatter.toDateAndTime(meta.date()),
|
||||||
|
"date_relative", TimeFormatter.toRelativeTime(meta.date()),
|
||||||
|
"description", meta.description(),
|
||||||
|
"tags", meta.tags().stream()
|
||||||
.map(t -> {
|
.map(t -> {
|
||||||
HtmlElement link = new HtmlElement("a");
|
HtmlElement link = new HtmlElement("a");
|
||||||
link.setText(t);
|
link.setText(t);
|
||||||
@ -171,10 +162,7 @@ public class MdBlog {
|
|||||||
return link.toString();
|
return link.toString();
|
||||||
})
|
})
|
||||||
.collect(Collectors.joining(", ")));
|
.collect(Collectors.joining(", ")));
|
||||||
postMd = postMd.replace("{description}", meta.description());
|
|
||||||
return postMd;
|
|
||||||
})
|
})
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.joining("\n\n")));
|
.collect(Collectors.joining("\n\n")));
|
||||||
|
|
||||||
index.getBodyNode().appendChild(new MdRenderer().render(MdParser.parse(indexMd)));
|
index.getBodyNode().appendChild(new MdRenderer().render(MdParser.parse(indexMd)));
|
||||||
@ -200,6 +188,10 @@ public class MdBlog {
|
|||||||
Post post = posts.get(path);
|
Post post = posts.get(path);
|
||||||
|
|
||||||
if(post != null) {
|
if(post != null) {
|
||||||
|
if(rawPath.endsWith("/")) {
|
||||||
|
ctx.redirect("../" + path.subPath(path.length() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
post.getContent().createContent();
|
post.getContent().createContent();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -237,6 +229,7 @@ public class MdBlog {
|
|||||||
private static Path extract(String path) throws IOException {
|
private static Path extract(String path) throws IOException {
|
||||||
Path filePath = FILES_PATH.resolve(path);
|
Path filePath = FILES_PATH.resolve(path);
|
||||||
if(!Files.exists(filePath)) {
|
if(!Files.exists(filePath)) {
|
||||||
|
System.out.println("Extracting " + path);
|
||||||
Files.createDirectories(filePath.getParent());
|
Files.createDirectories(filePath.getParent());
|
||||||
Files.write(filePath, MdBlog.class.getResourceAsStream("/" + path).readAllBytes());
|
Files.write(filePath, MdBlog.class.getResourceAsStream("/" + path).readAllBytes());
|
||||||
}
|
}
|
||||||
@ -248,33 +241,43 @@ public class MdBlog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void updateBlogs() throws IOException {
|
private static void updateBlogs() throws IOException {
|
||||||
Iterator<Post> it = posts.values().iterator();
|
System.out.println("Update");
|
||||||
while(it.hasNext()) {
|
|
||||||
Post p = it.next();
|
|
||||||
if(!p.update()) it.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
indexTemplates.clear();
|
indexTemplates.clear();
|
||||||
|
|
||||||
|
System.out.println(posts);
|
||||||
|
|
||||||
Files.walk(POSTS_PATH)
|
Files.walk(POSTS_PATH)
|
||||||
.filter(Files::isRegularFile)
|
.filter(Files::isRegularFile)
|
||||||
.filter(f -> f.getFileName().toString().endsWith(Post.FILE_EXTENSION))
|
.filter(f -> f.getFileName().toString().endsWith(Post.FILE_EXTENSION))
|
||||||
.filter(f -> posts.values().stream().noneMatch(p -> p.getFilePath().equals(f)))
|
.filter(f -> posts.values().stream().noneMatch(p -> p.getFilePath().equals(f)))
|
||||||
.forEach(f -> {
|
.forEach(f -> {
|
||||||
try {
|
try {
|
||||||
String postName = f.getFileName().toString();
|
String fullPostName = f.getFileName().toString();
|
||||||
postName = postName.substring(0, postName.length() - Post.FILE_EXTENSION.length());
|
String postName = fullPostName.substring(0, fullPostName.length() - Post.FILE_EXTENSION.length());
|
||||||
PostPath path = PostPath.of(POSTS_PATH.relativize(f).getParent(), postName);
|
PostPath path = PostPath.of(POSTS_PATH.relativize(f).getParent(), postName);
|
||||||
|
|
||||||
if(INDEX_NAME.equals(postName) || INDEX_SUB_BLOG_NAME.equals(postName) || INDEX_POST_NAME.equals(postName)) {
|
Template template = Arrays.stream(Template.values())
|
||||||
|
.filter(t -> t.getName().equals(postName))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
if(template != null) {
|
||||||
// File is an index template, don't parse it as a post
|
// File is an index template, don't parse it as a post
|
||||||
indexTemplates.put(path, Files.readString(f, StandardCharsets.UTF_8));
|
indexTemplates.computeIfAbsent(path.getParent(), p -> new Templates(defaultTemplates)).put(template, Files.readString(f, StandardCharsets.UTF_8));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
posts.put(path, new Post(f));
|
posts.put(path, new Post(f));
|
||||||
} catch (IOException e) {}
|
} catch (IOException e) {}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Iterator<Map.Entry<PostPath, Post>> it = posts.entrySet().iterator();
|
||||||
|
while(it.hasNext()) {
|
||||||
|
Map.Entry<PostPath, Post> en = it.next();
|
||||||
|
PostPath path = en.getKey();
|
||||||
|
Post p = en.getValue();
|
||||||
|
|
||||||
|
Templates templates = indexTemplates.getOrDefault(path.getParent(), defaultTemplates);
|
||||||
|
if(!p.update(templates)) it.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void watchFolders() throws IOException {
|
private static void watchFolders() throws IOException {
|
||||||
|
@ -8,7 +8,9 @@ import java.security.NoSuchAlgorithmException;
|
|||||||
|
|
||||||
import me.mrletsplay.mdblog.markdown.MdParser;
|
import me.mrletsplay.mdblog.markdown.MdParser;
|
||||||
import me.mrletsplay.mdblog.markdown.MdRenderer;
|
import me.mrletsplay.mdblog.markdown.MdRenderer;
|
||||||
import me.mrletsplay.mrcore.misc.ByteUtils;
|
import me.mrletsplay.mdblog.template.Template;
|
||||||
|
import me.mrletsplay.mdblog.template.Templates;
|
||||||
|
import me.mrletsplay.mdblog.util.TimeFormatter;
|
||||||
import me.mrletsplay.simplehttpserver.dom.html.HtmlDocument;
|
import me.mrletsplay.simplehttpserver.dom.html.HtmlDocument;
|
||||||
|
|
||||||
public class Post {
|
public class Post {
|
||||||
@ -27,14 +29,12 @@ public class Post {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Path filePath;
|
private Path filePath;
|
||||||
private String checksum;
|
// private String checksum; TODO currently unused, post also needs to update when templates change
|
||||||
private PostMetadata metadata;
|
private PostMetadata metadata;
|
||||||
private HtmlDocument content;
|
private HtmlDocument content;
|
||||||
|
|
||||||
public Post(Path filePath) throws IOException {
|
public Post(Path filePath) throws IOException {
|
||||||
this.filePath = filePath;
|
this.filePath = filePath;
|
||||||
this.checksum = checksum(filePath);
|
|
||||||
load();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path getFilePath() {
|
public Path getFilePath() {
|
||||||
@ -54,7 +54,7 @@ public class Post {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void load() throws IOException {
|
private void load(Templates templates) throws IOException {
|
||||||
String postData = Files.readString(filePath);
|
String postData = Files.readString(filePath);
|
||||||
String[] spl = postData.split("\n---\n", 2);
|
String[] spl = postData.split("\n---\n", 2);
|
||||||
if(spl.length != 2) throw new IOException("Invalid post file");
|
if(spl.length != 2) throw new IOException("Invalid post file");
|
||||||
@ -62,30 +62,37 @@ public class Post {
|
|||||||
this.metadata = PostMetadata.load(spl[0]);
|
this.metadata = PostMetadata.load(spl[0]);
|
||||||
|
|
||||||
HtmlDocument document = new HtmlDocument();
|
HtmlDocument document = new HtmlDocument();
|
||||||
document.getBodyNode().appendChild(RENDERER.render(MdParser.parse(spl[1])));
|
document.getBodyNode().appendChild(RENDERER.render(MdParser.parse(templates.render(Template.POST,
|
||||||
|
"content", spl[1],
|
||||||
|
"title", metadata.title(),
|
||||||
|
"author", metadata.author(),
|
||||||
|
"description", metadata.description(),
|
||||||
|
"date", TimeFormatter.toDateOnly(metadata.date()),
|
||||||
|
"date_time", TimeFormatter.toDateAndTime(metadata.date()),
|
||||||
|
"date_relative", TimeFormatter.toRelativeTime(metadata.date())))));
|
||||||
document.setTitle(metadata.title());
|
document.setTitle(metadata.title());
|
||||||
document.setDescription(metadata.description());
|
document.setDescription(metadata.description());
|
||||||
document.addStyleSheet("/_/style/base.css");
|
document.addStyleSheet("_/style/base.css");
|
||||||
document.addStyleSheet("/_/style/post.css");
|
document.addStyleSheet("_/style/post.css");
|
||||||
this.content = document;
|
this.content = document;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean update() {
|
public boolean update(Templates templates) {
|
||||||
if(!Files.exists(filePath)) return false;
|
if(!Files.exists(filePath)) return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String newChecksum = checksum(filePath);
|
//String newChecksum = checksum(filePath);
|
||||||
if(checksum.equals(newChecksum)) return true;
|
//if(checksum != null && checksum.equals(newChecksum)) return true;
|
||||||
this.checksum = newChecksum;
|
//this.checksum = newChecksum;
|
||||||
load();
|
load(templates);
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String checksum(Path filePath) throws IOException {
|
// private static String checksum(Path filePath) throws IOException {
|
||||||
return ByteUtils.bytesToHex(MD_5.digest(Files.readAllBytes(filePath)));
|
// return ByteUtils.bytesToHex(MD_5.digest(Files.readAllBytes(filePath)));
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
21
src/main/java/me/mrletsplay/mdblog/template/Template.java
Normal file
21
src/main/java/me/mrletsplay/mdblog/template/Template.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package me.mrletsplay.mdblog.template;
|
||||||
|
|
||||||
|
public enum Template {
|
||||||
|
|
||||||
|
INDEX("index"),
|
||||||
|
INDEX_POST("index-post"),
|
||||||
|
INDEX_SUB_BLOG("index-sub-blog"),
|
||||||
|
POST("post"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private Template(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
src/main/java/me/mrletsplay/mdblog/template/Templates.java
Normal file
37
src/main/java/me/mrletsplay/mdblog/template/Templates.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package me.mrletsplay.mdblog.template;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Templates {
|
||||||
|
|
||||||
|
private Templates defaults;
|
||||||
|
private Map<Template, String> templates;
|
||||||
|
|
||||||
|
public Templates(Templates defaults) {
|
||||||
|
this.defaults = defaults;
|
||||||
|
this.templates = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String get(Template template) {
|
||||||
|
return templates.getOrDefault(template, defaults == null ? null : defaults.get(template));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(Template template, String templateContent) {
|
||||||
|
templates.put(template, templateContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String render(Template template, String... variables) {
|
||||||
|
if(variables.length % 2 != 0) throw new IllegalArgumentException("Invalid number of arguments");
|
||||||
|
|
||||||
|
String content = get(template);
|
||||||
|
|
||||||
|
for(int i = 0; i < variables.length; i += 2) {
|
||||||
|
String variable = variables[i];
|
||||||
|
content = content.replace("{" + variable + "}", variables[i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
6
src/main/resources/template/post.md
Normal file
6
src/main/resources/template/post.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# {title}
|
||||||
|
by {author} {date_relative}
|
||||||
|
|
||||||
|
{description}
|
||||||
|
|
||||||
|
{content}
|
Loading…
Reference in New Issue
Block a user