210 lines
9.3 KiB
HTML
210 lines
9.3 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Navidrome Music Sync</title>
|
||
<link rel="stylesheet" href="static/style.css">
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||
</head>
|
||
<body>
|
||
<div class="app-container">
|
||
<header class="header">
|
||
<div class="logo-group">
|
||
<span class="logo-icon">🎵</span>
|
||
<div>
|
||
<h1>Navidrome Music Sync</h1>
|
||
<p class="subtitle">Поиск, импорт и синхронизация музыки в Navidrome</p>
|
||
</div>
|
||
</div>
|
||
<div class="status-badges">
|
||
<span class="badge badge-success" id="yandexStatus">Яндекс Музыка: Активна</span>
|
||
<span class="badge badge-info" id="tracksCount">Загружено: 0</span>
|
||
{% if user %}
|
||
<span class="badge badge-user">👤 {{ user }}</span>
|
||
<a href="/logout" class="btn-logout" title="Выйти из системы">Выйти 🚪</a>
|
||
{% endif %}
|
||
</div>
|
||
</header>
|
||
|
||
<main class="main-content">
|
||
<!-- Search & Input Card -->
|
||
<section class="card input-card">
|
||
<h2>🔍 Поиск и импорт музыки</h2>
|
||
<p class="card-desc">Введите название трека/артиста (например: <b>Booker - Время колокольчиков</b>) или вставьте прямую ссылку (Яндекс, Spotify, Apple, YouTube):</p>
|
||
|
||
<form id="downloadForm" class="download-form">
|
||
<div class="input-wrapper">
|
||
<input type="text" id="urlInput" placeholder="Название трека или https://..." required autocomplete="off">
|
||
<button type="submit" id="submitBtn" class="btn btn-primary">Найти / Загрузить</button>
|
||
</div>
|
||
</form>
|
||
|
||
<div class="quick-actions">
|
||
<span>Быстрые действия:</span>
|
||
<button id="syncLikesBtn" class="btn btn-secondary">
|
||
❤️ Синхронизировать «Мне нравится» (Яндекс)
|
||
</button>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Search Results Card (Hidden by default) -->
|
||
<section class="card search-card" id="searchCard" style="display: none;">
|
||
<div class="search-header">
|
||
<h2>🎯 Результаты поиска: <span id="searchQueryLabel"></span></h2>
|
||
<button id="closeSearchBtn" class="btn-close" title="Закрыть поиск">×</button>
|
||
</div>
|
||
|
||
<div id="searchLoading" class="search-loading" style="display: none;">
|
||
<div class="spinner"></div> Ищем на Spotify, Яндекс Музыке, SoundCloud, YouTube и Apple Music...
|
||
</div>
|
||
|
||
<!-- Search Tracks -->
|
||
<div class="search-section" id="searchTracksSection">
|
||
<h3>🎵 Найденные треки</h3>
|
||
<div class="search-tracks-list" id="searchTracksList"></div>
|
||
</div>
|
||
|
||
<!-- Search Albums -->
|
||
<div class="search-section" id="searchAlbumsSection" style="margin-top: 1.5rem;">
|
||
<h3>💿 Альбомы</h3>
|
||
<div class="search-albums-grid" id="searchAlbumsList"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Smart Wave Card -->
|
||
<section class="card wave-card">
|
||
<div class="wave-header">
|
||
<div class="wave-header-title">
|
||
<h2>🌊 Моя Волна <span class="badge badge-wave">Smart Wave V2</span> <span class="badge badge-llm">🤖 Qwen 2.5</span></h2>
|
||
<p class="wave-subtitle">
|
||
Персональный контекстный поток рекомендаций. Нейросетевой реранкинг по времени суток и настроению с авто-ротацией в Navidrome.
|
||
</p>
|
||
</div>
|
||
<div class="wave-controls">
|
||
<button id="waveGenerateBtn" class="btn btn-primary">⚡ Обновить Волну</button>
|
||
<button id="waveRotateBtn" class="btn btn-outline" title="Перенести лайкнутые треки в постоянную библиотеку и очистить старые">🔄 Ротация</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Mood & Context Selector Row -->
|
||
<div class="wave-mood-row">
|
||
<div class="wave-mood-group">
|
||
<label for="waveMoodSelect" class="wave-mood-label">Режим настроения:</label>
|
||
<select id="waveMoodSelect" class="wave-mood-select">
|
||
<option value="auto" selected>🕒 Авто (по времени суток)</option>
|
||
<option value="energy">⚡ Энергия & Спорт</option>
|
||
<option value="chill">☕ Спокойствие & Чилл</option>
|
||
<option value="dark">🌙 Ночной андеграунд</option>
|
||
</select>
|
||
</div>
|
||
<div class="wave-context-badge-wrap">
|
||
<span id="waveContextLabel" class="badge badge-context">Определение контекста...</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wave-stats-row">
|
||
<div class="wave-stat">
|
||
<span class="wave-stat-label">Буфер ротации:</span>
|
||
<strong id="waveCountLabel">0 / 25 треков</strong>
|
||
</div>
|
||
<div class="wave-stat">
|
||
<span class="wave-stat-label">Объём на диске:</span>
|
||
<strong id="waveSizeLabel">0 МБ</strong>
|
||
</div>
|
||
<div class="wave-stat">
|
||
<span class="wave-stat-label">Срок хранения:</span>
|
||
<strong>7 дней</strong>
|
||
</div>
|
||
<div class="wave-stat">
|
||
<span class="wave-stat-label">Умный плейлист:</span>
|
||
<strong><a href="https://music.qpid.pro" target="_blank">Моя Волна.nsp ↗</a></strong>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="waveAnchorsContainer" class="wave-anchors" style="margin-top: 0.8rem; display: none;">
|
||
<span style="font-size: 0.8rem; color: var(--text-secondary);">Якорные исполнители вкуса:</span>
|
||
<div id="waveAnchorsList" class="wave-anchors-tags"></div>
|
||
</div>
|
||
|
||
<!-- Wave Tracks List -->
|
||
<div class="wave-tracks-container" style="margin-top: 1rem;">
|
||
<div class="wave-tracks-header">
|
||
<h3>🎵 Треки сейчас в потоке Волны</h3>
|
||
<span id="waveLoadingText" style="display: none; color: var(--accent-color); font-size: 0.82rem;">
|
||
<span class="spinner-sm"></span> Идёт поиск и загрузка рекомендаций...
|
||
</span>
|
||
</div>
|
||
<div id="waveTracksList" class="wave-tracks-list">
|
||
<p class="empty-state">Волна пуста. Нажмите «Обновить Волну» для генерации первого потока.</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Active Tasks -->
|
||
<section class="card tasks-card">
|
||
<h2>⚡ Очередь задач</h2>
|
||
<div id="tasksList" class="tasks-list">
|
||
<p class="empty-state">Нет активных загрузок</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- History -->
|
||
<section class="card history-card">
|
||
<h2>📜 Недавно загруженные треки</h2>
|
||
<div class="table-container">
|
||
<table class="tracks-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Сервис</th>
|
||
<th>Исполнитель</th>
|
||
<th>Трек</th>
|
||
<th>Альбом</th>
|
||
<th>Дата</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="historyBody">
|
||
<tr>
|
||
<td colspan="5" class="empty-state">Пока нет загрузок</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<footer class="footer">
|
||
<p>Navidrome Music Sync • Интегрировано с <a href="https://music.qpid.pro" target="_blank">music.qpid.pro</a></p>
|
||
</footer>
|
||
</div>
|
||
|
||
<!-- Floating Audio Preview Player -->
|
||
<div id="audioPlayerBar" class="audio-player-bar" style="display: none;">
|
||
<div class="player-track-info">
|
||
<img id="playerCover" class="player-cover" src="" alt="Cover" />
|
||
<div class="player-meta">
|
||
<div class="player-title-row">
|
||
<span id="playerTitle" class="player-title"></span>
|
||
<span id="playerExplicitBadge" class="badge"></span>
|
||
</div>
|
||
<span id="playerArtist" class="player-artist"></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="player-controls-container">
|
||
<audio id="globalAudioPlayer" controls preload="metadata"></audio>
|
||
</div>
|
||
|
||
<div class="player-actions">
|
||
<button id="playerImportBtn" class="btn-sm btn-import">📥 В Navidrome</button>
|
||
<button id="playerDownloadBtn" class="btn-sm btn-direct-dl">💾 Скачать</button>
|
||
<button id="playerCloseBtn" class="btn-player-close" title="Закрыть плеер">×</button>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="static/app.js"></script>
|
||
</body>
|
||
</html>
|