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 RecordId,
14 album::{Album, AlbumBrief},
15 artist::{Artist, ArtistBrief},
16 collection::{Collection, CollectionBrief},
17 dynamic::{DynamicPlaylist, DynamicPlaylistChangeSet, query::Query},
18 playlist::{Playlist, PlaylistBrief},
19 song::{Song, SongBrief},
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 RepeatMode, SeekType, StateAudio,
29 library::{LibraryBrief, LibraryFull, LibraryHealth},
30 },
31};
32
33pub type SongId = RecordId;
34pub type ArtistId = RecordId;
35pub type AlbumId = RecordId;
36pub type CollectionId = RecordId;
37pub type PlaylistId = RecordId;
38pub type DynamicPlaylistId = RecordId;
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 #[inline]
50 pub const fn len(&self) -> usize {
51 self.songs.len() + self.albums.len() + self.artists.len()
52 }
53
54 #[must_use]
55 #[inline]
56 pub const fn is_empty(&self) -> bool {
57 self.songs.is_empty() && self.albums.is_empty() && self.artists.is_empty()
58 }
59}
60
61#[tarpc::service]
65pub trait MusicPlayer {
66 async fn register_listener(listener_addr: SocketAddr) -> ();
68
69 async fn ping() -> String;
71
72 async fn library_rescan() -> Result<(), SerializableLibraryError>;
75 async fn library_rescan_in_progress() -> bool;
77 async fn library_analyze(overwrite: bool) -> Result<(), SerializableLibraryError>;
79 async fn library_analyze_in_progress() -> bool;
81 async fn library_recluster() -> Result<(), SerializableLibraryError>;
83 async fn library_recluster_in_progress() -> bool;
85 async fn library_brief() -> Result<LibraryBrief, SerializableLibraryError>;
87 async fn library_full() -> Result<LibraryFull, SerializableLibraryError>;
89 async fn library_artists_brief() -> Result<Box<[ArtistBrief]>, SerializableLibraryError>;
91 async fn library_artists_full() -> Result<Box<[Artist]>, SerializableLibraryError>;
93 async fn library_albums_brief() -> Result<Box<[AlbumBrief]>, SerializableLibraryError>;
95 async fn library_albums_full() -> Result<Box<[Album]>, SerializableLibraryError>;
97 async fn library_songs_brief() -> Result<Box<[SongBrief]>, SerializableLibraryError>;
99 async fn library_songs_full() -> Result<Box<[Song]>, SerializableLibraryError>;
101 async fn library_health() -> Result<LibraryHealth, SerializableLibraryError>;
103
104 async fn library_song_get(id: SongId) -> Option<Song>;
107 async fn library_song_get_by_path(path: PathBuf) -> Option<Song>;
109 async fn library_song_get_artist(id: SongId) -> OneOrMany<Artist>;
111 async fn library_song_get_album(id: SongId) -> Option<Album>;
113 async fn library_song_get_playlists(id: SongId) -> Box<[Playlist]>;
115 async fn library_song_get_collections(id: SongId) -> Box<[Collection]>;
117 async fn library_album_get(id: AlbumId) -> Option<Album>;
119 async fn library_album_get_artist(id: AlbumId) -> OneOrMany<Artist>;
121 async fn library_album_get_songs(id: AlbumId) -> Option<Box<[Song]>>;
123 async fn library_artist_get(id: ArtistId) -> Option<Artist>;
125 async fn library_artist_get_songs(id: ArtistId) -> Option<Box<[Song]>>;
127 async fn library_artist_get_albums(id: ArtistId) -> Option<Box<[Album]>>;
129
130 async fn daemon_shutdown() -> ();
133
134 async fn state_audio() -> Option<StateAudio>;
137
138 async fn current_artist() -> OneOrMany<Artist>;
141 async fn current_album() -> Option<Album>;
143 async fn current_song() -> Option<Song>;
145
146 async fn rand_artist() -> Option<Artist>;
149 async fn rand_album() -> Option<Album>;
151 async fn rand_song() -> Option<Song>;
153
154 async fn search(query: String, limit: u32) -> SearchResult;
157 async fn search_artist(query: String, limit: u32) -> Box<[Artist]>;
159 async fn search_album(query: String, limit: u32) -> Box<[Album]>;
161 async fn search_song(query: String, limit: u32) -> Box<[Song]>;
163
164 async fn playback_toggle() -> ();
167 async fn playback_play() -> ();
169 async fn playback_pause() -> ();
171 async fn playback_stop() -> ();
173 async fn playback_restart() -> ();
175 async fn playback_skip_forward(amount: usize) -> ();
177 async fn playback_skip_backward(amount: usize) -> ();
179 async fn playback_clear_player() -> ();
181 async fn playback_clear() -> ();
183 async fn playback_seek(seek: SeekType, duration: Duration) -> ();
185 async fn playback_repeat(mode: RepeatMode) -> ();
187 async fn playback_shuffle() -> ();
189 async fn playback_volume(volume: f32) -> ();
192 async fn playback_volume_up(amount: f32) -> ();
194 async fn playback_volume_down(amount: f32) -> ();
196 async fn playback_volume_toggle_mute() -> ();
198 async fn playback_mute() -> ();
200 async fn playback_unmute() -> ();
202
203 async fn queue_add(thing: RecordId) -> Result<(), SerializableLibraryError>;
207 async fn queue_add_list(list: Vec<RecordId>) -> Result<(), SerializableLibraryError>;
210 async fn queue_set_index(index: usize) -> ();
213 async fn queue_remove_range(range: Range<usize>) -> ();
216
217 async fn playlist_list() -> Box<[PlaylistBrief]>;
220 async fn playlist_get_or_create(name: String) -> Result<PlaylistId, SerializableLibraryError>;
222 async fn playlist_remove(id: PlaylistId) -> Result<(), SerializableLibraryError>;
224 async fn playlist_clone(id: PlaylistId) -> Result<PlaylistId, SerializableLibraryError>;
228 async fn playlist_get_id(name: String) -> Option<PlaylistId>;
231 async fn playlist_remove_songs(
234 playlist: PlaylistId,
235 songs: Vec<SongId>,
236 ) -> Result<(), SerializableLibraryError>;
237 async fn playlist_add(
240 playlist: PlaylistId,
241 thing: RecordId,
242 ) -> Result<(), SerializableLibraryError>;
243 async fn playlist_add_list(
246 playlist: PlaylistId,
247 list: Vec<RecordId>,
248 ) -> Result<(), SerializableLibraryError>;
249 async fn playlist_get(id: PlaylistId) -> Option<Playlist>;
251 async fn playlist_get_songs(id: PlaylistId) -> Option<Box<[Song]>>;
253 async fn playlist_rename(
255 id: PlaylistId,
256 name: String,
257 ) -> Result<Playlist, SerializableLibraryError>;
258
259 async fn collection_list() -> Box<[CollectionBrief]>;
263 async fn collection_get(id: CollectionId) -> Option<Collection>;
265 async fn collection_freeze(
267 id: CollectionId,
268 name: String,
269 ) -> Result<PlaylistId, SerializableLibraryError>;
270 async fn collection_get_songs(id: CollectionId) -> Option<Box<[Song]>>;
272
273 async fn radio_get_similar(
276 things: Vec<RecordId>,
277 n: u32,
278 ) -> Result<Box<[Song]>, SerializableLibraryError>;
279 async fn radio_get_similar_ids(
281 things: Vec<RecordId>,
282 n: u32,
283 ) -> Result<Box<[SongId]>, SerializableLibraryError>;
284
285 async fn dynamic_playlist_create(
288 name: String,
289 query: Query,
290 ) -> Result<DynamicPlaylistId, SerializableLibraryError>;
291 async fn dynamic_playlist_list() -> Box<[DynamicPlaylist]>;
293 async fn dynamic_playlist_update(
295 id: DynamicPlaylistId,
296 changes: DynamicPlaylistChangeSet,
297 ) -> Result<DynamicPlaylist, SerializableLibraryError>;
298 async fn dynamic_playlist_remove(id: DynamicPlaylistId)
300 -> Result<(), SerializableLibraryError>;
301 async fn dynamic_playlist_get(id: DynamicPlaylistId) -> Option<DynamicPlaylist>;
303 async fn dynamic_playlist_get_songs(id: DynamicPlaylistId) -> Option<Box<[Song]>>;
305}
306
307#[allow(clippy::missing_inline_in_public_items)]
313pub async fn init_client(rpc_port: u16) -> Result<MusicPlayerClient, std::io::Error> {
314 let server_addr = (IpAddr::V4(Ipv4Addr::LOCALHOST), rpc_port);
315
316 let mut transport = tarpc::serde_transport::tcp::connect(server_addr, Json::default);
317 transport.config_mut().max_frame_length(usize::MAX);
318
319 Ok(MusicPlayerClient::new(client::Config::default(), transport.await?).spawn())
322}