1use std::{cell::RefCell, rc::Rc};
18
19use extism_pdk::FnResult;
20use serde_json::Value;
21use types::entities::{Playlist, Album, Artist, SearchResult};
22use types::errors::Result as MoosyncResult;
23use types::songs::Song;
24use types::ui::extensions::{
25 AccountLoginArgs, ContextMenuReturnType, CustomRequestReturnType, ExtensionAccountDetail,
26 ExtensionProviderScope, PlaybackDetailsReturnType, PreferenceArgs,
27 SongsWithPageTokenReturnType,
28};
29
30use crate::api::Extension;
31
32macro_rules! generate_extension_methods {
33 ($(
34 $fn_name:ident (
35 $( $arg_name:ident : $arg_type:ty ),*
36 ) -> $ret_type:ty
37 );* $(;)?) => {
38 $(
39 pub(crate) fn $fn_name($( $arg_name: $arg_type ),*) -> $ret_type {
40 EXTENSION.with(|ext| {
41 if let Some(ext) = ext.borrow().as_ref() {
42 ext.$fn_name($( $arg_name ),*)
43 } else {
44 panic!("No extension registered");
45 }
46 })
47 }
48 )*
49 };
50}
51
52thread_local!(
53 static EXTENSION: RefCell<Option<Rc<Box<dyn Extension>>>> = RefCell::new(None);
54);
55
56#[tracing::instrument(level = "debug", skip(extension))]
57pub fn register_extension(extension: Box<dyn Extension>) -> FnResult<()> {
58 EXTENSION.with(|ext| {
59 ext.borrow_mut().replace(Rc::new(extension));
60 });
61 Ok(())
62}
63
64generate_extension_methods!(
65 get_provider_scopes() -> MoosyncResult<Vec<ExtensionProviderScope>>;
67 get_playlists() -> MoosyncResult<Vec<Playlist>>;
68 get_playlist_content(id: String, next_page_token: Option<String>) -> MoosyncResult<SongsWithPageTokenReturnType>;
69 get_playlist_from_url(url: String) -> MoosyncResult<Option<Playlist>>;
70 get_playback_details(song: Song) -> MoosyncResult<PlaybackDetailsReturnType>;
71 search(term: String) -> MoosyncResult<SearchResult>;
72 get_recommendations() -> MoosyncResult<Vec<Song>>;
73 get_song_from_url(url: String) -> MoosyncResult<Option<Song>>;
74 handle_custom_request(url: String) -> MoosyncResult<CustomRequestReturnType>;
75 get_artist_songs(artist: Artist, next_page_token: Option<String>) -> MoosyncResult<SongsWithPageTokenReturnType>;
76 get_album_songs(album: Album, next_page_token: Option<String>) -> MoosyncResult<SongsWithPageTokenReturnType>;
77 get_song_from_id(id: String) -> MoosyncResult<Option<Song>>;
78 scrobble(song: Song) -> MoosyncResult<()>;
79 oauth_callback(code: String) -> MoosyncResult<()>;
80 get_lyrics(song: Song) -> MoosyncResult<String>;
81
82 on_queue_changed(queue: Value) -> MoosyncResult<()>;
84 on_volume_changed() -> MoosyncResult<()>;
85 on_player_state_changed() -> MoosyncResult<()>;
86 on_song_changed() -> MoosyncResult<()>;
87 on_seeked(time: f64) -> MoosyncResult<()>;
88
89 on_preferences_changed(args: PreferenceArgs) -> MoosyncResult<()>;
91
92 on_song_added(song: Song) -> MoosyncResult<()>;
94 on_song_removed(song: Song) -> MoosyncResult<()>;
95 on_playlist_added(playlist: Playlist) -> MoosyncResult<()>;
96 on_playlist_removed(playlist: Playlist) -> MoosyncResult<()>;
97
98 get_accounts() -> MoosyncResult<Vec<ExtensionAccountDetail>>;
100 perform_account_login(args: AccountLoginArgs) -> MoosyncResult<String>;
101
102 get_song_context_menu(songs: Vec<Song>) -> MoosyncResult<Vec<ContextMenuReturnType>>;
104 get_playlist_context_menu(playlist: Playlist) -> MoosyncResult<Vec<ContextMenuReturnType>>;
105 on_context_menu_action(action: String) -> MoosyncResult<()>;
106);