music_player_server/
library.rs

1use futures::future::FutureExt;
2use music_player_entity::{album, artist, artist_tracks, track};
3use music_player_scanner::scan_directory;
4use music_player_storage::repo::artist::ArtistRepository;
5use music_player_storage::repo::track::TrackRepository;
6use music_player_storage::Database;
7use music_player_storage::{repo::album::AlbumRepository, searcher::Searcher};
8use sea_orm::ActiveModelTrait;
9use std::sync::Arc;
10use tokio::sync::Mutex;
11
12use crate::api::music::v1alpha1::{
13    library_service_server::LibraryService, GetAlbumDetailsRequest, GetAlbumDetailsResponse,
14    GetAlbumsRequest, GetAlbumsResponse, GetArtistDetailsRequest, GetArtistDetailsResponse,
15    GetArtistsRequest, GetArtistsResponse, GetTrackDetailsRequest, GetTrackDetailsResponse,
16    GetTracksRequest, GetTracksResponse, ScanRequest, ScanResponse, SearchRequest, SearchResponse,
17};
18
19pub struct Library {
20    db: Database,
21}
22
23impl Library {
24    pub fn new(db: Database) -> Self {
25        Self { db }
26    }
27}
28
29#[tonic::async_trait]
30impl LibraryService for Library {
31    async fn scan(
32        &self,
33        _request: tonic::Request<ScanRequest>,
34    ) -> Result<tonic::Response<ScanResponse>, tonic::Status> {
35        scan_directory(
36            move |song, db| {
37                async move {
38                    let item: artist::ActiveModel = song.try_into().unwrap();
39                    match item.insert(db.get_connection()).await {
40                        Ok(_) => (),
41                        Err(_) => (),
42                    }
43
44                    let item: album::ActiveModel = song.try_into().unwrap();
45                    match item.insert(db.get_connection()).await {
46                        Ok(_) => (),
47                        Err(_) => (),
48                    }
49
50                    let item: track::ActiveModel = song.try_into().unwrap();
51
52                    match item.insert(db.get_connection()).await {
53                        Ok(_) => (),
54                        Err(_) => (),
55                    }
56
57                    let item: artist_tracks::ActiveModel = song.try_into().unwrap();
58                    match item.insert(db.get_connection()).await {
59                        Ok(_) => (),
60                        Err(_) => (),
61                    }
62                }
63                .boxed()
64            },
65            &Database::new().await,
66            &Searcher::new(),
67        )
68        .await
69        .map_err(|e| tonic::Status::internal(e.to_string()))?;
70
71        let response = ScanResponse {};
72        Ok(tonic::Response::new(response))
73    }
74
75    async fn search(
76        &self,
77        _request: tonic::Request<SearchRequest>,
78    ) -> Result<tonic::Response<SearchResponse>, tonic::Status> {
79        let response = SearchResponse {};
80        Ok(tonic::Response::new(response))
81    }
82
83    async fn get_artists(
84        &self,
85        request: tonic::Request<GetArtistsRequest>,
86    ) -> Result<tonic::Response<GetArtistsResponse>, tonic::Status> {
87        let request = request.into_inner();
88        let filter = match request.filter.as_str() {
89            "" => None,
90            _ => Some(request.filter),
91        };
92        let offset = request.offset;
93        let limit = request.limit;
94        let results = ArtistRepository::new(&self.db.get_connection())
95            .find_all(filter, Some(offset as u64), Some(limit as u64))
96            .await
97            .map_err(|e| tonic::Status::internal(e.to_string()))?;
98
99        let response = GetArtistsResponse {
100            artists: results.into_iter().map(Into::into).collect(),
101        };
102        Ok(tonic::Response::new(response))
103    }
104
105    async fn get_albums(
106        &self,
107        request: tonic::Request<GetAlbumsRequest>,
108    ) -> Result<tonic::Response<GetAlbumsResponse>, tonic::Status> {
109        let request = request.into_inner();
110        let filter = match request.filter.as_str() {
111            "" => None,
112            _ => Some(request.filter),
113        };
114        let offset = request.offset;
115        let limit = request.limit;
116        let results = AlbumRepository::new(&self.db.get_connection())
117            .find_all(filter, Some(offset as u64), Some(limit as u64))
118            .await
119            .map_err(|e| tonic::Status::internal(e.to_string()))?;
120
121        let response = GetAlbumsResponse {
122            albums: results.into_iter().map(Into::into).collect(),
123        };
124        Ok(tonic::Response::new(response))
125    }
126
127    async fn get_tracks(
128        &self,
129        request: tonic::Request<GetTracksRequest>,
130    ) -> Result<tonic::Response<GetTracksResponse>, tonic::Status> {
131        let request = request.into_inner();
132        let filter = match request.filter.as_str() {
133            "" => None,
134            _ => Some(request.filter),
135        };
136        let offset = request.offset;
137        let limit = match request.limit {
138            0 => 100,
139            _ => request.limit,
140        };
141        let tracks = TrackRepository::new(&self.db.get_connection())
142            .find_all(filter, Some(offset as u64), limit as u64)
143            .await
144            .map_err(|e| tonic::Status::internal(e.to_string()))?;
145
146        let response = GetTracksResponse {
147            tracks: tracks.into_iter().map(Into::into).collect(),
148        };
149        Ok(tonic::Response::new(response))
150    }
151
152    async fn get_track_details(
153        &self,
154        request: tonic::Request<GetTrackDetailsRequest>,
155    ) -> Result<tonic::Response<GetTrackDetailsResponse>, tonic::Status> {
156        let id = request.into_inner().id;
157
158        let track = TrackRepository::new(&self.db.get_connection())
159            .find(&id)
160            .await
161            .map_err(|e| tonic::Status::internal(e.to_string()))?;
162
163        Ok(tonic::Response::new(GetTrackDetailsResponse {
164            track: Some(track.into()),
165        }))
166    }
167
168    async fn get_album_details(
169        &self,
170        request: tonic::Request<GetAlbumDetailsRequest>,
171    ) -> Result<tonic::Response<GetAlbumDetailsResponse>, tonic::Status> {
172        let id = request.into_inner().id;
173        let album = AlbumRepository::new(&self.db.get_connection())
174            .find(&id)
175            .await
176            .map_err(|e| tonic::Status::internal(e.to_string()))?;
177
178        Ok(tonic::Response::new(GetAlbumDetailsResponse {
179            album: Some(album.into()),
180        }))
181    }
182
183    async fn get_artist_details(
184        &self,
185        request: tonic::Request<GetArtistDetailsRequest>,
186    ) -> Result<tonic::Response<GetArtistDetailsResponse>, tonic::Status> {
187        let id = request.into_inner().id;
188
189        let artist = ArtistRepository::new(&self.db.get_connection())
190            .find(&id)
191            .await
192            .map_err(|e| tonic::Status::internal(e.to_string()))?;
193
194        let response = GetArtistDetailsResponse {
195            artist: Some(artist.into()),
196        };
197        Ok(tonic::Response::new(response))
198    }
199}