rsshub
Version:
Make RSS Great Again!
147 lines (133 loc) • 5.09 kB
text/typescript
import { Route, ViewType } from '@/types';
import cache from '@/utils/cache';
import { ig, login } from './utils';
import logger from '@/utils/logger';
import { config } from '@/config';
import { renderItems } from '../common-utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
// loadContent pulls the desired user/tag/etc
async function loadContent(category, nameOrId, tryGet) {
let feedTitle, feedLink, feedDescription, feedLogo;
let itemsRaw;
switch (category) {
case 'user': {
let userInfo, username, id;
if (Number.isNaN(nameOrId)) {
username = nameOrId;
id = await tryGet(`instagram:getIdByUsername:${username}`, () => ig.user.getIdByUsername(username), 31_536_000); // 1 year since it will never change
userInfo = await tryGet(`instagram:userInfo:${id}`, () => ig.user.info(id));
} else {
id = nameOrId;
userInfo = await tryGet(`instagram:userInfo:${id}`, () => ig.user.info(id));
username = userInfo.username;
}
feedDescription = userInfo.biography;
// exists in web api ?? exist in private api ?? exist in both
feedLogo = userInfo.profile_pic_url_hd ?? userInfo.hd_profile_pic_url_info?.url ?? userInfo.profile_pic_url;
const fullName = userInfo.full_name;
feedTitle = `${fullName} (@${username}) - Instagram`;
feedLink = `https://www.instagram.com/${username}`;
itemsRaw = await tryGet(`instagram:feed:${id}`, () => ig.feed.user(id).items(), config.cache.routeExpire, false);
break;
}
case 'tags': {
const tag = nameOrId;
feedTitle = `#${tag} - Instagram`;
feedLink = `https://www.instagram.com/explore/tags/${tag}`;
itemsRaw = await tryGet(`instagram:tags:${tag}`, () => ig.feed.tags(tag, 'recent').items(), config.cache.routeExpire, false);
break;
}
default:
break;
}
return {
feedTitle,
feedLink,
feedDescription,
feedLogo,
itemsRaw,
};
}
export const route: Route = {
path: '/:category/:key',
categories: ['social-media'],
view: ViewType.SocialMedia,
example: '/instagram/user/stefaniejoosten',
parameters: {
category: {
description: 'Feed category',
default: 'user',
options: [
{
label: 'User',
value: 'user',
},
{
label: 'Tags',
value: 'tags',
},
],
},
key: 'Username / Hashtag name',
},
features: {
requireConfig: [
{
name: 'IG_PROXY',
optional: true,
description: '',
},
{
name: 'IG_USERNAME',
description: 'Instagram username',
},
{
name: 'IG_PASSWORD',
description: 'Instagram password, due to [Instagram Private API](https://github.com/dilame/instagram-private-api) restrictions, you have to setup your credentials on the server. 2FA is not supported.',
},
],
requirePuppeteer: false,
antiCrawler: true,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
name: 'User Profile / Hashtag - Private API',
maintainers: ['oppilate', 'DIYgod'],
handler,
};
async function handler(ctx) {
// https://github.com/dilame/instagram-private-api#feeds
// const availableCategories = ["accountFollowers", "accountFollowing", "news",
// "discover", "pendingFriendships", "blockedUsers", "directInbox", "directPending",
// "directThread", "user", "tag", "location", "mediaComments", "reelsMedia", "reelsTray",
// "timeline", "musicTrending", "musicSearch", "musicGenre", "musicMood", "usertags", "saved"];
const availableCategories = ['user', 'tags'];
// Unique key for a feed category
// e.g. username for user feed
const { category, key } = ctx.req.param();
if (!availableCategories.includes(category)) {
throw new InvalidParameterError('Such feed is not supported.');
}
if (config.instagram && config.instagram.proxy) {
ig.state.proxyUrl = config.instagram.proxy;
}
await login(ig, cache);
let data;
try {
data = await loadContent(category, key, cache.tryGet);
} catch (error) {
logger.error(`Instagram error: ${error}`);
throw error;
}
return {
title: data.feedTitle,
link: data.feedLink,
description: data.feedDescription,
item: renderItems(data.itemsRaw),
icon: 'https://www.instagram.com/static/images/ico/xxhdpi_launcher.png/99cf3909d459.png',
logo: data.feedLogo,
image: data.feedLogo,
allowEmpty: true,
};
}