init: media-center v2

Rewrite of ESH-Media v1 with separated main/renderer/shared architecture
(vite-plugin-electron, React 18, react-router-dom). Includes NeDB storage,
electron-store config, proxy manager with FoxyProxy/uBlock extensions,
custom server-checked updater, NSIS installer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 23:49:43 +03:00
commit ecb5e7e49f
52 changed files with 11718 additions and 0 deletions

271
SEARCH_SCRIPTS.md Normal file
View File

@@ -0,0 +1,271 @@
# Система Поисковых Скриптов
## Обзор
Media Center использует систему кастомных JavaScript скриптов для поиска контента на различных сайтах. Каждый сайт имеет свой собственный скрипт, который знает, как выполнять поиск на этом конкретном сайте.
## Преимущества подхода
1. **Гибкость**: Каждый сайт может иметь уникальную логику поиска
2. **Расширяемость**: Легко добавлять новые сайты без изменения основного кода
3. **Обновляемость**: Скрипты можно обновлять с сервера
4. **Нет зависимости от Node.js**: Скрипты выполняются в контексте Electron
## Структура скрипта
Каждый скрипт - это JavaScript файл, который экспортирует функцию `search`:
```javascript
async function search(query, siteUrl, useProxy, axios, cheerio, proxyConfig) {
// Ваша логика поиска
return [
{
name: "Название фильма",
url: "https://site.com/movie/123",
image: "https://site.com/poster.jpg", // опционально
year: "2023", // опционально
description: "Описание фильма", // опционально
rating: "8.5" // опционально
}
];
}
```
### Параметры функции
- `query` (string) - поисковый запрос пользователя
- `siteUrl` (string) - базовый URL сайта
- `useProxy` (boolean) - флаг использования прокси
- `axios` - HTTP клиент для запросов
- `cheerio` - библиотека для парсинга HTML
- `proxyConfig` - объект с настройками прокси `{host, port}`
### Возвращаемое значение
Массив объектов с результатами. Обязательные поля:
- `name` - название фильма/сериала
- `url` - ссылка на страницу
Опциональные поля:
- `image` - URL постера
- `year` - год выпуска
- `description` - краткое описание
- `rating` - рейтинг
## Доступные инструменты
### axios
HTTP клиент для выполнения запросов:
```javascript
// GET запрос
const response = await axios.get('https://site.com/search', {
params: { q: query },
timeout: 15000,
headers: {
'User-Agent': 'Mozilla/5.0...'
}
});
// POST запрос
const response = await axios.post('https://site.com/search', {
query: query
}, {
timeout: 15000
});
// С прокси
if (useProxy && proxyConfig) {
const response = await axios.get(url, {
proxy: {
host: proxyConfig.host,
port: proxyConfig.port
}
});
}
```
### cheerio
jQuery-подобная библиотека для парсинга HTML:
```javascript
const $ = cheerio.load(html);
// Поиск элементов
const title = $('.movie-title').text();
const link = $('a.movie-link').attr('href');
// Итерация по элементам
$('.movie-card').each((index, element) => {
const $el = $(element);
const name = $el.find('.title').text().trim();
const url = $el.find('a').attr('href');
});
```
## Примеры реализаций
### Пример 1: HTML парсинг (Kinogo)
```javascript
async function search(query, siteUrl, useProxy, axios, cheerio, proxyConfig) {
const config = {
params: { do: 'search', subaction: 'search', story: query },
timeout: 15000,
headers: { 'User-Agent': 'Mozilla/5.0...' }
};
if (useProxy && proxyConfig) {
config.proxy = { host: proxyConfig.host, port: proxyConfig.port };
}
const response = await axios.get(`${siteUrl}/index.php`, config);
const $ = cheerio.load(response.data);
const results = [];
$('.shortstory').each((i, el) => {
const $item = $(el);
const name = $item.find('.title a').text().trim();
const url = $item.find('.title a').attr('href');
const image = $item.find('img').attr('src');
if (name && url) {
results.push({ name, url: siteUrl + url, image });
}
});
return results;
}
```
### Пример 2: JSON API (Rutube)
```javascript
async function search(query, siteUrl, useProxy, axios, cheerio, proxyConfig) {
const config = {
params: { query, limit: 20 },
timeout: 15000
};
const response = await axios.get(`${siteUrl}/api/search/video/`, config);
const data = response.data;
if (!data.results) return [];
return data.results.map(item => ({
name: item.title,
url: item.video_url || `${siteUrl}/video/${item.id}`,
image: item.thumbnail_url,
description: item.description
}));
}
```
## Хранение скриптов
Скрипты хранятся в двух местах:
1. **Встроенные скрипты**: `<app>/search-scripts/`
- Поставляются с приложением
- Только для чтения
- Используются по умолчанию
2. **Пользовательские скрипты**: `<userData>/search-scripts/`
- Загружаются с сервера
- Можно обновлять
- Имеют приоритет над встроенными
## Конфигурация сайта
В `config/sites.json`:
```json
{
"id": "kinogo",
"name": "Kinogo",
"url": "https://kinogo.biz",
"logo": "https://kinogo.biz/favicon.ico",
"enabled": true,
"useProxy": true,
"searchScript": "kinogo.js"
}
```
## Создание нового скрипта
1. Скопируйте `SCRIPT_TEMPLATE.js`
2. Назовите файл по имени сайта (например, `mysite.js`)
3. Реализуйте функцию `search()`
4. Протестируйте с разными запросами
5. Добавьте сайт в конфигурацию
## Обновление скриптов с сервера
Пользователи могут обновлять скрипты через настройки приложения:
1. Настройки → Конфигурация
2. Кнопка "Обновить конфигурацию"
3. Скачиваются новые скрипты и конфигурация
4. Применяются автоматически
## Безопасность
- Скрипты выполняются в изолированном контексте
- Таймаут выполнения: 30 секунд
- Нет доступа к файловой системе
- Нет доступа к другим модулям Node.js
- Только axios и cheerio
## Отладка
Для отладки скриптов:
1. Откройте DevTools (F12 в приложении)
2. Выполните поиск
3. Проверьте консоль на наличие ошибок
4. Логи включают:
- Найденное количество результатов
- Ошибки выполнения
- Невалидные результаты
## Требования к серверу
Сервер должен предоставлять:
### GET /api/config/sites
Возвращает конфигурацию со списком сайтов и ссылками на скрипты:
```json
{
"version": "1.0.0",
"lastUpdated": "2025-10-14T12:00:00Z",
"sites": [
{
"id": "kinogo",
"name": "Kinogo",
"url": "https://kinogo.biz",
"logo": "https://kinogo.biz/favicon.ico",
"enabled": true,
"useProxy": true,
"searchScript": "kinogo.js",
"scriptUrl": "https://server.com/scripts/kinogo.js"
}
]
}
```
### GET /scripts/{scriptName}
Возвращает содержимое скрипта (JavaScript файл).
## Best Practices
1. **Обработка ошибок**: Всегда оборачивайте код в try-catch
2. **Таймауты**: Устанавливайте разумные таймауты для запросов
3. **Валидация**: Проверяйте наличие обязательных полей
4. **User-Agent**: Используйте реалистичный User-Agent
5. **Относительные URL**: Преобразуйте в абсолютные
6. **Пустые результаты**: Возвращайте `[]` при ошибке, а не `null`