Add multiple features: auth, uploads, queue management, and filters

- Replace email with username for authentication
  - Update User model, schemas, and auth endpoints
  - Update frontend login and register views
  - Add migration to remove email column

- Add multiple track upload support
  - New backend endpoint for bulk upload
  - Frontend multi-file selection with progress
  - Auto-extract metadata from ID3 tags
  - Visual upload progress for each file

- Prevent duplicate tracks in room queue
  - Backend validation for duplicates
  - Visual indication of tracks already in queue
  - Error handling with user feedback

- Add bulk track selection for rooms
  - Multi-select mode with checkboxes
  - Bulk add endpoint with duplicate filtering
  - Selection counter and controls

- Add track filters in room modal
  - Search by title and artist
  - Filter by "My tracks"
  - Filter by "Not in queue"
  - Live filtering with result counter

- Improve Makefile
  - Add build-backend and build-frontend commands
  - Add rebuild-backend and rebuild-frontend commands
  - Add rebuild-clean variants
  - Update migrations to run in Docker

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-19 19:22:35 +03:00
parent fdc854256c
commit 8a2ea5b4af
17 changed files with 848 additions and 143 deletions

View File

@@ -4,8 +4,8 @@
<h2>Вход</h2>
<form @submit.prevent="handleLogin">
<div class="form-group">
<label>Email</label>
<input type="email" v-model="email" required />
<label>Имя пользователя</label>
<input type="text" v-model="username" required />
</div>
<div class="form-group">
<label>Пароль</label>
@@ -31,7 +31,7 @@ import { useAuthStore } from '../stores/auth'
const router = useRouter()
const authStore = useAuthStore()
const email = ref('')
const username = ref('')
const password = ref('')
const error = ref('')
const loading = ref(false)
@@ -41,7 +41,7 @@ async function handleLogin() {
loading.value = true
try {
await authStore.login(email.value, password.value)
await authStore.login(username.value, password.value)
router.push('/')
} catch (e) {
error.value = e.response?.data?.detail || 'Ошибка входа'