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