|
import got from 'got'; |
|
import * as cheerio from 'cheerio'; |
|
import { TwitterDlArgsSchema, TwitterDLResponseSchema, TwitterDlSchema } from '../types/twitter-v1.js'; |
|
import { DEFAULT_HEADERS } from '../constant.js'; |
|
import { stringifyCookies, generateTokenId } from './util.js'; |
|
|
|
export async function twitterdl(url) { |
|
if (!url || typeof url !== 'string') { |
|
throw new Error("Invalid or missing URL parameter."); |
|
} |
|
|
|
TwitterDlArgsSchema.parse([url]); |
|
|
|
const idMatch = url.match(/status\/(\d+)/) || url.match(/(\d+)/); |
|
if (!idMatch) { |
|
throw new Error("Invalid Twitter URL: Cannot extract tweet ID."); |
|
} |
|
|
|
const id = idMatch[1]; |
|
const token = generateTokenId(id); |
|
|
|
try { |
|
const data = await got(`https://api.redketchup.io/tweetAttachments-v6?id=${encodeURIComponent(token)}`, { |
|
headers: { |
|
...DEFAULT_HEADERS, |
|
origin: 'https://redketchup.io', |
|
referer: 'https://redketchup.io/', |
|
} |
|
}).json(); |
|
|
|
if (!data || !data.includes || !data.includes.media) { |
|
throw new Error("Invalid API response: Missing media data."); |
|
} |
|
|
|
const json = TwitterDLResponseSchema.parse(data); |
|
const videos = json.includes.media |
|
.filter((m) => m.type === 'video') |
|
.flatMap((m) => m.variants) |
|
.filter((v) => v.content_type !== 'application/x-mpegURL'); |
|
|
|
const result = Array.isArray(videos) ? videos : [videos]; |
|
return result |
|
|
|
} catch (error) { |
|
console.error("Error fetching Twitter video:", error.message); |
|
throw new Error("Failed to fetch Twitter video. Please try again later."); |
|
} |
|
} |
|
|
|
|