Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/stream and subtitle relative url #641

Open
wants to merge 7 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions src/addon_transport/http_transport/http_transport.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use std::marker::PhantomData;

use futures::{future, FutureExt};
use http::Request;
use percent_encoding::utf8_percent_encode;
use url::Url;

use crate::addon_transport::http_transport::legacy::AddonLegacyTransport;
use crate::addon_transport::AddonTransport;
use crate::constants::{ADDON_LEGACY_PATH, ADDON_MANIFEST_PATH, URI_COMPONENT_ENCODE_SET};
use crate::runtime::{Env, EnvError, EnvFutureExt, TryEnvFuture};
use crate::types::addon::{Manifest, ResourcePath, ResourceResponse};
use crate::types::query_params_encode;
use futures::future;
use http::Request;
use percent_encoding::utf8_percent_encode;
use std::marker::PhantomData;
use url::Url;

pub struct AddonHTTPTransport<E: Env> {
transport_url: Url,
Expand Down Expand Up @@ -61,7 +63,19 @@ impl<E: Env> AddonTransport for AddonHTTPTransport<E> {
.as_str()
.replace(ADDON_MANIFEST_PATH, &path);
let request = Request::get(&url).body(()).expect("request builder failed");
E::fetch(request)
let addon_transport_url = self.transport_url.clone();
E::fetch::<_, ResourceResponse>(request)
.map(move |result| match result {
Ok(mut response_result) => {
// convert all relative paths in StreamSource::Url and `Subtitle.url`
// with absolute
response_result.convert_relative_paths(addon_transport_url.clone());

Ok(response_result)
}
Err(err) => Err(err),
})
.boxed_env()
}
fn manifest(&self) -> TryEnvFuture<Manifest> {
if self.transport_url.path().ends_with(ADDON_LEGACY_PATH) {
Expand Down
4 changes: 2 additions & 2 deletions src/models/meta_details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ impl<E: Env + 'static> UpdateWithCtx<E> for MetaDetails {
);
let watched_effects =
watched_update(&mut self.watched, &self.meta_items, &self.library_item);
let libraty_item_sync_effects = library_item_sync(&self.library_item, &ctx.profile);
libraty_item_sync_effects
let library_item_sync_effects = library_item_sync(&self.library_item, &ctx.profile);
library_item_sync_effects
.join(selected_effects)
.join(selected_override_effects)
.join(meta_items_effects)
Expand Down
210 changes: 209 additions & 1 deletion src/types/addon/response.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use derive_more::TryInto;
use serde::{de::Deserializer, Deserialize, Serialize};
use serde_with::{serde_as, VecSkipError};
use url::Url;

use crate::types::{
addon::DescriptorPreview,
Expand Down Expand Up @@ -122,6 +123,93 @@ pub enum ResourceResponse {
},
}

impl ResourceResponse {
/// Convert any relative path in `Stream.source` with absolute url using the provided addon's transport url
pub fn convert_relative_paths(&mut self, addon_transport_url: Url) {
match self {
ResourceResponse::Metas { ref mut metas } => {
metas
.iter_mut()
.flat_map(|meta_item_preview| {
meta_item_preview
.trailer_streams
.iter_mut()
.filter_map(|stream| stream.with_addon_url(&addon_transport_url).ok())
// .collect::<Result<_, _>>()
})
.collect()
}
ResourceResponse::MetasDetailed {
ref mut metas_detailed,
} => {
metas_detailed
.iter_mut()
.flat_map(|meta_item| {
// MetaItem videos
meta_item
.videos
.iter_mut()
.flat_map(|video| {
// MetaItem video streams
video
.streams
.iter_mut()
.filter_map(|stream| {
stream.with_addon_url(&addon_transport_url).ok()
})
.chain(
// MetaItem videos' trailer streams
video.trailer_streams.iter_mut().filter_map(|stream| {
stream.with_addon_url(&addon_transport_url).ok()
}),
)
})
// Trailer Streams of the MetaItemPreview
.chain(meta_item.preview.trailer_streams.iter_mut().filter_map(
|stream| stream.with_addon_url(&addon_transport_url).ok(),
))
})
.collect()
}
ResourceResponse::Meta { meta } => meta
.videos
.iter_mut()
.flat_map(|video| {
// MetaItem video streams
video
.streams
.iter_mut()
.filter_map(|stream| stream.with_addon_url(&addon_transport_url).ok())
.chain(
// MetaItem videos' trailer streams
video.trailer_streams.iter_mut().filter_map(|stream| {
stream.with_addon_url(&addon_transport_url).ok()
}),
)
})
// Trailer Streams of the MetaItemPreview
.chain(
meta.preview
.trailer_streams
.iter_mut()
.filter_map(|stream| stream.with_addon_url(&addon_transport_url).ok()),
)
.collect(),
ResourceResponse::Streams { streams } => streams
.iter_mut()
.filter_map(|stream| stream.with_addon_url(&addon_transport_url).ok())
.collect(),
ResourceResponse::Subtitles { subtitles } => subtitles
.iter_mut()
.filter_map(|subtitle| subtitle.with_addon_url(&addon_transport_url).ok())
.collect(),
ResourceResponse::Addons { .. } => {
// for addons - do nothing
}
}
}
}

#[serde_as]
#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(transparent)]
Expand Down Expand Up @@ -229,9 +317,18 @@ impl<'de> Deserialize<'de> for ResourceResponse {

#[cfg(test)]
mod tests {
use once_cell::sync::Lazy;
use serde_json::from_value;
use url::Url;

use crate::types::resource::{
MetaItem, MetaItemPreview, Stream, StreamBehaviorHints, StreamSource, UrlExtended, Video,
};

use super::ResourceResponse;

use super::*;
pub static ADDON_TRANSPORT_URL: Lazy<Url> =
Lazy::new(|| "https://example-addon.com/manifest.json".parse().unwrap());

#[test]
fn test_response_deserialization_keys() {
Expand Down Expand Up @@ -314,4 +411,115 @@ mod tests {
);
}
}

#[test]
fn replace_relative_path_for_meta() {
let relative_stream = Stream {
source: StreamSource::Url {
url: UrlExtended::RelativePath("/stream/path/tt123456.json".into()),
},
name: None,
description: None,
thumbnail: None,
subtitles: vec![],
behavior_hints: StreamBehaviorHints::default(),
};

let relative_video_trailer_stream = Stream {
source: StreamSource::Url {
url: UrlExtended::RelativePath("/stream/video/trailer/path/tt123456:1.json".into()),
},
name: None,
description: None,
thumbnail: None,
subtitles: vec![],
behavior_hints: StreamBehaviorHints::default(),
};

let relative_trailer_stream = Stream {
source: StreamSource::Url {
url: UrlExtended::RelativePath("/stream/trailer/path/tt123456.json".into()),
},
name: None,
description: None,
thumbnail: None,
subtitles: vec![],
behavior_hints: StreamBehaviorHints::default(),
};

let relative_meta_preview = {
let mut preview = MetaItemPreview::default();
preview
.trailer_streams
.push(relative_trailer_stream.clone());
preview
};

let relative_video_stream = {
let mut video = Video::default();
video
.trailer_streams
.push(relative_video_trailer_stream.clone());

video.streams.push(relative_stream.clone());
video
};

// Meta response with relative path
{
let mut resource_response = ResourceResponse::Meta {
meta: MetaItem {
preview: relative_meta_preview.clone(),
videos: vec![relative_video_stream.clone()],
},
};

resource_response.convert_relative_paths(ADDON_TRANSPORT_URL.clone());

let meta = match resource_response {
ResourceResponse::Meta { meta } => meta,
_ => unreachable!(),
};
// Meta trailer stream
assert_eq!(
"https://example-addon.com/stream/trailer/path/tt123456.json",
&meta
.preview
.trailer_streams
.first()
.unwrap()
.download_url()
.unwrap()
);

// Video stream
assert_eq!(
"https://example-addon.com/stream/path/tt123456.json",
&meta
.videos
.first()
.unwrap()
.streams
.first()
.unwrap()
.download_url()
.unwrap()
);

// Video trailer stream

assert_eq!(
"https://example-addon.com/stream/video/trailer/path/tt123456:1.json",
&meta
.videos
.first()
.unwrap()
.trailer_streams
.first()
.unwrap()
.download_url()
.unwrap()
);
}
}
}
Loading
Loading