diff --git a/README.md b/README.md
index 9d6bb9a9..d5fe8164 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,7 @@ this list is not final and keeps expanding over time. if support for a service y
| pinterest | ✅ | ✅ | ✅ | ➖ | ➖ |
| reddit | ✅ | ✅ | ✅ | ❌ | ❌ |
| rutube | ✅ | ✅ | ✅ | ✅ | ✅ |
+| snapchat stories & spotlights | ✅ | ✅ | ✅ | ➖ | ➖ |
| soundcloud | ➖ | ✅ | ➖ | ✅ | ✅ |
| streamable | ✅ | ✅ | ✅ | ➖ | ➖ |
| tiktok | ✅ | ✅ | ✅ | ❌ | ❌ |
@@ -49,6 +50,7 @@ this list is not final and keeps expanding over time. if support for a service y
| facebook | supports public accessible videos content only. |
| pinterest | supports photos, gifs, videos and stories. |
| reddit | supports gifs and videos. |
+| snapchat | supports spotlights and stories. lets you pick what to save from stories. |
| rutube | supports yappy & private links. |
| soundcloud | supports private links. |
| tiktok | supports videos with or without watermark, images from slideshow without watermark, and full (original) audios. |
diff --git a/src/modules/processing/match.js b/src/modules/processing/match.js
index 59bc2dd9..3c16a75b 100644
--- a/src/modules/processing/match.js
+++ b/src/modules/processing/match.js
@@ -24,6 +24,7 @@ import streamable from "./services/streamable.js";
import twitch from "./services/twitch.js";
import rutube from "./services/rutube.js";
import dailymotion from "./services/dailymotion.js";
+import snapchat from "./services/snapchat.js";
import loom from "./services/loom.js";
import facebook from "./services/facebook.js";
@@ -189,6 +190,14 @@ export default async function(host, patternMatch, lang, obj) {
case "dailymotion":
r = await dailymotion(patternMatch);
break;
+ case "snapchat":
+ r = await snapchat({
+ url,
+ username: patternMatch.username,
+ storyId: patternMatch.storyId,
+ spotlightId: patternMatch.spotlightId,
+ shortLink: patternMatch.shortLink || false
+ });
case "loom":
r = await loom({
id: patternMatch.id
diff --git a/src/modules/processing/matchActionDecider.js b/src/modules/processing/matchActionDecider.js
index 74f0ec49..7643d491 100644
--- a/src/modules/processing/matchActionDecider.js
+++ b/src/modules/processing/matchActionDecider.js
@@ -73,6 +73,7 @@ export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, di
switch (host) {
case "instagram":
case "twitter":
+ case "snapchat":
params = { picker: r.picker };
break;
case "tiktok":
@@ -136,6 +137,7 @@ export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, di
case "tumblr":
case "pinterest":
case "streamable":
+ case "snapchat":
case "loom":
responseType = "redirect";
break;
diff --git a/src/modules/processing/services/snapchat.js b/src/modules/processing/services/snapchat.js
new file mode 100644
index 00000000..44a2b84e
--- /dev/null
+++ b/src/modules/processing/services/snapchat.js
@@ -0,0 +1,96 @@
+import { genericUserAgent } from "../../config.js";
+import { getRedirectingURL } from "../../sub/utils.js";
+import { extract, normalizeURL } from "../url.js";
+
+const SPOTLIGHT_VIDEO_REGEX = //;
+const NEXT_DATA_REGEX = /