Compare commits

...

2 Commits

Author SHA1 Message Date
vchikalkin
88aa8eb34a fix: instagram reels download 2026-01-20 20:16:29 +03:00
Vlad Chikalkin
9a504c10a3
fix: use downr.org to download from instagram source (#6) 2026-01-20 18:25:53 +03:00
4 changed files with 91 additions and 57 deletions

View File

@ -75,7 +75,7 @@ async function getDownloadData(
}
if (isInstagram) {
const result = await getInstagramDownloadUrl(url);
const result = await getInstagramDownloadUrl(url.replace('/reel/', '/p/'));
return {
caption: result.caption,
imagesUrls: result.images,

View File

@ -0,0 +1,37 @@
import axios from 'axios';
import { wrapper } from 'axios-cookiejar-support';
import * as tough from 'tough-cookie';
const jar = new tough.CookieJar();
const headers = {
accept: '*/*',
// 'accept-language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
'content-type': 'application/json',
dnt: '1',
priority: 'u=1, i',
'sec-ch-ua': '"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'sec-gpc': '1',
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36',
};
export const getClient = async () => {
const client = wrapper(
axios.create({
headers,
jar,
withCredentials: true,
}),
);
// get session cookie
await client.get('https://downr.org/.netlify/functions/analytics');
return client;
};

View File

@ -1,48 +1,76 @@
import axios from 'axios';
import { getClient } from './client';
export type AuthorInfo = {
avatar: string;
id: number;
nickname: string;
username: string;
export type InfoRoot = {
author: string;
error: boolean;
like_count: number;
medias: Media[];
music_attribution_info: unknown;
owner: Owner;
shortcode: string;
source: string;
thumbnail: string;
time_end: number;
title: string;
type: string;
url: string;
view_count: unknown;
};
export type CarouselItem = {
export type Media = {
bandwidth?: number;
codec?: string;
extension: string;
frameRate: unknown;
id: string;
is_audio: boolean;
mimeType?: string;
quality: string;
resolution?: string;
thumbnail?: string;
type: string;
url: string;
};
export type Root = {
authorInfo: AuthorInfo;
caption: string;
carouselItems: CarouselItem[];
id: number;
mediaUrls: string[];
type: string;
url: string;
export type Owner = {
__typename: string;
ai_agent_owner_username: unknown;
friendship_status: unknown;
id: string;
is_private: boolean;
is_unpublished: boolean;
is_verified: boolean;
pk: string;
profile_pic_url: string;
show_account_transparency_details: boolean;
transparency_label: unknown;
transparency_product: unknown;
transparency_product_enabled: boolean;
username: string;
};
export async function getInstagramDownloadUrl(url: string) {
const { data } = await axios.post<Root>('https://thesocialcat.com/api/instagram-download', {
const client = await getClient();
// fetch video info
const { data } = await client.post<InfoRoot>('https://downr.org/.netlify/functions/nyt', {
url,
});
if (!data) throw new Error('err-invalid-instagram-response');
const isVideo = data.type === 'video' || !data.carouselItems.length;
const video = data.medias.find((media) => media.type === 'video');
if (isVideo) {
if (video) {
return {
caption: data.caption,
caption: data.title,
images: [],
play: data.mediaUrls.at(0),
play: video.url,
};
}
return {
caption: data.caption,
images: data.mediaUrls,
caption: data.title,
images: data.medias.map((media) => media.url),
play: undefined,
};
}

View File

@ -1,34 +1,5 @@
import { getClient } from './client';
import { MAX_VIDEO_DURATION_SECONDS } from '@/constants/limits';
import axios from 'axios';
import { wrapper } from 'axios-cookiejar-support';
import * as tough from 'tough-cookie';
const jar = new tough.CookieJar();
const headers = {
accept: '*/*',
'accept-language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
'content-type': 'application/json',
dnt: '1',
priority: 'u=1, i',
'sec-ch-ua': '"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'sec-gpc': '1',
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36',
};
const client = wrapper(
axios.create({
headers,
jar,
withCredentials: true,
}),
);
export type DownloadRoot = {
duration: number;
@ -54,10 +25,8 @@ export type Media = {
const qualityOrder = ['144p', '240p', '360p', '480p', '1080p', '720p'].reverse();
export async function getYoutubeDownloadUrl(url: string) {
// get session cookie
await client.get('https://downr.org/.netlify/functions/analytics');
// fetch video info
const client = await getClient();
// fetch info
const { data: infoData } = await client.post<InfoRoot>(
'https://downr.org/.netlify/functions/video-info',
{