moosync_edk/
handler.rs

1// Moosync
2// Copyright (C) 2024, 2025  Moosync <support@moosync.app>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17use std::{cell::RefCell, rc::Rc};
18
19use extism_pdk::FnResult;
20use serde_json::Value;
21use types::entities::{QueryableAlbum, QueryableArtist, QueryablePlaylist, 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    // Provider trait methods
66    get_provider_scopes() -> MoosyncResult<Vec<ExtensionProviderScope>>;
67    get_playlists() -> MoosyncResult<Vec<QueryablePlaylist>>;
68    get_playlist_content(id: String, next_page_token: Option<String>) -> MoosyncResult<SongsWithPageTokenReturnType>;
69    get_playlist_from_url(url: String) -> MoosyncResult<Option<QueryablePlaylist>>;
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: QueryableArtist, next_page_token: Option<String>) -> MoosyncResult<SongsWithPageTokenReturnType>;
76    get_album_songs(album: QueryableAlbum, 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    // PlayerEvents trait methods
83    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    // PreferenceEvents trait methods
90    on_preferences_changed(args: PreferenceArgs) -> MoosyncResult<()>;
91
92    // DatabaseEvents trait methods
93    on_song_added(song: Song) -> MoosyncResult<()>;
94    on_song_removed(song: Song) -> MoosyncResult<()>;
95    on_playlist_added(playlist: QueryablePlaylist) -> MoosyncResult<()>;
96    on_playlist_removed(playlist: QueryablePlaylist) -> MoosyncResult<()>;
97
98    // Account trait methods
99    get_accounts() -> MoosyncResult<Vec<ExtensionAccountDetail>>;
100    perform_account_login(args: AccountLoginArgs) -> MoosyncResult<String>;
101
102    // ContextMenu trait methods
103    get_song_context_menu(songs: Vec<Song>) -> MoosyncResult<Vec<ContextMenuReturnType>>;
104    get_playlist_context_menu(playlist: QueryablePlaylist) -> MoosyncResult<Vec<ContextMenuReturnType>>;
105    on_context_menu_action(action: String) -> MoosyncResult<()>;
106);