Music Player & Playlist Manager

This commit is contained in:
Andrey Tkachenko
2026-04-08 15:14:03 +03:00
parent 2e8e0ef6c5
commit da066f47fa
53 changed files with 6043 additions and 23 deletions
@@ -0,0 +1,207 @@
use std::sync::Arc;
use axum::{
Json,
extract::{Path, Query, State},
http::StatusCode,
response::IntoResponse,
};
use serde::Deserialize;
use crate::application::dtos::playlist_dto::{
AddTracksDto, CreatePlaylistDto, PlaylistQueryDto, ReorderTracksDto, SharePlaylistDto,
UpdatePlaylistDto,
};
use crate::application::ports::music_ports::MusicUseCase;
use crate::application::services::music_service::MusicService;
use crate::interfaces::errors::AppError;
use crate::interfaces::middleware::auth::AuthUser;
#[derive(Debug, Deserialize)]
pub struct PaginationQuery {
pub limit: Option<i64>,
pub offset: Option<i64>,
}
pub async fn create_playlist(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Json(dto): Json<CreatePlaylistDto>,
) -> impl IntoResponse {
match music_service.create_playlist(dto, auth_user.id).await {
Ok(playlist) => (StatusCode::CREATED, Json(playlist)).into_response(),
Err(err) => AppError::from(err).into_response(),
}
}
pub async fn get_playlist(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Path(playlist_id): Path<String>,
) -> impl IntoResponse {
match music_service.get_playlist(&playlist_id, auth_user.id).await {
Ok(playlist) => (StatusCode::OK, Json(playlist)).into_response(),
Err(err) => AppError::from(err).into_response(),
}
}
pub async fn list_playlists(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Query(query): Query<PlaylistQueryDto>,
) -> impl IntoResponse {
match music_service.list_playlists(query, auth_user.id).await {
Ok(playlists) => (StatusCode::OK, Json(playlists)).into_response(),
Err(err) => AppError::from(err).into_response(),
}
}
#[derive(Debug, Deserialize)]
pub struct IncludeSharedQuery {
pub include_shared: Option<bool>,
pub include_public: Option<bool>,
}
pub async fn update_playlist(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Path(playlist_id): Path<String>,
Json(dto): Json<UpdatePlaylistDto>,
) -> impl IntoResponse {
match music_service
.update_playlist(&playlist_id, dto, auth_user.id)
.await
{
Ok(playlist) => (StatusCode::OK, Json(playlist)).into_response(),
Err(err) => AppError::from(err).into_response(),
}
}
pub async fn delete_playlist(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Path(playlist_id): Path<String>,
) -> impl IntoResponse {
match music_service
.delete_playlist(&playlist_id, auth_user.id)
.await
{
Ok(()) => StatusCode::NO_CONTENT.into_response(),
Err(err) => AppError::from(err).into_response(),
}
}
pub async fn add_tracks(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Path(playlist_id): Path<String>,
Json(dto): Json<AddTracksDto>,
) -> impl IntoResponse {
match music_service
.add_tracks(&playlist_id, dto, auth_user.id)
.await
{
Ok(tracks) => (StatusCode::CREATED, Json(tracks)).into_response(),
Err(err) => AppError::from(err).into_response(),
}
}
pub async fn remove_track(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Path((playlist_id, file_id)): Path<(String, String)>,
) -> impl IntoResponse {
match music_service
.remove_track(&playlist_id, &file_id, auth_user.id)
.await
{
Ok(()) => StatusCode::NO_CONTENT.into_response(),
Err(err) => AppError::from(err).into_response(),
}
}
pub async fn reorder_tracks(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Path(playlist_id): Path<String>,
Json(dto): Json<ReorderTracksDto>,
) -> impl IntoResponse {
match music_service
.reorder_tracks(&playlist_id, dto, auth_user.id)
.await
{
Ok(()) => StatusCode::NO_CONTENT.into_response(),
Err(err) => AppError::from(err).into_response(),
}
}
pub async fn list_playlist_tracks(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Path(playlist_id): Path<String>,
) -> impl IntoResponse {
match music_service
.list_playlist_tracks(&playlist_id, auth_user.id)
.await
{
Ok(tracks) => (StatusCode::OK, Json(tracks)).into_response(),
Err(err) => AppError::from(err).into_response(),
}
}
pub async fn share_playlist(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Path(playlist_id): Path<String>,
Json(dto): Json<SharePlaylistDto>,
) -> impl IntoResponse {
match music_service
.share_playlist(&playlist_id, dto, auth_user.id)
.await
{
Ok(()) => StatusCode::NO_CONTENT.into_response(),
Err(err) => AppError::from(err).into_response(),
}
}
pub async fn remove_share(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Path((playlist_id, user_id)): Path<(String, String)>,
) -> impl IntoResponse {
match music_service
.remove_share(&playlist_id, &user_id, auth_user.id)
.await
{
Ok(()) => StatusCode::NO_CONTENT.into_response(),
Err(err) => AppError::from(err).into_response(),
}
}
pub async fn get_playlist_shares(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Path(playlist_id): Path<String>,
) -> impl IntoResponse {
match music_service
.get_playlist_shares(&playlist_id, auth_user.id)
.await
{
Ok(shares) => (StatusCode::OK, Json(shares)).into_response(),
Err(err) => AppError::from(err).into_response(),
}
}
pub async fn get_audio_metadata(
State(music_service): State<Arc<MusicService>>,
auth_user: AuthUser,
Path(file_id): Path<String>,
) -> impl IntoResponse {
match music_service
.get_audio_metadata(&file_id, auth_user.id)
.await
{
Ok(metadata) => (StatusCode::OK, Json(metadata)).into_response(),
Err(err) => AppError::from(err).into_response(),
}
}