From 60dfe901523562ed8caa8d70ccfd3e8d9a2c56f2 Mon Sep 17 00:00:00 2001 From: Peter Hormanns Date: Fri, 19 Sep 2025 18:48:08 +0200 Subject: [PATCH] initial commit --- .gitignore | 7 + README.md | 9 + pom.xml | 52 +++ .../java/de/jalin/fedipage/FediServlet.java | 57 +++ .../java/de/jalin/fedipage/JSONLoader.java | 99 +++++ src/main/resources/templates/profil.vm | 380 ++++++++++++++++++ src/main/webapp/WEB-INF/web.xml | 22 + 7 files changed, 626 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/de/jalin/fedipage/FediServlet.java create mode 100644 src/main/java/de/jalin/fedipage/JSONLoader.java create mode 100644 src/main/resources/templates/profil.vm create mode 100644 src/main/webapp/WEB-INF/web.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2b9980e --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +target/ +/.settings/ +/.classpath +/.project +nb-configuration.xml +nbactions.xml +/nbproject/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..b41e151 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +Fedi Page +========= + +This JakartaEE servlet uses content from your +Mastodon profile to provide an HTML website for +your personal domain. + +The only dependencies are a JSON parser and +Velocity as a template engine. \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..dd605f1 --- /dev/null +++ b/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + de.jalin.fedipage + fedipage + 1.0-SNAPSHOT + war + + + 21 + 21 + UTF-8 + + + + + + jakarta.servlet + jakarta.servlet-api + 5.0.0 + provided + + + + + org.json + json + 20250517 + + + + + org.apache.velocity + velocity-engine-core + 2.4.1 + + + + + fedipage + + + org.eclipse.jetty.ee10 + jetty-ee10-maven-plugin + 12.1.1 + + + + diff --git a/src/main/java/de/jalin/fedipage/FediServlet.java b/src/main/java/de/jalin/fedipage/FediServlet.java new file mode 100644 index 0000000..f800826 --- /dev/null +++ b/src/main/java/de/jalin/fedipage/FediServlet.java @@ -0,0 +1,57 @@ +package de.jalin.fedipage; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.URISyntaxException; + +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.exception.ResourceNotFoundException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +public class FediServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + private VelocityEngine velocityEngine; + + @Override + public void init() throws ServletException { + velocityEngine = new VelocityEngine(); + velocityEngine.setProperty("resource.loaders", "class"); + velocityEngine.setProperty("resource.loader.class.class", + "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + velocityEngine.init(); + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + try { + final JSONLoader loader = new JSONLoader("mastodon.social", "Mastodon"); + final VelocityContext context = new VelocityContext(); + context.put("profile", loader.loadProfile()); + context.put("pinned", loader.loadPinned()); + context.put("timeline", loader.loadTimeline()); + final Template template = velocityEngine.getTemplate("/templates/profil.vm"); + response.setContentType("text/html;charset=UTF-8"); + try (PrintWriter writer = response.getWriter()) { + template.merge(context, writer); + } + + } catch (ResourceNotFoundException e) { + throw new ServletException("Template nicht gefunden", e); + } catch (ParseErrorException e) { + throw new ServletException("Fehler beim Parsen des Templates", e); + } catch (URISyntaxException e) { + throw new ServletException("Instanz URL ist falsch", e); + } + } +} diff --git a/src/main/java/de/jalin/fedipage/JSONLoader.java b/src/main/java/de/jalin/fedipage/JSONLoader.java new file mode 100644 index 0000000..2b108ed --- /dev/null +++ b/src/main/java/de/jalin/fedipage/JSONLoader.java @@ -0,0 +1,99 @@ +package de.jalin.fedipage; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Serializable; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONObject; + +public class JSONLoader implements Serializable { + + private static final long serialVersionUID = 7255602422151204643L; + + private final String instance; + private final String account; + + private int id; + + public JSONLoader(String instance, String account) { + this.instance = instance; + this.account = account; + this.id = -1; + } + + public JSONObject loadProfile() throws IOException, URISyntaxException { + final URI uri = new URI("https://" + instance + "/api/v1/accounts/lookup?acct=" + account); + final URL url = uri.toURL(); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + final StringBuilder content = new StringBuilder(); + while ((line = reader.readLine()) != null) { + content.append(line); + } + final JSONObject data = new JSONObject(content.toString()); + id = data.getInt("id"); + return data; + } + + public JSONArray loadPinned() throws IOException, URISyntaxException { + final JSONArray pinnedStatusesArray = loadStatuses("pinned=true"); +// final ArrayList pinnedStatuses = new ArrayList<>(); + return pinnedStatusesArray; + } + + public JSONArray loadTimeline() throws IOException, URISyntaxException { + final JSONArray lastStatusesArray = loadStatuses("limit=20"); +// for (int idx=0; idx< lastStatusesArray.length(); idx++) { +// final Object object = lastStatusesArray.get(idx); +// JSONObject json = (JSONObject) object; +// final Status status = new Status(); +// JSONObject account = json.getJSONObject("account"); +// if (json.get("reblog") != null) { +// status.setBoostedBy(account.getString("display_name")); +// json = json.getJSONObject("reblog"); +// } +// } +// final ArrayList latestStatuses = new ArrayList<>(); + return lastStatusesArray; + } + + private JSONArray loadStatuses(final String filter) throws IOException, URISyntaxException { + if (id < 0) { + loadProfile(); + } + final URI uri = new URI("https://" + instance + "/api/v1/accounts/" + id + "/statuses?" + filter); + final URL url = uri.toURL(); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + final StringBuilder content = new StringBuilder(); + while ((line = reader.readLine()) != null) { + content.append(line); + } + return new JSONArray(content.toString()); + } + + public static void main(String[] args) { + // final JSONLoader loader = new JSONLoader(args[0], args[1]); + final JSONLoader loader = new JSONLoader("krefeld.life", "darestiet"); + try { + final JSONArray pinned = loader.loadTimeline(); + for (Object obj : pinned) { + @SuppressWarnings("unchecked") + final Map json = (Map) obj; + System.out.println(json.toString()); + } + } catch (IOException | URISyntaxException e) { + } + } +} diff --git a/src/main/resources/templates/profil.vm b/src/main/resources/templates/profil.vm new file mode 100644 index 0000000..5ff78e0 --- /dev/null +++ b/src/main/resources/templates/profil.vm @@ -0,0 +1,380 @@ + + + + + + $profile.display_name - $profile.username + + + +
+
+ +
+ +
+ Avatar +
+
$profile.display_name
+ +
$profile.note
+
+ $profile.following_count Folgt + $profile.followers_count Follower + $profile.statuses_count BeitrΓ€ge +
+
+
+ + + + +
+#foreach( $post in $pinned ) +
+
πŸ“Œ Angeheftet
+
+ Avatar +
+
$post.account.display_name
+
@$post.account.acct
+
+
+
$post.content
+#if( $post.media_attachments.length > 0 ) +
+
+
+ $post.media_attachments[0].description +
+
+
+#end +
+ πŸ”„ $post.reblogs_count + ⭐ $post.favourites_count + πŸ’¬ $post.replies_count +
+
+#end +#foreach( $post in $timeline ) +
+#if( $post.reblog.account ) +
πŸ”„ $post.account.display_name hat geteilt
+
+ Avatar +
+
$post.reblog.account.display_name
+
@$post.reblog.account.acct
+
+
+
$post.reblog.content
+#if( $post.reblog.media_attachments.length > 0 ) +
+
+
+ $post.reblog.media_attachments[0].description +
+
+
+#end +#else +
+ Avatar +
+
$post.account.display_name
+
@$post.account.acct
+
+
+
$post.content
+#if( $post.media_attachments.length > 0 ) +
+
+
+ $post.media_attachments[0].description +
+
+
+#end +
+ πŸ”„ $post.reblogs_count + ⭐ $post.favourites_count + πŸ’¬ $post.replies_count +
+#end +
+#end +
+
+ + + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d50e551 --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,22 @@ + + + + Fediverse Homepage + + + FediServlet + de.jalin.fedipage.FediServlet + + + + FediServlet + / + + + + / + +