Skip to content

Commit

Permalink
Merge pull request #516 from Mossop/transcode
Browse files Browse the repository at this point in the history
feat: Add functionality for transcoding media.
  • Loading branch information
mergify[bot] committed Mar 5, 2023
2 parents 0c376c6 + 2584ed0 commit 91c89ae
Show file tree
Hide file tree
Showing 24 changed files with 9,138 additions and 23 deletions.
4 changes: 4 additions & 0 deletions crates/plex-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ async-std = { version = "^1.12", features = ["attributes"] }
plex-api-test-helper = { path = "../plex-api-test-helper" }
rstest = "^0.16.0"
rpassword = "^7.2"
dash-mpd = "^0.7.0"
hls_m3u8 = "^0.4.1"
mp4 = "^0.13.0"
mp3-metadata = "^0.3.4"

[dev-dependencies.cargo-husky]
version = "1"
Expand Down
6 changes: 6 additions & 0 deletions crates/plex-api/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ pub enum Error {
PinNotLinked,
#[error("Item requested was not found on the server.")]
ItemNotFound,
#[error("The requested transcode parameters were invalid.")]
InvalidTranscodeSettings,
#[error("The transcode request failed: {0}.")]
TranscodeError(String),
#[error("The server thinks the client should just play the original media.")]
TranscodeRefused,
}

const PLEX_API_ERROR_CODE_AUTH_OTP_REQUIRED: i32 = 1029;
Expand Down
39 changes: 35 additions & 4 deletions crates/plex-api/src/http_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::time::Duration;
use uuid::Uuid;

const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
const DEFAULT_CONNECTIONT_TIMEOUT: Duration = Duration::from_secs(5);
const DEFAULT_CONNECTION_TIMEOUT: Duration = Duration::from_secs(5);

#[derive(Debug, Clone)]
pub struct HttpClient {
Expand Down Expand Up @@ -114,6 +114,7 @@ impl HttpClient {
base_url: self.api_url.clone(),
path_and_query: path,
request_builder: self.prepare_request().method("POST"),
timeout: Some(DEFAULT_TIMEOUT),
}
}

Expand All @@ -129,6 +130,7 @@ impl HttpClient {
base_url: self.api_url.clone(),
path_and_query: path,
request_builder: self.prepare_request_min().method("POST"),
timeout: Some(DEFAULT_TIMEOUT),
}
}

Expand All @@ -143,6 +145,7 @@ impl HttpClient {
base_url: self.api_url.clone(),
path_and_query: path,
request_builder: self.prepare_request().method("GET"),
timeout: Some(DEFAULT_TIMEOUT),
}
}

Expand All @@ -158,6 +161,7 @@ impl HttpClient {
base_url: self.api_url.clone(),
path_and_query: path,
request_builder: self.prepare_request_min().method("GET"),
timeout: Some(DEFAULT_TIMEOUT),
}
}

Expand All @@ -172,6 +176,7 @@ impl HttpClient {
base_url: self.api_url.clone(),
path_and_query: path,
request_builder: self.prepare_request().method("PUT"),
timeout: Some(DEFAULT_TIMEOUT),
}
}

Expand All @@ -187,6 +192,7 @@ impl HttpClient {
base_url: self.api_url.clone(),
path_and_query: path,
request_builder: self.prepare_request_min().method("PUT"),
timeout: Some(DEFAULT_TIMEOUT),
}
}

Expand All @@ -201,6 +207,7 @@ impl HttpClient {
base_url: self.api_url.clone(),
path_and_query: path,
request_builder: self.prepare_request().method("DELETE"),
timeout: Some(DEFAULT_TIMEOUT),
}
}

Expand All @@ -216,6 +223,7 @@ impl HttpClient {
base_url: self.api_url.clone(),
path_and_query: path,
request_builder: self.prepare_request_min().method("DELETE"),
timeout: Some(DEFAULT_TIMEOUT),
}
}

Expand Down Expand Up @@ -245,13 +253,25 @@ where
base_url: Uri,
path_and_query: P,
request_builder: Builder,
timeout: Option<Duration>,
}

impl<'a, P> RequestBuilder<'a, P>
where
PathAndQuery: TryFrom<P>,
<PathAndQuery as TryFrom<P>>::Error: Into<http::Error>,
{
// Sets the maximum timeout for this request or disables timeouts.
pub fn timeout(self, timeout: Option<Duration>) -> RequestBuilder<'a, P> {
Self {
http_client: self.http_client,
base_url: self.base_url,
path_and_query: self.path_and_query,
request_builder: self.request_builder,
timeout,
}
}

/// Adds a body to the request.
pub fn body<B>(self, body: B) -> Result<Request<'a, B>>
where
Expand All @@ -262,9 +282,14 @@ where
uri_parts.path_and_query = Some(path_and_query);
let uri = Uri::from_parts(uri_parts).map_err(Into::<http::Error>::into)?;

let mut builder = self.request_builder.uri(uri);
if let Some(timeout) = self.timeout {
builder = builder.timeout(timeout);
}

Ok(Request {
http_client: self.http_client,
request: self.request_builder.uri(uri).body(body)?,
request: builder.body(body)?,
})
}

Expand All @@ -289,6 +314,7 @@ where
base_url: self.base_url,
path_and_query: self.path_and_query,
request_builder: self.request_builder.header(key, value),
timeout: self.timeout,
}
}

Expand Down Expand Up @@ -350,8 +376,7 @@ impl Default for HttpClientBuilder {
let client = HttpClient {
api_url: Uri::from_static(MYPLEX_DEFAULT_API_URL),
http_client: IsahcHttpClient::builder()
.timeout(DEFAULT_TIMEOUT)
.connect_timeout(DEFAULT_CONNECTIONT_TIMEOUT)
.connect_timeout(DEFAULT_CONNECTION_TIMEOUT)
.redirect_policy(RedirectPolicy::None)
.build()
.expect("failed to create default http client"),
Expand All @@ -376,6 +401,12 @@ impl Default for HttpClientBuilder {
}

impl HttpClientBuilder {
/// Creates a client that maps to Plex's Generic profile which has no
/// particular settings defined for transcoding.
pub fn generic() -> Self {
Self::default().set_x_plex_platform("Generic".to_string())
}

pub fn build(self) -> Result<HttpClient> {
self.client
}
Expand Down
9 changes: 8 additions & 1 deletion crates/plex-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@ pub use http_client::HttpClient;
pub use http_client::HttpClientBuilder;
pub use media_container::devices::Feature;
pub use media_container::preferences::Value as SettingValue;
pub use media_container::server::library::ContainerFormat;
pub use media_container::server::library::{
AudioCodec, ContainerFormat, Decision, Protocol, SubtitleCodec, VideoCodec,
};
pub use media_container::server::Feature as ServerFeature;
pub use myplex::{device, pin::PinManager, MyPlex, MyPlexBuilder};
pub use player::Player;
pub use server::library::{
Artist, Collection, Episode, Item, Library, MediaItem, MetadataItem, Movie, MusicAlbum, Photo,
PhotoAlbum, PhotoAlbumItem, Playlist, Season, Show, Track, Video,
};
pub use server::transcode::{
AudioSetting, Constraint, Limitation, MusicTranscodeOptions, TranscodeSession, TranscodeStatus,
VideoSetting, VideoTranscodeOptions,
};
pub use server::Server;

pub type Result<T = (), E = error::Error> = std::result::Result<T, E>;
Loading

0 comments on commit 91c89ae

Please sign in to comment.