orztv
update
5bab120
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" };
}