cleanup, better media ig

This commit is contained in:
sample-text-here 2022-01-06 11:09:29 -08:00
parent 7089b6f39e
commit 1076402221
8 changed files with 75 additions and 34 deletions

View file

@ -1,16 +1,17 @@
.posts {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
grid-template-rows: repeat(auto-fill, 300px);
}
.post {
margin: 1em;
border: solid var(--accent1) 2px;
padding: 1em;
overflow-wrap: break-word;
background-size: cover;
}
.post > h2 > a {
.post h2 > a {
color: inherit;
}
@ -19,3 +20,12 @@
margin-bottom: 1em;
}
.preview {
padding: 1em;
background: #111111bb;
}
.attachment {
width: 100%;
}

View file

@ -8,7 +8,7 @@ they find throughout the day. Name comes from banal and otiose.
- [x] authentication
- [x] user config
- [x] basic posting
- [ ] media posts
- [x] media posts
- [ ] post config
- [ ] user profiles
- [ ] tagging

View file

@ -1,22 +1,19 @@
import busboy from "busboy";
// TODO: this code is messy! redo it
async function parse(req, files) {
const bb = busboy({ headers: req.headers, limits: { files: 1 } });
return new Promise((res) => {
const post = {};
let hasFile = false;
bb.on("field", (key, val) => post[key] = val);
bb.on("file", async (_name, file, info) => {
bb.on("file", async (_name, stream, info) => {
hasFile = true;
res({
post,
file: {
attachHash: await files.insert(file),
attachName: info.filename,
attachType: info.mimeType,
},
});
const file = {
attachHash: await files.insert(stream),
attachName: info.filename,
attachType: info.mimeType,
};
res({ post, file });
});
bb.on("close", () => {
if(!hasFile) res({ post });

View file

@ -25,9 +25,14 @@ async function init(schema, log) {
table.integer("author").unsigned();
table.string("title");
table.string("body");
table.string("attachHash");
table.string("attachName");
table.string("attachType");
table.integer("attachment").unsigned();
}).createTable("files", table => {
// map of the files
table.increments("fileId").primary();
table.string("hash");
table.string("name");
table.string("type");
table.binary("preview");
}).createTable("log", table => {
// log of everything that happens
table.increments("auditId");

View file

@ -1,3 +1,4 @@
// save files to a hash-based filestore
import fs from "fs/promises";
import path from "path";
import crypto from "crypto";
@ -5,9 +6,9 @@ import crypto from "crypto";
class Filestore {
where = path.join(process.cwd(), ".data");
constructor(log, db, options) {
this.log = log;
this.db = db;
constructor(ctx, options) {
this.log = ctx.log;
this.db = ctx.db;
this.options = options;
}
@ -28,7 +29,7 @@ class Filestore {
const h = hash.digest();
await tmpFd.close();
await fs.rename(tmpName, path.join(this.where, "files", h.toString("hex")));
this.log.info("saved file with hash " + h.toString("hex"));
this.log.debug("saved file with hash " + h.toString("hex"));
res(h);
});
});
@ -47,6 +48,6 @@ async function exists(where) {
export default async function(ctx, options) {
if(!await exists(".data/files")) await fs.mkdir(".data/files");
if(!await exists(".data/tmp")) await fs.mkdir(".data/tmp");
return new Filestore(ctx.log, ctx.db, options);
return new Filestore(ctx, options);
}

View file

@ -6,16 +6,19 @@ const md = markdown({
linkify: true,
});
// get a post by id
export async function getPost(db, id) {
const [post] = await db("posts").select().where("postId", id);
return post ?? null;
}
// get a user by id
export async function getUser(db, id) {
const [user] = await db("users").select().where("userId", id);
return user ?? null;
}
// render a post
export function render(post, author, trim = false) {
const date = new Date(post.createdAt);
const body = (trim && post.body.length > 200) ? post.body.slice(0, 200) + "..." : post.body;
@ -30,13 +33,36 @@ export function render(post, author, trim = false) {
};
}
// TODO: add support for other content types
export function attachment(post) {
switch(post.attachType?.split("/")[0]) {
case "image":
return `<img src="/media/${post.attachHash.toString("hex")}/${escape(post.attachName)}" alt="main image" class="attachment" />`;
default:
return null;
// render a post's attachment to html
function attachment(post) {
if(!post.attachHash) return null;
const location = `/media/${post.attachHash.toString("hex")}/${escape(post.attachName)}`;
return {
html: toHtml(),
preview: getPreview(),
url: location,
};
function toHtml() {
switch(post.attachType.split("/")[0]) {
case "image":
return `<img src="${location}" alt="main image" class="attachment" />`;
case "audio":
return `<audio controls src="${location}" alt="main audio" class="attachment"></audio>`;
case "video":
return `<video controls src="${location}" alt="main video" class="attachment"></video>`;
default:
return null;
}
}
function getPreview() {
switch(post.attachType.split("/")[0]) {
case "image":
return location;
default:
return null;
}
}
}
@ -57,6 +83,7 @@ const units = [
{ name: "internet explorer page load", size: 1000 },
];
// format dates to a relative time
function format(date) {
const delta = Date.now() - date;
let size = 1;

View file

@ -1,6 +1,7 @@
<div class="post">
<h2><a href="/post/{{id}}">{{title}}</a></h2>
<div class="fineprint"><i><time datetime="{{time}}">{{timefmt}}</time> - by {{author}}</i></div>
<p>{{{body}}}</p>
{{#attachment}}{{{this}}}{{/attachment}}
<div class="post" {{#attachment}}{{#preview}}style="background-image: url({{this}})"{{/preview}}{{/attachment}}>
<div class="preview">
<h2><a href="/post/{{id}}">{{title}}</a></h2>
<div class="fineprint"><i><time datetime="{{time}}">{{timefmt}}</time> - by {{author}}</i></div>
<p>{{{body}}}</p>
</div>
</div>

View file

@ -1,6 +1,6 @@
<main class="center">
<h1>{{title}}</h1>
<div class="fineprint"><i><time datetime="{{time}}">{{timefmt}}</time> - by {{author}}</i></div>
{{#attachment}}{{{this}}}{{/attachment}}
{{#attachment}}<a href="{{url}}">{{{html}}}</a>{{/attachment}}
<p>{{{body}}}</p>
</main>