
News
- 1 installs
- 1 repo stars
- Updated February 23, 2026
- criandonegocioia/narcissus
Automate Instagram content creation, publishing, and scheduling using AI image/video generation.
About
Narcissus is a full-stack AI automation platform for Instagram that generates images with LoRA/Gemini, creates videos with Kling, and publishes via WhatsApp/Telegram bots.
- LoRA fine-tuned image generation
- Multi-channel bot interfaces
News by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,710 of 1,879 Marketing & SEO skills by installs in the Skillselion catalog
- Data as of Jul 8, 2026 (Skillselion catalog sync)
npx skills add https://github.com/criandonegocioia/narcissus --skill newsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 1 |
| Last updated | February 23, 2026 |
| Repository | criandonegocioia/narcissus ↗ |
What it does
Automate Instagram content creation, publishing, and scheduling using AI image/video generation.
Files
News Skill
This skill retrieves current events and news articles.
Scripts
scripts/news_service.js: News API integration.
const axios = require('axios');
class NewsService {
constructor(config, researchService) {
this.config = config;
this.researchService = researchService;
}
async getTrends(topic = 'instagram') {
console.log(`📰 NewsService: Fetching trends for "${topic}"...`);
let results = [];
// 1. Priority: Perplexity AI (if key exists)
if (this.config.perplexityKey) {
results = await this.fetchPerplexity(topic);
}
// 2. Fallback: X (Twitter) via Google RSS
if (results.length === 0) {
results = await this.fetchXTrends(topic);
}
// Strategy Selection
const isTech = ['tech', 'ai', 'dev', 'code', 'programming'].some(k => topic.toLowerCase().includes(k));
if (results.length === 0 && isTech) {
results = await this.fetchTabNews(topic);
}
// Fallback or Primary for non-tech: Google RSS (General)
if (results.length === 0) {
results = await this.fetchGoogleRSS(topic);
}
return results;
}
async fetchPerplexity(topic) {
console.log(` 🧠 Fetching from Perplexity AI...`);
try {
const response = await axios.post('https://api.perplexity.ai/chat/completions', {
model: 'llama-3.1-sonar-small-128k-online',
messages: [
{ role: 'system', content: 'You are a news aggregator. Return a JSON array of 3 recent news items about the topic. Format: [{"title": "...", "snippet": "...", "url": "..."}]. Do not include markdown code blocks.' },
{ role: 'user', content: `Latest news about ${topic}` }
]
}, {
headers: {
'Authorization': `Bearer ${this.config.perplexityKey}`,
'Content-Type': 'application/json'
}
});
const content = response.data.choices[0].message.content;
// Clean up if markdown is present
const jsonStr = content.replace(/```json/g, '').replace(/```/g, '').trim();
const items = JSON.parse(jsonStr);
return items;
} catch (e) {
console.error("❌ Perplexity Error:", e.response ? e.response.data : e.message);
return [];
}
}
async fetchXTrends(topic) {
console.log(` 🐦 Fetching X (Twitter) trends via Google RSS...`);
try {
// Use Google News RSS to bypass scraper blocks
// This returns recent X posts indexed by Google News
const query = `site:x.com ${topic}`;
const url = `https://news.google.com/rss/search?q=${encodeURIComponent(query)}&hl=pt-BR&gl=BR&ceid=BR:pt-419`;
const response = await axios.get(url, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
},
timeout: 5000
});
const xml = response.data;
const items = [];
const regex = /<item>[\s\S]*?<title>(.*?)<\/title>[\s\S]*?<link>(.*?)<\/link>[\s\S]*?<\/item>/g;
let match;
while ((match = regex.exec(xml)) !== null) {
if (items.length >= 3) break;
let title = match[1].replace('<![CDATA[', '').replace(']]>', '');
// Clean title
title = title.replace(/\s-\sRx\.com$/, '').replace(/\s-\sx\.com$/, '');
items.push({
title: title,
url: match[2],
snippet: "Tweet encontrado via Google News"
});
}
return items;
} catch (e) {
console.error("❌ X Trends Error:", e.message);
return [];
}
}
async fetchTabNews(topic) {
try {
// Strategy: relevant or new
const url = `https://www.tabnews.com.br/api/v1/contents?strategy=relevant`;
const response = await axios.get(url, { timeout: 5000 });
// Filter slightly if possible, or just return top relevant
// TabNews doesn't have search via API easily, so we get top relevant
return response.data.slice(0, 3).map(item => ({
title: item.title,
url: `https://www.tabnews.com.br/${item.owner_username}/${item.slug}`,
snippet: `TabNews: ${item.tabcoins} tabcoins - ${item.children_deep_count} coments`
}));
} catch (e) {
console.error("❌ TabNews Error:", e.message);
return [];
}
}
async fetchGoogleRSS(query) {
try {
// Mapping topics to better search queries
const queryMap = {
'instagram': 'instagram marketing trends 2025',
'ai_marketing': 'inteligencia artificial marketing tendencias',
'tech': 'tecnologia inovação noticias'
};
const actualQuery = queryMap[query] || query;
const url = `https://news.google.com/rss/search?q=${encodeURIComponent(actualQuery)}&hl=pt-BR&gl=BR&ceid=BR:pt-419`;
const response = await axios.get(url, { timeout: 5000 });
const xml = response.data;
const items = [];
const regex = /<item>[\s\S]*?<title>(.*?)<\/title>[\s\S]*?<link>(.*?)<\/link>[\s\S]*?<\/item>/g;
let match;
while ((match = regex.exec(xml)) !== null) {
if (items.length >= 3) break;
items.push({
title: match[1].replace('<![CDATA[', '').replace(']]>', ''),
url: match[2],
snippet: "Google News"
});
}
return items;
} catch (e) {
console.error("❌ Google RSS Error:", e.message);
return [];
}
}
}
module.exports = NewsService;