From 174cd147f77ac21305bbcf650b0223c12fb022d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Jab=C5=82o=C5=84ski?= Date: Wed, 19 Nov 2025 22:13:14 +0100 Subject: [PATCH] fix(video): add support for CMAF video format alongside DASH Reddit has transitioned from DASH to CMAF video format. This change adds support for both formats to maintain compatibility. Changes: - Update REGEX_URL_VIDEOS to match both DASH and CMAF formats - Add format capture group to preserve DASH/CMAF in URL path - Add separate proxy endpoints for /vid/:id/dash/:size and /vid/:id/cmaf/:size - Update format_url to handle 3-segment video URLs (id/format/size) - Update tests to reflect new URL format with format segment Video URLs now follow pattern: /vid/{id}/{format}/{size}.mp4 Example: /vid/abc123/cmaf/720.mp4 --- src/main.rs | 3 ++- src/utils.rs | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index dc578187..757ccfbc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -264,7 +264,8 @@ async fn main() { app.at("/instances.json").get(|_| async move { proxy_instances().await }.boxed()); // Proxy media through Redlib - app.at("/vid/:id/:size").get(|r| proxy(r, "https://v.redd.it/{id}/DASH_{size}").boxed()); + app.at("/vid/:id/dash/:size").get(|r| proxy(r, "https://v.redd.it/{id}/DASH_{size}").boxed()); + app.at("/vid/:id/cmaf/:size").get(|r| proxy(r, "https://v.redd.it/{id}/CMAF_{size}").boxed()); app.at("/hls/:id/*path").get(|r| proxy(r, "https://v.redd.it/{id}/{path}").boxed()); app.at("/img/*path").get(|r| proxy(r, "https://i.redd.it/{path}").boxed()); app.at("/thumb/:point/:id").get(|r| proxy(r, "https://{point}.thumbs.redditmedia.com/{id}").boxed()); diff --git a/src/utils.rs b/src/utils.rs index efe98b7d..805332f5 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1007,7 +1007,7 @@ static REGEX_URL_WWW: LazyLock = LazyLock::new(|| Regex::new(r"https?://w static REGEX_URL_OLD: LazyLock = LazyLock::new(|| Regex::new(r"https?://old\.reddit\.com/(.*)").unwrap()); static REGEX_URL_NP: LazyLock = LazyLock::new(|| Regex::new(r"https?://np\.reddit\.com/(.*)").unwrap()); static REGEX_URL_PLAIN: LazyLock = LazyLock::new(|| Regex::new(r"https?://reddit\.com/(.*)").unwrap()); -static REGEX_URL_VIDEOS: LazyLock = LazyLock::new(|| Regex::new(r"https?://v\.redd\.it/(.*)/DASH_([0-9]{2,4}(\.mp4|$|\?source=fallback))").unwrap()); +static REGEX_URL_VIDEOS: LazyLock = LazyLock::new(|| Regex::new(r"https?://v\.redd\.it/(.*)/(DASH|CMAF)_([0-9]{2,4}(\.mp4|$|\?source=fallback))").unwrap()); static REGEX_URL_VIDEOS_HLS: LazyLock = LazyLock::new(|| Regex::new(r"https?://v\.redd\.it/(.+)/(HLSPlaylist\.m3u8.*)$").unwrap()); static REGEX_URL_IMAGES: LazyLock = LazyLock::new(|| Regex::new(r"https?://i\.redd\.it/(.*)").unwrap()); static REGEX_URL_THUMBS_A: LazyLock = LazyLock::new(|| Regex::new(r"https?://a\.thumbs\.redditmedia\.com/(.*)").unwrap()); @@ -1030,6 +1030,7 @@ pub fn format_url(url: &str) -> String { regex.captures(url).map_or(String::new(), |caps| match segments { 1 => [format, &caps[1]].join(""), 2 => [format, &caps[1], "/", &caps[2]].join(""), + 3 => [format, &caps[1], "/", &caps[2].to_lowercase().as_str(), "/", &caps[3]].join(""), _ => String::new(), }) }; @@ -1060,7 +1061,7 @@ pub fn format_url(url: &str) -> String { "old.reddit.com" => capture(®EX_URL_OLD, "/", 1), "np.reddit.com" => capture(®EX_URL_NP, "/", 1), "reddit.com" => capture(®EX_URL_PLAIN, "/", 1), - "v.redd.it" => chain!(capture(®EX_URL_VIDEOS, "/vid/", 2), capture(®EX_URL_VIDEOS_HLS, "/hls/", 2)), + "v.redd.it" => chain!(capture(®EX_URL_VIDEOS, "/vid/", 3), capture(®EX_URL_VIDEOS_HLS, "/hls/", 2)), "i.redd.it" => capture(®EX_URL_IMAGES, "/img/", 1), "a.thumbs.redditmedia.com" => capture(®EX_URL_THUMBS_A, "/thumb/a/", 1), "b.thumbs.redditmedia.com" => capture(®EX_URL_THUMBS_B, "/thumb/b/", 1), @@ -1499,7 +1500,8 @@ mod tests { format_url("https://preview.redd.it/qwerty.jpg?auto=webp&s=asdf"), "/preview/pre/qwerty.jpg?auto=webp&s=asdf" ); - assert_eq!(format_url("https://v.redd.it/foo/DASH_360.mp4?source=fallback"), "/vid/foo/360.mp4"); + assert_eq!(format_url("https://v.redd.it/foo/DASH_360.mp4?source=fallback"), "/vid/foo/dash/360.mp4"); + assert_eq!(format_url("https://v.redd.it/foo/CMAF_720.mp4?source=fallback"), "/vid/foo/cmaf/720.mp4"); assert_eq!( format_url("https://v.redd.it/foo/HLSPlaylist.m3u8?a=bar&v=1&f=sd"), "/hls/foo/HLSPlaylist.m3u8?a=bar&v=1&f=sd"