Spaces:
Running
Running
import { extract, normalizeURL } from "../url.js"; | |
import { genericUserAgent } from "../../config.js"; | |
import { createStream } from "../../stream/manage.js"; | |
import { getRedirectingURL } from "../../misc/utils.js"; | |
const SPOTLIGHT_VIDEO_REGEX = /<link data-react-helmet="true" rel="preload" href="([^"]+)" as="video"\/>/; | |
const NEXT_DATA_REGEX = /<script id="__NEXT_DATA__" type="application\/json">({.+})<\/script><\/body><\/html>$/; | |
async function getSpotlight(id) { | |
const html = await fetch(`https://www.snapchat.com/spotlight/${id}`, { | |
headers: { 'user-agent': genericUserAgent } | |
}).then((r) => r.text()).catch(() => null); | |
if (!html) { | |
return { error: "fetch.fail" }; | |
} | |
const videoURL = html.match(SPOTLIGHT_VIDEO_REGEX)?.[1]; | |
if (videoURL && new URL(videoURL).hostname.endsWith(".sc-cdn.net")) { | |
return { | |
urls: videoURL, | |
filename: `snapchat_${id}.mp4`, | |
audioFilename: `snapchat_${id}_audio` | |
} | |
} | |
} | |
async function getStory(username, storyId, alwaysProxy) { | |
const html = await fetch( | |
`https://www.snapchat.com/add/${username}${storyId ? `/${storyId}` : ''}`, | |
{ headers: { 'user-agent': genericUserAgent } } | |
) | |
.then((r) => r.text()) | |
.catch(() => null); | |
if (!html) { | |
return { error: "fetch.fail" }; | |
} | |
const nextDataString = html.match(NEXT_DATA_REGEX)?.[1]; | |
if (nextDataString) { | |
const data = JSON.parse(nextDataString); | |
const storyIdParam = data.query.profileParams[1]; | |
if (storyIdParam && data.props.pageProps.story) { | |
const story = data.props.pageProps.story.snapList.find((snap) => snap.snapId.value === storyIdParam); | |
if (story) { | |
if (story.snapMediaType === 0) { | |
return { | |
urls: story.snapUrls.mediaUrl, | |
filename: `snapchat_${storyId}.jpg`, | |
isPhoto: true | |
} | |
} | |
return { | |
urls: story.snapUrls.mediaUrl, | |
filename: `snapchat_${storyId}.mp4`, | |
audioFilename: `snapchat_${storyId}_audio` | |
} | |
} | |
} | |
const defaultStory = data.props.pageProps.curatedHighlights[0]; | |
if (defaultStory) { | |
return { | |
picker: defaultStory.snapList.map(snap => { | |
const snapType = snap.snapMediaType === 0 ? "photo" : "video"; | |
const snapExt = snapType === "video" ? "mp4" : "jpg"; | |
let snapUrl = snap.snapUrls.mediaUrl; | |
const proxy = createStream({ | |
service: "snapchat", | |
type: "proxy", | |
u: snapUrl, | |
filename: `snapchat_${username}_${snap.timestampInSec.value}.${snapExt}`, | |
}); | |
let thumbProxy; | |
if (snapType === "video") thumbProxy = createStream({ | |
service: "snapchat", | |
type: "proxy", | |
u: snap.snapUrls.mediaPreviewUrl.value, | |
}); | |
if (alwaysProxy) snapUrl = proxy; | |
return { | |
type: snapType, | |
url: snapUrl, | |
thumb: thumbProxy || proxy, | |
} | |
}) | |
} | |
} | |
} | |
} | |
export default async function (obj) { | |
let params = obj; | |
if (obj.shortLink) { | |
const link = await getRedirectingURL(`https://t.snapchat.com/${obj.shortLink}`); | |
if (!link?.startsWith('https://www.snapchat.com/')) { | |
return { error: "fetch.short_link" }; | |
} | |
const extractResult = extract(normalizeURL(link)); | |
if (extractResult?.host !== 'snapchat') { | |
return { error: "fetch.short_link" }; | |
} | |
params = extractResult.patternMatch; | |
} | |
if (params.spotlightId) { | |
const result = await getSpotlight(params.spotlightId); | |
if (result) return result; | |
} else if (params.username) { | |
const result = await getStory(params.username, params.storyId, obj.alwaysProxy); | |
if (result) return result; | |
} | |
return { error: "fetch.fail" }; | |
} | |