feat: added api conversation + api review
This commit is contained in:
32
.cursor/rules/api-conventions.mdc
Normal file
32
.cursor/rules/api-conventions.mdc
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
description: REST API запросы — создавать функции в furumiApi.ts (только furumi-node-player/client)
|
||||
globs: furumi-node-player/client/**/*.{ts,tsx}
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# REST API в furumi-node-player
|
||||
|
||||
**Область действия:** правило применяется только к проекту `furumi-node-player/client/`. В остальных частях репозитория можно использовать другой подход.
|
||||
|
||||
Чтобы выполнить REST API запрос, нужно создать функцию, которая принимает необходимые параметры и вызывает `furumiApi`. Все такие функции должны находиться в файле `furumi-node-player/client/src/furumiApi.ts`.
|
||||
|
||||
## Правила
|
||||
|
||||
1. **Не вызывать `furumiApi` напрямую** из компонентов или других модулей.
|
||||
2. **Добавлять новую функцию** в `furumiApi.ts` для каждого эндпоинта.
|
||||
3. Функция принимает нужные параметры и возвращает `Promise` с данными (или `null` при ошибке).
|
||||
|
||||
## Пример
|
||||
|
||||
```typescript
|
||||
// furumiApi.ts — добавлять сюда
|
||||
export async function getSomething(id: string) {
|
||||
const res = await furumiApi.get(`/something/${id}`).catch(() => null)
|
||||
return res?.data ?? null
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
// FurumiPlayer.tsx — использовать функцию, не furumiApi напрямую
|
||||
const data = await getSomething(id)
|
||||
```
|
||||
@@ -1,6 +1,15 @@
|
||||
import { useEffect, useRef, useState, type MouseEvent as ReactMouseEvent } from 'react'
|
||||
import './furumi-player.css'
|
||||
import { API_ROOT, furumiApi } from './furumiApi'
|
||||
import {
|
||||
API_ROOT,
|
||||
getArtists,
|
||||
getArtistAlbums,
|
||||
getAlbumTracks,
|
||||
getArtistTracks,
|
||||
searchTracks,
|
||||
getTrackInfo,
|
||||
preloadStream,
|
||||
} from './furumiApi'
|
||||
import { SearchDropdown } from './components/SearchDropdown'
|
||||
import { Breadcrumbs } from './components/Breadcrumbs'
|
||||
import { LibraryList } from './components/LibraryList'
|
||||
@@ -107,7 +116,7 @@ export function FurumiPlayer() {
|
||||
setBreadcrumb([{ label: 'Artists', action: showArtists }])
|
||||
setLibraryLoading(true)
|
||||
setLibraryError(null)
|
||||
const artists = (await furumiApi.get('/artists').catch(() => null))?.data ?? null
|
||||
const artists = await getArtists()
|
||||
if (!artists) {
|
||||
setLibraryLoading(false)
|
||||
setLibraryError('Error')
|
||||
@@ -133,7 +142,7 @@ export function FurumiPlayer() {
|
||||
])
|
||||
setLibraryLoading(true)
|
||||
setLibraryError(null)
|
||||
const albums = (await furumiApi.get('/artists/' + artistSlug + '/albums').catch(() => null))?.data ?? null
|
||||
const albums = await getArtistAlbums(artistSlug)
|
||||
if (!albums) {
|
||||
setLibraryLoading(false)
|
||||
setLibraryError('Error')
|
||||
@@ -182,7 +191,7 @@ export function FurumiPlayer() {
|
||||
])
|
||||
setLibraryLoading(true)
|
||||
setLibraryError(null)
|
||||
const tracks = (await furumiApi.get('/albums/' + albumSlug).catch(() => null))?.data ?? null
|
||||
const tracks = await getAlbumTracks(albumSlug)
|
||||
if (!tracks) {
|
||||
setLibraryLoading(false)
|
||||
setLibraryError('Error')
|
||||
@@ -252,7 +261,7 @@ export function FurumiPlayer() {
|
||||
}
|
||||
|
||||
async function addAlbumToQueue(albumSlug: string, playFirst?: boolean) {
|
||||
const tracks = (await furumiApi.get('/albums/' + albumSlug).catch(() => null))?.data ?? null
|
||||
const tracks = await getAlbumTracks(albumSlug)
|
||||
if (!tracks || !(tracks as any[]).length) return
|
||||
const list = tracks as any[]
|
||||
let firstIdx = queue.length
|
||||
@@ -272,7 +281,7 @@ export function FurumiPlayer() {
|
||||
}
|
||||
|
||||
async function playAllArtistTracks(artistSlug: string) {
|
||||
const tracks = (await furumiApi.get('/artists/' + artistSlug + '/tracks').catch(() => null))?.data ?? null
|
||||
const tracks = await getArtistTracks(artistSlug)
|
||||
if (!tracks || !(tracks as any[]).length) return
|
||||
const list = tracks as any[]
|
||||
clearQueue()
|
||||
@@ -487,7 +496,7 @@ export function FurumiPlayer() {
|
||||
return
|
||||
}
|
||||
searchTimer = window.setTimeout(async () => {
|
||||
const results = (await furumiApi.get('/search?q=' + encodeURIComponent(q)).catch(() => null))?.data ?? null
|
||||
const results = await searchTracks(q)
|
||||
if (!results || !(results as any[]).length) {
|
||||
closeSearch()
|
||||
return
|
||||
@@ -511,7 +520,7 @@ export function FurumiPlayer() {
|
||||
{ slug, title: '', artist: '', album_slug: null, duration: null },
|
||||
true,
|
||||
)
|
||||
void furumiApi.get('/stream/' + slug).catch(() => null)
|
||||
void preloadStream(slug)
|
||||
}
|
||||
}
|
||||
searchSelectRef.current = onSearchSelect
|
||||
@@ -617,7 +626,7 @@ export function FurumiPlayer() {
|
||||
const url = new URL(window.location.href)
|
||||
const urlSlug = url.searchParams.get('t')
|
||||
if (urlSlug) {
|
||||
const info = (await furumiApi.get('/tracks/' + urlSlug).catch(() => null))?.data ?? null
|
||||
const info = await getTrackInfo(urlSlug)
|
||||
if (info) {
|
||||
addTrackToQueue(
|
||||
{
|
||||
|
||||
@@ -10,3 +10,37 @@ export const furumiApi = axios.create({
|
||||
headers: apiKey ? { 'x-api-key': apiKey } : {},
|
||||
})
|
||||
|
||||
export async function getArtists() {
|
||||
const res = await furumiApi.get('/artists').catch(() => null)
|
||||
return res?.data ?? null
|
||||
}
|
||||
|
||||
export async function getArtistAlbums(artistSlug: string) {
|
||||
const res = await furumiApi.get(`/artists/${artistSlug}/albums`).catch(() => null)
|
||||
return res?.data ?? null
|
||||
}
|
||||
|
||||
export async function getAlbumTracks(albumSlug: string) {
|
||||
const res = await furumiApi.get(`/albums/${albumSlug}`).catch(() => null)
|
||||
return res?.data ?? null
|
||||
}
|
||||
|
||||
export async function getArtistTracks(artistSlug: string) {
|
||||
const res = await furumiApi.get(`/artists/${artistSlug}/tracks`).catch(() => null)
|
||||
return res?.data ?? null
|
||||
}
|
||||
|
||||
export async function searchTracks(query: string) {
|
||||
const res = await furumiApi.get(`/search?q=${encodeURIComponent(query)}`).catch(() => null)
|
||||
return res?.data ?? null
|
||||
}
|
||||
|
||||
export async function getTrackInfo(trackSlug: string) {
|
||||
const res = await furumiApi.get(`/tracks/${trackSlug}`).catch(() => null)
|
||||
return res?.data ?? null
|
||||
}
|
||||
|
||||
export async function preloadStream(trackSlug: string) {
|
||||
await furumiApi.get(`/stream/${trackSlug}`).catch(() => null)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user