Update files

This commit is contained in:
glpshchn 2025-12-01 04:11:27 +03:00
parent 8092d25c0c
commit 04f4bce239
2 changed files with 63 additions and 19 deletions

View File

@ -38,11 +38,20 @@ const interactionLimiter = rateLimit({
message: 'Вы слишком активны, немного подождите', message: 'Вы слишком активны, немного подождите',
}); });
// Мягкий лимит для прокси изображений (больше запросов, так как это медиа)
const proxyLimiter = rateLimit({
windowMs: 15 * 1000, // 15 секунд
max: 200, // 200 запросов (больше для загрузки множества изображений)
message: 'Слишком много запросов изображений',
skipSuccessfulRequests: true, // Не считать успешные запросы
});
module.exports = { module.exports = {
generalLimiter, generalLimiter,
postCreationLimiter, postCreationLimiter,
authLimiter, authLimiter,
searchLimiter, searchLimiter,
interactionLimiter interactionLimiter,
proxyLimiter
}; };

View File

@ -2,6 +2,7 @@ const express = require('express');
const router = express.Router(); const router = express.Router();
const axios = require('axios'); const axios = require('axios');
const { authenticate } = require('../middleware/auth'); const { authenticate } = require('../middleware/auth');
const { proxyLimiter } = require('../middleware/rateLimiter');
const config = require('../config'); const config = require('../config');
// e621 требует описательный User-Agent с контактами // e621 требует описательный User-Agent с контактами
@ -55,7 +56,8 @@ function createProxyUrl(originalUrl) {
} }
// Эндпоинт для проксирования изображений // Эндпоинт для проксирования изображений
router.get('/proxy/:encodedUrl', async (req, res) => { // Используем более мягкий rate limiter для прокси
router.get('/proxy/:encodedUrl', proxyLimiter, async (req, res) => {
try { try {
const { encodedUrl } = req.params; const { encodedUrl } = req.params;
@ -156,19 +158,34 @@ router.get('/furry', authenticate, async (req, res) => {
return res.json({ posts: [] }); return res.json({ posts: [] });
} }
// Проверка на наличие данных // Проверка на наличие данных (e621 может возвращать массив напрямую или объект с posts)
if (!response.data || !response.data.posts || !Array.isArray(response.data.posts)) { let postsData = null;
console.warn('⚠️ e621 вернул неверный формат данных');
if (Array.isArray(response.data)) {
postsData = response.data;
} else if (response.data && Array.isArray(response.data.posts)) {
postsData = response.data.posts;
} else if (response.data && Array.isArray(response.data.data)) {
postsData = response.data.data;
} else {
console.warn('⚠️ e621 вернул неверный формат данных для постов:', {
type: typeof response.data,
keys: response.data ? Object.keys(response.data) : null,
hasPosts: !!(response.data && response.data.posts),
isArray: Array.isArray(response.data)
});
return res.json({ posts: [] }); return res.json({ posts: [] });
} }
const posts = response.data.posts.map(post => ({ const posts = postsData
.filter(post => post && post.file && post.file.url) // Фильтруем посты без URL
.map(post => ({
id: post.id, id: post.id,
url: createProxyUrl(post.file.url), url: createProxyUrl(post.file.url),
preview: createProxyUrl(post.preview.url), preview: post.preview && post.preview.url ? createProxyUrl(post.preview.url) : null,
tags: post.tags.general, tags: post.tags && post.tags.general ? post.tags.general : [],
rating: post.rating, rating: post.rating || 'q',
score: post.score.total, score: post.score && post.score.total ? post.score.total : 0,
source: 'e621' source: 'e621'
})); }));
@ -312,15 +329,27 @@ router.get('/furry/tags', authenticate, async (req, res) => {
return res.json({ tags: [] }); return res.json({ tags: [] });
} }
// Проверка на массив // Проверка на массив (e621 может возвращать массив напрямую или объект с массивом)
if (!response.data || !Array.isArray(response.data)) { let tagsData = null;
console.warn('⚠️ e621 вернул не массив:', typeof response.data);
if (Array.isArray(response.data)) {
tagsData = response.data;
} else if (response.data && Array.isArray(response.data.tags)) {
tagsData = response.data.tags;
} else if (response.data && Array.isArray(response.data.data)) {
tagsData = response.data.data;
} else {
console.warn('⚠️ e621 вернул неверный формат данных для тегов:', {
type: typeof response.data,
keys: response.data ? Object.keys(response.data) : null,
data: response.data
});
return res.json({ tags: [] }); return res.json({ tags: [] });
} }
const tags = response.data.map(tag => ({ const tags = tagsData.map(tag => ({
name: tag.name, name: tag.name,
count: tag.post_count count: tag.post_count || tag.count || 0
})); }));
const payload = { tags }; const payload = { tags };
@ -351,6 +380,12 @@ router.get('/anime/tags', authenticate, async (req, res) => {
return res.json({ tags: [] }); return res.json({ tags: [] });
} }
const cacheKey = getCacheKey('gelbooru-tags', { query: query.trim().toLowerCase() });
const cached = getFromCache(cacheKey);
if (cached) {
return res.json(cached);
}
try { try {
const response = await axios.get('https://gelbooru.com/index.php', { const response = await axios.get('https://gelbooru.com/index.php', {
params: { params: {