feat(1.0.13): тематики, стриминг поиска, авто-логотипы
- Тематики: 14 курированных категорий (Зомби, Космос, Вампиры, Постапокалипсис, Шпионы и т.д.) поверх жанров TMDB. discover-tmdb принимает themeKeywords (pipe-OR по with_keywords); для musical/ superhero/martial добавлен extraGenre AND-связкой в movie-режиме. - Стриминг поиска по сайтам: search-movies переведён с invoke→return на event-emit — карточки появляются по мере ответа каждого сайта, не ждут самого медленного. Спиннер виден до первого результата. - Авто-детект логотипа сайта: поле "URL иконки" убрано из формы. Бэк IPC detect-logo пробует manifest.json → apple-touch-icon → link rel=icon ≥48px → JSON-LD → og:image → msapplication-TileImage → /favicon.ico (с проверкой content-type=image/*). Легаси-приложения без иконки догоняются тихо при открытии Settings.
This commit is contained in:
@@ -66,9 +66,33 @@ const Settings: React.FC<SettingsProps> = ({ onClose, onAppsChange }) => {
|
||||
const [settings, setSettings] = useState<SettingsData>(DEFAULT_SETTINGS)
|
||||
const [newApp, setNewApp] = useState<AppEntry>({ name: '', imageUrl: '', url: '', useProxy: false })
|
||||
|
||||
// Тихая авто-детекция логотипа: обновляет imageUrl в state+config когда сервер вернёт URL.
|
||||
// Если детект ничего не нашёл — оставляем пустой imageUrl (тогда отобразится буква-заглушка).
|
||||
const autoDetectLogo = (appUrl: string, onDetected: (logoUrl: string) => void) => {
|
||||
if (!window.electron?.detectLogo) return
|
||||
window.electron.detectLogo(appUrl).then(logoUrl => {
|
||||
if (logoUrl) onDetected(logoUrl)
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
window.electron?.readConfig().then((cfg: SettingsData | null) => {
|
||||
if (cfg?.apps) setSettings(cfg)
|
||||
if (!cfg?.apps) return
|
||||
setSettings(cfg)
|
||||
// Догоняем легаси-приложения без иконки: тихо парсим и обновляем конфиг.
|
||||
const missing = cfg.apps.filter(a => !a.imageUrl && a.url)
|
||||
if (!missing.length) return
|
||||
missing.forEach(target => {
|
||||
autoDetectLogo(target.url, logoUrl => {
|
||||
setSettings(prev => {
|
||||
const apps = prev.apps.map(a => a.url === target.url && !a.imageUrl ? { ...a, imageUrl: logoUrl } : a)
|
||||
const updated = { ...prev, apps }
|
||||
saveSettings(updated)
|
||||
onAppsChange(apps)
|
||||
return updated
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}, [])
|
||||
|
||||
@@ -91,12 +115,23 @@ const Settings: React.FC<SettingsProps> = ({ onClose, onAppsChange }) => {
|
||||
|
||||
const addApp = () => {
|
||||
if (!newApp.name || !newApp.url) return
|
||||
const apps = [...settings.apps, newApp]
|
||||
const fresh: AppEntry = { ...newApp, imageUrl: '' }
|
||||
const apps = [...settings.apps, fresh]
|
||||
const updated = { ...settings, apps }
|
||||
setSettings(updated)
|
||||
saveSettings(updated)
|
||||
onAppsChange(apps)
|
||||
setNewApp({ name: '', imageUrl: '', url: '', useProxy: false })
|
||||
// Тихо детектим логотип в фоне; UI получит иконку, когда сервер ответит.
|
||||
autoDetectLogo(fresh.url, logoUrl => {
|
||||
setSettings(prev => {
|
||||
const nextApps = prev.apps.map(a => a.url === fresh.url && !a.imageUrl ? { ...a, imageUrl: logoUrl } : a)
|
||||
const next = { ...prev, apps: nextApps }
|
||||
saveSettings(next)
|
||||
onAppsChange(nextApps)
|
||||
return next
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const removeApp = (index: number) => {
|
||||
@@ -268,12 +303,6 @@ const Settings: React.FC<SettingsProps> = ({ onClose, onAppsChange }) => {
|
||||
value={newApp.url}
|
||||
onChange={e => setNewApp({ ...newApp, url: e.target.value })}
|
||||
/>
|
||||
<input
|
||||
className="settings-input"
|
||||
placeholder="URL иконки (необязательно)"
|
||||
value={newApp.imageUrl}
|
||||
onChange={e => setNewApp({ ...newApp, imageUrl: e.target.value })}
|
||||
/>
|
||||
<label className="proxy-switch-label add-proxy-label">
|
||||
<span>Использовать прокси</span>
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user