nakama/backend/routes/search.js

208 lines
5.7 KiB
JavaScript
Raw Normal View History

2025-11-03 20:35:01 +00:00
const express = require('express');
const router = express.Router();
const axios = require('axios');
const { authenticate } = require('../middleware/auth');
// Функция для создания прокси URL
function createProxyUrl(originalUrl) {
if (!originalUrl) return null;
// Кодируем URL в base64
const encodedUrl = Buffer.from(originalUrl).toString('base64');
return `/api/search/proxy/${encodedUrl}`;
}
// Эндпоинт для проксирования изображений
router.get('/proxy/:encodedUrl', async (req, res) => {
try {
const { encodedUrl } = req.params;
// Декодируем URL
const originalUrl = Buffer.from(encodedUrl, 'base64').toString('utf-8');
// Проверяем, что URL от разрешенных доменов
const allowedDomains = [
'e621.net',
'static1.e621.net',
'gelbooru.com',
'img3.gelbooru.com',
'img2.gelbooru.com',
'img1.gelbooru.com',
'simg3.gelbooru.com',
'simg4.gelbooru.com'
];
const urlObj = new URL(originalUrl);
if (!allowedDomains.some(domain => urlObj.hostname.includes(domain))) {
return res.status(403).json({ error: 'Запрещенный домен' });
}
// Запрашиваем изображение
const response = await axios.get(originalUrl, {
responseType: 'stream',
headers: {
'User-Agent': 'NakamaSpace/1.0',
'Referer': urlObj.origin
},
timeout: 30000 // 30 секунд таймаут
});
// Копируем заголовки
res.setHeader('Content-Type', response.headers['content-type']);
res.setHeader('Cache-Control', 'public, max-age=86400'); // Кешируем на 24 часа
if (response.headers['content-length']) {
res.setHeader('Content-Length', response.headers['content-length']);
}
// Стримим изображение
response.data.pipe(res);
} catch (error) {
console.error('Ошибка проксирования изображения:', error.message);
res.status(500).json({ error: 'Ошибка загрузки изображения' });
}
});
// e621 API поиск
router.get('/furry', authenticate, async (req, res) => {
try {
const { query, limit = 50, page = 1 } = req.query;
if (!query) {
return res.status(400).json({ error: 'Параметр query обязателен' });
}
const response = await axios.get('https://e621.net/posts.json', {
params: {
tags: query,
limit,
page
},
headers: {
'User-Agent': 'NakamaSpace/1.0'
}
});
const posts = response.data.posts.map(post => ({
id: post.id,
url: createProxyUrl(post.file.url),
preview: createProxyUrl(post.preview.url),
tags: post.tags.general,
rating: post.rating,
score: post.score.total,
source: 'e621'
}));
res.json({ posts });
} catch (error) {
console.error('Ошибка e621 API:', error);
res.status(500).json({ error: 'Ошибка поиска' });
}
});
// Gelbooru API поиск
router.get('/anime', authenticate, async (req, res) => {
try {
const { query, limit = 50, page = 1 } = req.query;
if (!query) {
return res.status(400).json({ error: 'Параметр query обязателен' });
}
const response = await axios.get('https://gelbooru.com/index.php', {
params: {
page: 'dapi',
s: 'post',
q: 'index',
json: 1,
tags: query,
limit,
pid: page
}
});
const posts = (response.data.post || []).map(post => ({
id: post.id,
url: createProxyUrl(post.file_url),
preview: createProxyUrl(post.preview_url),
tags: post.tags ? post.tags.split(' ') : [],
rating: post.rating,
score: post.score,
source: 'gelbooru'
}));
res.json({ posts });
} catch (error) {
console.error('Ошибка Gelbooru API:', error);
res.status(500).json({ error: 'Ошибка поиска' });
}
});
// Автокомплит тегов для e621
router.get('/furry/tags', authenticate, async (req, res) => {
try {
const { query } = req.query;
if (!query || query.length < 2) {
return res.json({ tags: [] });
}
const response = await axios.get('https://e621.net/tags.json', {
params: {
'search[name_matches]': `${query}*`,
'search[order]': 'count',
limit: 10
},
headers: {
'User-Agent': 'NakamaSpace/1.0'
}
});
const tags = response.data.map(tag => ({
name: tag.name,
count: tag.post_count
}));
res.json({ tags });
} catch (error) {
console.error('Ошибка получения тегов:', error);
res.status(500).json({ error: 'Ошибка получения тегов' });
}
});
// Автокомплит тегов для Gelbooru
router.get('/anime/tags', authenticate, async (req, res) => {
try {
const { query } = req.query;
if (!query || query.length < 2) {
return res.json({ tags: [] });
}
const response = await axios.get('https://gelbooru.com/index.php', {
params: {
page: 'dapi',
s: 'tag',
q: 'index',
json: 1,
name_pattern: `${query}%`,
orderby: 'count',
limit: 10
}
});
const tags = (response.data.tag || []).map(tag => ({
name: tag.name,
count: tag.count
}));
res.json({ tags });
} catch (error) {
console.error('Ошибка получения тегов:', error);
res.status(500).json({ error: 'Ошибка получения тегов' });
}
});
module.exports = router;