diff --git a/set_version.sh b/set_version.sh
index f3e28f9e4f6b7886ab483e401c0cd2bd07e28361..ef9bef81a45f9e0c58c170e4c91f28d046b92e6a 100755
--- a/set_version.sh
+++ b/set_version.sh
@@ -1,3 +1,3 @@
 #!/bin/bash
-export version=0.4.1-alpha.9
+export version=0.4.1-alpha.10
 echo "pub const VERSION: &str = \"${version}\";" > src/version.rs
diff --git a/src/database/entities/january.rs b/src/database/entities/january.rs
index 043561a5f1567b2c14631cd2853fbb6e961afd23..c530b75e550a20f57bac9474f1ba57e2b6d00789 100644
--- a/src/database/entities/january.rs
+++ b/src/database/entities/january.rs
@@ -3,30 +3,77 @@ use linkify::{LinkFinder, LinkKind};
 use crate::util::{result::{Error, Result}, variables::JANUARY_URL};
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-pub enum MediaSize {
+pub enum ImageSize {
     Large,
     Preview,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-pub struct Media {
+pub struct Image {
     pub url: String,
     pub width: isize,
     pub height: isize,
-    pub size: MediaSize,
+    pub size: ImageSize,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct Video {
+    pub url: String,
+    pub width: isize,
+    pub height: isize,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub enum TwitchType {
+    Channel,
+    Video,
+    Clip,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub enum BandcampType {
+    Album,
+    Track
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+#[serde(tag = "type")]
+pub enum Special {
+    None,
+    YouTube {
+        id: String,
+    },
+    Twitch {
+        content_type: TwitchType,
+        id: String,
+    },
+    Spotify {
+        content_type: String,
+        id: String,
+    },
+    Soundcloud,
+    Bandcamp {
+        content_type: BandcampType,
+        id: String
+    }
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
 pub struct Metadata {
-    #[serde(skip_serializing_if = "Option::is_none")]
     url: Option<String>,
+    special: Option<Special>,
+
     #[serde(skip_serializing_if = "Option::is_none")]
     title: Option<String>,
     #[serde(skip_serializing_if = "Option::is_none")]
     description: Option<String>,
     #[serde(skip_serializing_if = "Option::is_none")]
-    image: Option<Media>,
-    
+    image: Option<Image>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    video: Option<Video>,
+
+    // #[serde(skip_serializing_if = "Option::is_none")]
+    // opengraph_type: Option<String>,
     #[serde(skip_serializing_if = "Option::is_none")]
     site_name: Option<String>,
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -39,13 +86,30 @@ pub struct Metadata {
 #[serde(tag = "type")]
 pub enum Embed {
     Website(Metadata),
-    Image(Media),
+    Image(Image),
     None,
 }
 
 impl Embed {
     pub async fn generate(content: String) -> Result<Vec<Embed>> {
-        // FIXME: allow multiple links
+        let content = content
+            .split("\n")
+            .map(|v| {
+                // Ignore quoted lines.
+                if let Some(c) = v.chars().next() {
+                    if c == '>' {
+                        return ""
+                    }
+                }
+
+                v
+            })
+            // This will also remove newlines, but
+            // that isn't important here.
+            .collect::<String>();
+
+        // ! FIXME: allow multiple links
+        // ! FIXME: prevent generation if link is surrounded with < >
         let mut finder = LinkFinder::new();
         finder.kinds(&[LinkKind::Url]);
         let links: Vec<_> = finder.links(&content).collect();
diff --git a/src/version.rs b/src/version.rs
index 5716a7d6ac5e51822eacc71f61cc0619a465f541..0efb35a6b4eb9f5d7253516e61b23d44144d5006 100644
--- a/src/version.rs
+++ b/src/version.rs
@@ -1 +1 @@
-pub const VERSION: &str = "0.4.1-alpha.9";
+pub const VERSION: &str = "0.4.1-alpha.10";