plex_api/myplex/sharing/
mod.rs

1mod filter;
2mod friend;
3mod server;
4mod shareables;
5
6use crate::{
7    media_container::users::AllowTuners,
8    url::{MYPLEX_INVITES_FRIENDS, MYPLEX_INVITES_INVITE, MYPLEX_INVITES_SHARED_SERVERS},
9    MyPlex, Result,
10};
11use serde::{Deserialize, Serialize};
12
13pub use filter::SharingFilter;
14pub use friend::{Friend, InviteStatus};
15pub use server::SharedServer;
16pub use shareables::*;
17
18#[derive(Debug)]
19pub struct Sharing<'a> {
20    myplex: &'a MyPlex,
21}
22
23#[derive(Debug, Deserialize, Serialize)]
24#[serde(rename_all = "camelCase")]
25pub struct Permissions {
26    pub allow_sync: bool,
27    pub allow_channels: bool,
28    pub allow_tuners: AllowTuners,
29    pub allow_subtitle_admin: bool,
30    pub allow_camera_upload: bool,
31}
32
33impl Default for Permissions {
34    fn default() -> Self {
35        Self {
36            allow_sync: true,
37            allow_channels: true,
38            allow_tuners: AllowTuners::None,
39            allow_subtitle_admin: true,
40            allow_camera_upload: false,
41        }
42    }
43}
44
45#[derive(Default, Debug, Deserialize, Serialize, Clone)]
46pub struct Filters {
47    #[serde(rename = "filterMovies")]
48    pub movies: SharingFilter,
49    #[serde(rename = "filterMusic")]
50    pub music: SharingFilter,
51    #[serde(rename = "filterTelevision")]
52    pub television: SharingFilter,
53    #[serde(rename = "filterPhotos")]
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub photos: Option<SharingFilter>,
56    #[serde(rename = "filterAll", skip)]
57    _all: Option<String>,
58}
59
60#[derive(Serialize, Debug)]
61#[serde(rename_all = "camelCase")]
62struct ShareServerRequest {
63    invited_email: String,
64    settings: server::Settings,
65    library_section_ids: Vec<u32>,
66    machine_identifier: String,
67}
68
69impl<'a> Sharing<'a> {
70    pub fn new(myplex: &'a MyPlex) -> Self {
71        Sharing { myplex }
72    }
73
74    /// Invite a friend.
75    #[tracing::instrument(level = "debug", skip_all, fields(identifier = user.id()))]
76    pub async fn invite<'b>(&self, user: User<'b>) -> Result<friend::Friend> {
77        self.myplex
78            .client()
79            .post(format!(
80                "{}?{}",
81                MYPLEX_INVITES_INVITE,
82                serde_urlencoded::to_string([("identifier", user.id())])?
83            ))
84            .json()
85            .await
86    }
87
88    /// Share the server with somebody. The user doesn't have to be an accepted friend.
89    #[tracing::instrument(level = "debug", skip_all, fields(user_identifier = user.id(), machine_identifier = server.id()))]
90    pub async fn share<'b, 'c, 'd>(
91        &self,
92        user: User<'b>,
93        server: ShareableServer<'c>,
94        sections: &[ShareableLibrary<'d>],
95        permissions: Permissions,
96        filters: Filters,
97    ) -> Result<SharedServer> {
98        let server_info = self.myplex.server_info(server.id()).await?;
99        let sections: Vec<u32> = sections
100            .iter()
101            .filter_map(|s| s.id().parse().ok())
102            .collect();
103        let request = ShareServerRequest {
104            invited_email: user.id().to_owned(),
105            settings: server::Settings {
106                allow_channels: permissions.allow_channels,
107                allow_subtitle_admin: permissions.allow_subtitle_admin,
108                allow_sync: permissions.allow_sync,
109                allow_tuners: permissions.allow_tuners,
110                allow_camera_upload: permissions.allow_camera_upload,
111                filter_movies: Some(filters.movies),
112                filter_television: Some(filters.television),
113                filter_music: Some(filters.music),
114                filter_photos: filters.photos,
115                ..Default::default()
116            },
117            library_section_ids: server_info
118                .library_sections
119                .iter()
120                .filter_map(|s| {
121                    if sections.contains(&s.key) {
122                        Some(s.id)
123                    } else {
124                        None
125                    }
126                })
127                .collect(),
128            machine_identifier: server.id().to_owned(),
129        };
130
131        self.myplex
132            .client()
133            .post(MYPLEX_INVITES_SHARED_SERVERS)
134            .json_body(&request)?
135            .json()
136            .await
137    }
138
139    /// Returns a list of friends with the requested status, including managed users.
140    #[tracing::instrument(level = "debug", skip(self))]
141    pub async fn friends(&self, status: InviteStatus) -> Result<Vec<friend::Friend>> {
142        let mut friends: Vec<friend::Friend> = self
143            .myplex
144            .client()
145            .get(format!("{}?includeSharedServers=true&includeSharedSources=true&includeSharingSettings=true&status={}", MYPLEX_INVITES_FRIENDS, status))
146            .json()
147            .await?;
148
149        for friend in &mut friends {
150            friend.client = Some(self.myplex.client().clone())
151        }
152
153        Ok(friends)
154    }
155}