From a8cbebd240fb7f92a2d476080b2cdf615596234b Mon Sep 17 00:00:00 2001
From: wukko <me@wukko.me>
Date: Sun, 20 Aug 2023 16:11:16 +0600
Subject: [PATCH] vxtwitter support

- moved out host overrides to its own file
- added mastodon verification
---
 README.md                                |  3 +-
 src/modules/api.js                       | 31 +++---------------
 src/modules/pageRender/page.js           |  2 ++
 src/modules/processing/hostOverrides.js  | 41 ++++++++++++++++++++++++
 src/modules/processing/services/vimeo.js |  2 +-
 src/test/tests.json                      | 16 +++++++++
 6 files changed, 67 insertions(+), 28 deletions(-)
 create mode 100644 src/modules/processing/hostOverrides.js

diff --git a/README.md b/README.md
index a558bf6e..ee002846 100644
--- a/README.md
+++ b/README.md
@@ -21,9 +21,10 @@ Paste the link, get the video, move on. It's that simple. Just how it should be.
 | Pinterest               | ✅           | ✅         | ✅         | Support for videos and stories.                                                                                           |
 | Reddit                  | ✅           | ✅         | ✅         | Support for GIFs and videos.                                                                                              |
 | SoundCloud              | ➖           | ✅         | ➖         | Audio metadata, downloads from private links.                                                                             |
+| Streamable              | ✅           | ✅         | ✅         |                                                                                                                           |
 | TikTok                  | ✅           | ✅         | ✅         | Supports downloads of: videos with or without watermark, images from slideshow without watermark, full (original) audios. |
 | Tumblr                  | ✅           | ✅         | ✅         | Support for audio file downloads.                                                                                         |
-| Twitter*                | ✅           | ✅         | ✅         | Ability to pick what to save from multi-media tweets.                                                                     |
+| Twitter/X *             | ✅           | ✅         | ✅         | Ability to pick what to save from multi-media tweets.                                                                     |
 | Vimeo                   | ✅           | ✅         | ✅         | Audio downloads are only available for dash files.                                                                        |
 | Vine Archive            | ✅           | ✅         | ✅         |                                                                                                                           |
 | VK Videos               | ✅           | ❌         | ❌         |                                                                                                                           |
diff --git a/src/modules/api.js b/src/modules/api.js
index f4b1e294..92fa5374 100644
--- a/src/modules/api.js
+++ b/src/modules/api.js
@@ -6,6 +6,7 @@ import { cleanURL, apiJSON } from "./sub/utils.js";
 import { errorUnsupported } from "./sub/errors.js";
 import loc from "../localization/manager.js";
 import match from "./processing/match.js";
+import hostOverrides from "./processing/hostOverrides.js";
 
 export async function getJSON(originalURL, lang, obj) {
     try {
@@ -15,32 +16,10 @@ export async function getJSON(originalURL, lang, obj) {
 
         if (!url.startsWith('https://')) return apiJSON(0, { t: errorUnsupported(lang) });
 
-        switch(host) {
-            case "youtu":
-                if (url.startsWith("https://youtu.be/")) {
-                    host = "youtube";
-                    url = `https://youtube.com/watch?v=${url.replace("https://youtu.be/", "")}`;
-                }
-                break;
-            case "goo":
-                if (url.substring(0, 30) === "https://soundcloud.app.goo.gl/") {
-                    host = "soundcloud";
-                    url = `https://soundcloud.com/${url.replace("https://soundcloud.app.goo.gl/", "").split('/')[0]}`
-                }
-                break;
-            case "x":
-                if (url.startsWith("https://x.com/")) {
-                    host = "twitter";
-                    url = url.replace("https://x.com/", "https://twitter.com/")
-                }
-                break;
-            case "tumblr":
-                if (!url.includes("blog/view")) {
-                    if (url.slice(-1) === '/') url = url.slice(0, -1);
-                    url = url.replace(url.split('/')[5], '')
-                }
-                break;
-        }
+        let overrides = hostOverrides(host, url);
+        host = overrides.host;
+        url = overrides.url;
+
         if (!(host && host.length < 20 && host in patterns && patterns[host]["enabled"])) return apiJSON(0, { t: errorUnsupported(lang) });
 
         let pathToMatch = cleanURL(url, host).split(`.${patterns[host]['tld'] ? patterns[host]['tld'] : "com"}/`)[1].replace('.', '');
diff --git a/src/modules/pageRender/page.js b/src/modules/pageRender/page.js
index 640745a8..754970a2 100644
--- a/src/modules/pageRender/page.js
+++ b/src/modules/pageRender/page.js
@@ -73,6 +73,8 @@ export default function(obj) {
         <link rel="stylesheet" href="fonts/notosansmono.css" rel="preload" />
         <link rel="stylesheet" href="cobalt.css" />
 
+        <link rel="me" href="${authorInfo.support.mastodon.url}">
+
         <noscript><div style="margin: 2rem;">${t('NoScriptMessage')}</div></noscript>
     </head>
     <body id="cobalt-body" ${platform === "p" ? 'class="desktop"' : ''} data-nosnippet ontouchstart>
diff --git a/src/modules/processing/hostOverrides.js b/src/modules/processing/hostOverrides.js
new file mode 100644
index 00000000..7fc7b67f
--- /dev/null
+++ b/src/modules/processing/hostOverrides.js
@@ -0,0 +1,41 @@
+export default function (inHost, inURL) {
+    let host = String(inHost);
+    let url = String(inURL);
+
+    switch(host) {
+        case "youtu":
+            if (url.startsWith("https://youtu.be/")) {
+                host = "youtube";
+                url = `https://youtube.com/watch?v=${url.replace("https://youtu.be/", "")}`;
+            }
+            break;
+        case "goo":
+            if (url.startsWith("https://soundcloud.app.goo.gl/")) {
+                host = "soundcloud";
+                url = `https://soundcloud.com/${url.replace("https://soundcloud.app.goo.gl/", "").split('/')[0]}`
+            }
+            break;
+        case "vxtwitter":
+        case "x":
+            if (url.startsWith("https://x.com/")) {
+                host = "twitter";
+                url = url.replace("https://x.com/", "https://twitter.com/")
+            }
+            if (url.startsWith("https://vxtwitter.com/")) {
+                host = "twitter";
+                url = url.replace("https://vxtwitter.com/", "https://twitter.com/")
+            }
+            break;
+        case "tumblr":
+            if (!url.includes("blog/view")) {
+                if (url.slice(-1) === '/') url = url.slice(0, -1);
+                url = url.replace(url.split('/')[5], '')
+            }
+            break;
+    }
+
+    return {
+        host: host,
+        url: url
+    }
+}
diff --git a/src/modules/processing/services/vimeo.js b/src/modules/processing/services/vimeo.js
index 56f85b83..a1c951a5 100644
--- a/src/modules/processing/services/vimeo.js
+++ b/src/modules/processing/services/vimeo.js
@@ -1,5 +1,6 @@
 import { maxVideoDuration } from "../../config.js";
 
+// vimeo you're fucked in the head for this
 const resolutionMatch = {
     "3840": "2160",
     "2732": "1440",
@@ -11,7 +12,6 @@ const resolutionMatch = {
     "640": "360",
     "426": "240"
 }
-// ^ vimeo you're fucked in the head for this ^
 
 const qualityMatch = {
     "2160": "4K",
diff --git a/src/test/tests.json b/src/test/tests.json
index e72421df..97286611 100644
--- a/src/test/tests.json
+++ b/src/test/tests.json
@@ -111,6 +111,22 @@
             "code": 200,
             "status": "redirect"
         }
+    }, {
+        "name": "twitter voice + x.com link",
+        "url": "https://x.com/eggsaladscreams/status/1693089534886506756?s=46",
+        "params": {},
+        "expected": {
+            "code": 200,
+            "status": "redirect"
+        }
+    }, {
+        "name": "vxtwitter link",
+        "url": "https://vxtwitter.com/dustbin_nie/status/1624596567188717568?s=20",
+        "params": {},
+        "expected": {
+            "code": 200,
+            "status": "redirect"
+        }
     }, {
         "name": "retweeted video, isAudioOnly",
         "url": "https://twitter.com/hugekiwinuts/status/1618671150829309953?s=46&t=gItGzgwGQQJJaJrO6qc1Pg",