1#![allow(clippy::future_not_send)]
4
5use std::{
6 net::{IpAddr, Ipv4Addr, SocketAddr},
7 ops::Range,
8 path::PathBuf,
9 time::Duration,
10};
11
12use mecomp_storage::db::schemas::{
13 album::{Album, AlbumBrief},
14 artist::{Artist, ArtistBrief},
15 collection::{Collection, CollectionBrief},
16 dynamic::{query::Query, DynamicPlaylist, DynamicPlaylistChangeSet},
17 playlist::{Playlist, PlaylistBrief},
18 song::{Song, SongBrief},
19 Thing,
20};
21use one_or_many::OneOrMany;
22use serde::{Deserialize, Serialize};
23use tarpc::{client, tokio_serde::formats::Json};
24
25use crate::{
26 errors::SerializableLibraryError,
27 state::{
28 library::{LibraryBrief, LibraryFull, LibraryHealth},
29 RepeatMode, SeekType, StateAudio,
30 },
31};
32
33pub type SongId = Thing;
34pub type ArtistId = Thing;
35pub type AlbumId = Thing;
36pub type CollectionId = Thing;
37pub type PlaylistId = Thing;
38pub type DynamicPlaylistId = Thing;
39
40#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
41pub struct SearchResult {
42 pub songs: Box<[Song]>,
43 pub albums: Box<[Album]>,
44 pub artists: Box<[Artist]>,
45}
46
47impl SearchResult {
48 #[must_use]
49 pub const fn len(&self) -> usize {
50 self.songs.len() + self.albums.len() + self.artists.len()
51 }
52
53 #[must_use]
54 pub const fn is_empty(&self) -> bool {
55 self.songs.is_empty() && self.albums.is_empty() && self.artists.is_empty()
56 }
57}
58
59#[tarpc::service]
63pub trait MusicPlayer {
64 async fn register_listener(listener_addr: SocketAddr) -> ();
66
67 async fn ping() -> String;
69
70 async fn library_rescan() -> Result<(), SerializableLibraryError>;
73 async fn library_rescan_in_progress() -> bool;
75 async fn library_analyze() -> Result<(), SerializableLibraryError>;
77 async fn library_analyze_in_progress() -> bool;
79 async fn library_recluster() -> Result<(), SerializableLibraryError>;
81 async fn library_recluster_in_progress() -> bool;
83 async fn library_brief() -> Result<LibraryBrief, SerializableLibraryError>;
85 async fn library_full() -> Result<LibraryFull, SerializableLibraryError>;
87 async fn library_artists_brief() -> Result<Box<[ArtistBrief]>, SerializableLibraryError>;
89 async fn library_artists_full() -> Result<Box<[Artist]>, SerializableLibraryError>;
91 async fn library_albums_brief() -> Result<Box<[AlbumBrief]>, SerializableLibraryError>;
93 async fn library_albums_full() -> Result<Box<[Album]>, SerializableLibraryError>;
95 async fn library_songs_brief() -> Result<Box<[SongBrief]>, SerializableLibraryError>;
97 async fn library_songs_full() -> Result<Box<[Song]>, SerializableLibraryError>;
99 async fn library_health() -> Result<LibraryHealth, SerializableLibraryError>;
101
102 async fn library_song_get(id: SongId) -> Option<Song>;
105 async fn library_song_get_by_path(path: PathBuf) -> Option<Song>;
107 async fn library_song_get_artist(id: SongId) -> OneOrMany<Artist>;
109 async fn library_song_get_album(id: SongId) -> Option<Album>;
111 async fn library_song_get_playlists(id: SongId) -> Box<[Playlist]>;
113 async fn library_song_get_collections(id: SongId) -> Box<[Collection]>;
115 async fn library_album_get(id: AlbumId) -> Option<Album>;
117 async fn library_album_get_artist(id: AlbumId) -> OneOrMany<Artist>;
119 async fn library_album_get_songs(id: AlbumId) -> Option<Box<[Song]>>;
121 async fn library_artist_get(id: ArtistId) -> Option<Artist>;
123 async fn library_artist_get_songs(id: ArtistId) -> Option<Box<[Song]>>;
125 async fn library_artist_get_albums(id: ArtistId) -> Option<Box<[Album]>>;
127
128 async fn daemon_shutdown() -> ();
131
132 async fn state_audio() -> Option<StateAudio>;
135
136 async fn current_artist() -> OneOrMany<Artist>;
139 async fn current_album() -> Option<Album>;
141 async fn current_song() -> Option<Song>;
143
144 async fn rand_artist() -> Option<Artist>;
147 async fn rand_album() -> Option<Album>;
149 async fn rand_song() -> Option<Song>;
151
152 async fn search(query: String, limit: u32) -> SearchResult;
155 async fn search_artist(query: String, limit: u32) -> Box<[Artist]>;
157 async fn search_album(query: String, limit: u32) -> Box<[Album]>;
159 async fn search_song(query: String, limit: u32) -> Box<[Song]>;
161
162 async fn playback_toggle() -> ();
165 async fn playback_play() -> ();
167 async fn playback_pause() -> ();
169 async fn playback_stop() -> ();
171 async fn playback_restart() -> ();
173 async fn playback_skip_forward(amount: usize) -> ();
175 async fn playback_skip_backward(amount: usize) -> ();
177 async fn playback_clear_player() -> ();
179 async fn playback_clear() -> ();
181 async fn playback_seek(seek: SeekType, duration: Duration) -> ();
183 async fn playback_repeat(mode: RepeatMode) -> ();
185 async fn playback_shuffle() -> ();
187 async fn playback_volume(volume: f32) -> ();
190 async fn playback_volume_up(amount: f32) -> ();
192 async fn playback_volume_down(amount: f32) -> ();
194 async fn playback_volume_toggle_mute() -> ();
196 async fn playback_mute() -> ();
198 async fn playback_unmute() -> ();
200
201 async fn queue_add(thing: Thing) -> Result<(), SerializableLibraryError>;
205 async fn queue_add_list(list: Vec<Thing>) -> Result<(), SerializableLibraryError>;
208 async fn queue_set_index(index: usize) -> ();
211 async fn queue_remove_range(range: Range<usize>) -> ();
214
215 async fn playlist_list() -> Box<[PlaylistBrief]>;
218 async fn playlist_get_or_create(name: String) -> Result<PlaylistId, SerializableLibraryError>;
220 async fn playlist_remove(id: PlaylistId) -> Result<(), SerializableLibraryError>;
222 async fn playlist_clone(id: PlaylistId) -> Result<PlaylistId, SerializableLibraryError>;
226 async fn playlist_get_id(name: String) -> Option<PlaylistId>;
229 async fn playlist_remove_songs(
232 playlist: PlaylistId,
233 songs: Vec<SongId>,
234 ) -> Result<(), SerializableLibraryError>;
235 async fn playlist_add(
238 playlist: PlaylistId,
239 thing: Thing,
240 ) -> Result<(), SerializableLibraryError>;
241 async fn playlist_add_list(
244 playlist: PlaylistId,
245 list: Vec<Thing>,
246 ) -> Result<(), SerializableLibraryError>;
247 async fn playlist_get(id: PlaylistId) -> Option<Playlist>;
249 async fn playlist_get_songs(id: PlaylistId) -> Option<Box<[Song]>>;
251 async fn playlist_rename(
253 id: PlaylistId,
254 name: String,
255 ) -> Result<Playlist, SerializableLibraryError>;
256
257 async fn collection_list() -> Box<[CollectionBrief]>;
261 async fn collection_get(id: CollectionId) -> Option<Collection>;
263 async fn collection_freeze(
265 id: CollectionId,
266 name: String,
267 ) -> Result<PlaylistId, SerializableLibraryError>;
268 async fn collection_get_songs(id: CollectionId) -> Option<Box<[Song]>>;
270
271 async fn radio_get_similar(
274 things: Vec<Thing>,
275 n: u32,
276 ) -> Result<Box<[Song]>, SerializableLibraryError>;
277 async fn radio_get_similar_ids(
279 things: Vec<Thing>,
280 n: u32,
281 ) -> Result<Box<[SongId]>, SerializableLibraryError>;
282
283 async fn dynamic_playlist_create(
286 name: String,
287 query: Query,
288 ) -> Result<DynamicPlaylistId, SerializableLibraryError>;
289 async fn dynamic_playlist_list() -> Box<[DynamicPlaylist]>;
291 async fn dynamic_playlist_update(
293 id: DynamicPlaylistId,
294 changes: DynamicPlaylistChangeSet,
295 ) -> Result<DynamicPlaylist, SerializableLibraryError>;
296 async fn dynamic_playlist_remove(id: DynamicPlaylistId)
298 -> Result<(), SerializableLibraryError>;
299 async fn dynamic_playlist_get(id: DynamicPlaylistId) -> Option<DynamicPlaylist>;
301 async fn dynamic_playlist_get_songs(id: DynamicPlaylistId) -> Option<Box<[Song]>>;
303}
304
305pub async fn init_client(rpc_port: u16) -> Result<MusicPlayerClient, std::io::Error> {
311 let server_addr = (IpAddr::V4(Ipv4Addr::LOCALHOST), rpc_port);
312
313 let mut transport = tarpc::serde_transport::tcp::connect(server_addr, Json::default);
314 transport.config_mut().max_frame_length(usize::MAX);
315
316 Ok(MusicPlayerClient::new(client::Config::default(), transport.await?).spawn())
319}