7.0 KiB
Личные плейлисты
Плейлисты хранятся в PostgreSQL. Владелец управляет ими в вебе, desktop и React Native-клиенте; по желанию может поделиться ссылкой для прослушивания. В вебе раздел находится в коллекции; на узком экране — в меню «Ещё». В мобильном клиенте — кнопка «Плейлисты» в коллекции.
Можно создать плейлист, изменить название и описание, добавить трек из поиска, альбома или коллекции, убрать трек и переместить его выше/ниже. В вебе можно добавить целый альбом. Один трек встречается в плейлисте один раз: повторное добавление не создаёт дубль. Воспроизведение доступно в сохранённом или случайном порядке; недоступные треки остаются видимыми, но пропускаются при запуске всего плейлиста. Удаление плейлиста требует подтверждения и не удаляет музыку из каталога.
API
GET /api/v1/me/playlists— сводки личных плейлистов, последние изменённые первыми.POST /api/v1/me/playlists— создание:name,description,track_ids.GET /api/v1/me/playlists/{id}— метаданные и упорядоченные треки с персональными реакциями и подписанными ссылками.PUT /api/v1/me/playlists/{id}— атомарная замена метаданных и порядка треков; дополнительно требуетсяrevisionиз прочитанного плейлиста.DELETE /api/v1/me/playlists/{id}— удаление.POST /api/v1/me/playlists/{id}/share— создать или вернуть действующийshare_id(только владелец).DELETE /api/v1/me/playlists/{id}/share— отключить доступ по ссылке (только владелец).GET /api/v1/shared/playlists/{shareId}— прочитать плейлист по действующей ссылке; требуется вход на этот сервер.
Все операции требуют авторизации. Чужой и отсутствующий плейлист возвращают одинаковый 404. Изменения блокируют строку плейлиста в транзакции; устаревшая версия возвращает 409 playlist.conflict. Редактор сохраняет исходную версию до закрытия, даже если фоновый запрос получил новую. Ошибка трека откатывает изменение целиком. Ввод ограничен 120 символами названия, 2000 символами описания и 2000 уникальными треками.
Миграция 00013_playlists.sql создаёт таблицы playlists, playlist_tracks и индексы. Удаление пользователя очищает его плейлисты; удаление трека из каталога очищает его членство. Таблицы не затрагивают музыкальные файлы.
Изначально плейлисты личные. Кнопка «Поделиться плейлистом» включает доступ по ссылке
/shared/playlist/{shareId}. В вебе/desktop ссылка копируется, в мобильном браузере и Android открывается
системное меню «Поделиться». Desktop использует адрес музыкального сервера, а не локального WebView.
Как и ссылки на треки, ссылка требует входа на тот же сервер. После входа открывается запрошенный плейлист,
без автоматического запуска музыки. Получатель может слушать в обычном или случайном порядке и переслать
ту же ссылку, но не может редактировать или удалять исходный плейлист.
Ссылка содержит отдельный случайный UUID и не раскрывает токены авторизации или подписанные URL аудио.
Список /me/playlists и обычное чтение по UUID плейлиста остаются доступны только владельцу. Реакции
на треки и ссылки стрима в общем плейлисте принадлежат текущему слушателю. Данные общих страниц в веб-кэше
разделяются по пользователям.
«Отключить доступ по ссылке» отзывает прежний share_id; следующая публикация создаёт новый.
Повторное нажатие «Поделиться» без отзыва сохраняет ссылку. Ссылка показывает актуальный порядок и метаданные;
изменение доступа не меняет revision и не вызывает конфликт редактора. При удалении плейлиста или блокировке
владельца ссылка возвращает 404. Миграция 00016_playlist_sharing.sql добавляет share_id и уникальный индекс.
Совместное редактирование и загрузка пользовательских обложек не входят в эту реализацию. Карточки имеют градиентную обложку, страница использует обложку первого трека. Контекст воспроизведения — collection с UUID и названием плейлиста.
Проверки
pnpm --filter @pipu/web test src/App.test.tsx -t playlistspnpm --filter @pipu/web test:e2e e2e/playlists.spec.tspnpm --filter @pipu/web buildpnpm --filter @pipu/mobile typecheck- В
services/api:go test ./internal/playback ./internal/server - С отдельной тестовой PostgreSQL/pgvector:
TEST_DATABASE_URL=… go test -tags integration ./internal/playback -run TestPlaylistPersistenceAndIsolation -v. Проверяет сохранение порядка, изоляцию владельцев, откат при несуществующем треке, конфликт конкурентных записей и каскадное удаление членства.