diff --git a/src/assets/style.css b/src/assets/style.css
index 56a4acca3109e13090c6c2e3a1baaf2dc7284043..05862b1c25443a77117c65361c243958d088e37f 100644
--- a/src/assets/style.css
+++ b/src/assets/style.css
@@ -40,7 +40,13 @@ a:visited {
 .header-container {
     display: flex;
 }
+
 .header-date {
     white-space: nowrap;
     margin: 1em 1em 1em auto;
 }
+
+img, video {
+    max-width: 100%;
+    max-width: 100%;
+}
diff --git a/src/blog.rs b/src/blog.rs
index 81d12d7b138454d530134fa769ba8bda3c255f4f..abf7d19f745369a0a9d37d59d5ad0be3c4bfc5c3 100644
--- a/src/blog.rs
+++ b/src/blog.rs
@@ -2,12 +2,13 @@ use anyhow::Error;
 use std::collections::HashMap;
 use warp::hyper::StatusCode;
 
-use crate::{image::MyImage, load::load_from_path, post::Post, resp::Response};
+use crate::{image::MyImage, load::load_from_path, misc::Misc, post::Post, resp::Response};
 
 pub struct Blog {
     //pages: Vec<Page>,
     posts: Vec<Post>,
     imgs: Vec<MyImage>,
+    misc: Vec<Misc>,
 }
 
 impl Blog {
@@ -20,7 +21,9 @@ impl Blog {
 
         let imgs = load_from_path("assets/img", "")?;
 
-        Ok(Self { posts, imgs })
+        let misc = load_from_path("assets/misc", "misc")?;
+
+        Ok(Self { posts, imgs, misc })
     }
 
     fn home(&self) -> Result<String, Error> {
@@ -77,6 +80,10 @@ impl TryFrom<Blog> for RenderedBlog {
             pages.insert(original_url, original);
         }
 
+        for m in b.misc {
+            pages.insert(m.url.clone(), m.response());
+        }
+
         let not_found = Response::html(dress_page(
             "Page not found",
             include_str!("assets/404.html"),
diff --git a/src/main.rs b/src/main.rs
index daedcbdb20de4b511aa343abe5d7847d13fa6637..6d2f2f12a3d2d25d0c2fd775d2a8a84fb180ade8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -13,6 +13,7 @@ mod blog;
 mod date;
 mod image;
 mod load;
+mod misc;
 mod parser;
 mod post;
 mod resp;
diff --git a/src/misc.rs b/src/misc.rs
new file mode 100644
index 0000000000000000000000000000000000000000..b62d64c16c804d5911d0e5270b2b4b6c831600d4
--- /dev/null
+++ b/src/misc.rs
@@ -0,0 +1,42 @@
+use std::{fs::File, io::Read};
+
+use anyhow::Context;
+
+use crate::{load::Loadable, resp::Response, util::slugify};
+
+pub struct Misc {
+    pub url: String,
+    content_type: &'static str,
+    data: Vec<u8>,
+}
+
+impl Loadable for Misc {
+    fn load(path: &std::path::Path, slug_prefix: &str) -> anyhow::Result<Self> {
+        let file_name = path
+            .file_name()
+            .context("Could not get file name")?
+            .to_str()
+            .context("Could not convert filename into string")?
+            .to_owned();
+
+        let url = slugify(&format!("/{slug_prefix}/{file_name}"));
+
+        let mut data = vec![];
+        File::open(path)?.read_to_end(&mut data)?;
+
+        Ok(Self {
+            data,
+            content_type: "todo",
+            url,
+        })
+    }
+}
+
+impl Misc {
+    pub fn response(self) -> Response {
+        Response {
+            content_type: self.content_type,
+            data: self.data,
+        }
+    }
+}
diff --git a/src/parser.rs b/src/parser.rs
index 6821d8f9305c11e3a2df9fca810dac2aa9f63d4a..2d58ce74dac1f7502d571bebf0b99cf01143fa81 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -1,6 +1,7 @@
 use anyhow::bail;
 use anyhow::Context;
 use anyhow::Error;
+use orgize::elements::Keyword;
 use orgize::elements::Link;
 use orgize::elements::Timestamp;
 use orgize::{
@@ -89,6 +90,12 @@ impl HtmlHandler<Error> for CustomHtmlHandler {
             Element::Link(Link { path, desc }) if desc.is_none() => {
                 write!(w, r#"<a href="/img/{path}"><img src="/thumb/{path}">"#)?;
             }
+            Element::Keyword(Keyword { key, value, .. }) if key == "VIDEO" => {
+                write!(
+                    w,
+                    r#"<video controls="controls"><source src="{value}"></video>"#
+                )?;
+            }
             // fallback to default handler
             _ => self.fallback.start(w, element)?,
         }