This commit is contained in:
2025-12-12 13:30:09 +03:00
commit 2f1e1f35e3
75 changed files with 4603 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import api from '../composables/useApi'
export const useAuthStore = defineStore('auth', () => {
const token = ref(localStorage.getItem('token') || null)
const user = ref(null)
const isAuthenticated = computed(() => !!token.value)
async function login(email, password) {
const response = await api.post('/api/auth/login', { email, password })
token.value = response.data.access_token
localStorage.setItem('token', token.value)
await fetchUser()
}
async function register(username, email, password) {
const response = await api.post('/api/auth/register', { username, email, password })
token.value = response.data.access_token
localStorage.setItem('token', token.value)
await fetchUser()
}
async function fetchUser() {
if (!token.value) return
try {
const response = await api.get('/api/auth/me')
user.value = response.data
} catch (error) {
logout()
}
}
function logout() {
token.value = null
user.value = null
localStorage.removeItem('token')
}
// Initialize
if (token.value) {
fetchUser()
}
return {
token,
user,
isAuthenticated,
login,
register,
fetchUser,
logout,
}
})

View File

@@ -0,0 +1,71 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const usePlayerStore = defineStore('player', () => {
const isPlaying = ref(false)
const currentTrack = ref(null)
const currentTrackUrl = ref(null)
const position = ref(0)
const duration = ref(0)
const volume = ref(100)
function setPlayerState(state) {
isPlaying.value = state.is_playing
position.value = state.position
if (state.current_track_id) {
currentTrack.value = { id: state.current_track_id }
}
if (state.track_url) {
currentTrackUrl.value = state.track_url
}
}
function setTrack(track, url) {
currentTrack.value = track
currentTrackUrl.value = url
position.value = 0
}
function setPosition(pos) {
position.value = pos
}
function setDuration(dur) {
duration.value = dur
}
function setVolume(vol) {
volume.value = vol
localStorage.setItem('volume', vol)
}
function play() {
isPlaying.value = true
}
function pause() {
isPlaying.value = false
}
// Load saved volume
const savedVolume = localStorage.getItem('volume')
if (savedVolume) {
volume.value = parseInt(savedVolume)
}
return {
isPlaying,
currentTrack,
currentTrackUrl,
position,
duration,
volume,
setPlayerState,
setTrack,
setPosition,
setDuration,
setVolume,
play,
pause,
}
})

View File

@@ -0,0 +1,85 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import api from '../composables/useApi'
export const useRoomStore = defineStore('room', () => {
const rooms = ref([])
const currentRoom = ref(null)
const participants = ref([])
const queue = ref([])
async function fetchRooms() {
const response = await api.get('/api/rooms')
rooms.value = response.data
}
async function fetchRoom(roomId) {
const response = await api.get(`/api/rooms/${roomId}`)
currentRoom.value = response.data
participants.value = response.data.participants
}
async function createRoom(name) {
const response = await api.post('/api/rooms', { name })
return response.data
}
async function deleteRoom(roomId) {
await api.delete(`/api/rooms/${roomId}`)
rooms.value = rooms.value.filter(r => r.id !== roomId)
}
async function joinRoom(roomId) {
await api.post(`/api/rooms/${roomId}/join`)
}
async function leaveRoom(roomId) {
await api.post(`/api/rooms/${roomId}/leave`)
}
async function fetchQueue(roomId) {
const response = await api.get(`/api/rooms/${roomId}/queue`)
queue.value = response.data
}
async function addToQueue(roomId, trackId) {
await api.post(`/api/rooms/${roomId}/queue`, { track_id: trackId })
}
async function removeFromQueue(roomId, trackId) {
await api.delete(`/api/rooms/${roomId}/queue/${trackId}`)
}
function updateParticipants(newParticipants) {
participants.value = newParticipants
}
function addParticipant(user) {
if (!participants.value.find(p => p.id === user.id)) {
participants.value.push(user)
}
}
function removeParticipant(userId) {
participants.value = participants.value.filter(p => p.id !== userId)
}
return {
rooms,
currentRoom,
participants,
queue,
fetchRooms,
fetchRoom,
createRoom,
deleteRoom,
joinRoom,
leaveRoom,
fetchQueue,
addToQueue,
removeFromQueue,
updateParticipants,
addParticipant,
removeParticipant,
}
})

View File

@@ -0,0 +1,50 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import api from '../composables/useApi'
export const useTracksStore = defineStore('tracks', () => {
const tracks = ref([])
const loading = ref(false)
async function fetchTracks() {
loading.value = true
try {
const response = await api.get('/api/tracks')
tracks.value = response.data
} finally {
loading.value = false
}
}
async function uploadTrack(file, title, artist) {
const formData = new FormData()
formData.append('file', file)
formData.append('title', title)
formData.append('artist', artist)
const response = await api.post('/api/tracks/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
})
tracks.value.unshift(response.data)
return response.data
}
async function deleteTrack(trackId) {
await api.delete(`/api/tracks/${trackId}`)
tracks.value = tracks.value.filter(t => t.id !== trackId)
}
async function getTrackUrl(trackId) {
const response = await api.get(`/api/tracks/${trackId}`)
return response.data.url
}
return {
tracks,
loading,
fetchTracks,
uploadTrack,
deleteTrack,
getTrackUrl,
}
})