Skip to content

Commit

Permalink
Merge pull request #522 from Stremio/feat/continue-watching-item-stream
Browse files Browse the repository at this point in the history
feat: deeplinks with stream bucket and CW items
  • Loading branch information
elpiel authored Sep 18, 2023
2 parents 1259c0c + 4380a6f commit 0ca1c1f
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 73 deletions.
50 changes: 43 additions & 7 deletions src/deep_links/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::{
profile::Settings,
query_params_encode,
resource::{MetaItem, MetaItemPreview, Stream, StreamSource, Video},
streams::StreamsItem,
},
};

Expand Down Expand Up @@ -48,18 +49,25 @@ pub struct ExternalPlayerLink {
pub file_name: Option<String>,
}

/// Using &Option<Url> is not encouraged, use `.as_ref()` to get an `Option<&Url>` instead!
impl From<(&Stream, &Option<Url>, &Settings)> for ExternalPlayerLink {
fn from((stream, streaming_server_url, settings): (&Stream, &Option<Url>, &Settings)) -> Self {
Self::from((stream, streaming_server_url.as_ref(), settings))
}
}

impl From<(&Stream, Option<&Url>, &Settings)> for ExternalPlayerLink {
/// Create an [`ExternalPlayerLink`] using the [`Stream`],
/// the server url (from [`StreamingServer::base_url`] which indicates a running or not server)
/// and the user's [`Settings`] in order to use the [`Settings::player_type`] for generating a
/// player-specific url.
///
/// [`StreamingServer::base_url`]: crate::models::streaming_server::StreamingServer::base_url
fn from((stream, streaming_server_url, settings): (&Stream, &Option<Url>, &Settings)) -> Self {
fn from((stream, streaming_server_url, settings): (&Stream, Option<&Url>, &Settings)) -> Self {
let http_regex = Regex::new(r"https?://").unwrap();
let download = stream.download_url();
let streaming = stream.streaming_url(streaming_server_url.as_ref());
let m3u_uri = stream.m3u_data_uri(streaming_server_url.as_ref());
let streaming = stream.streaming_url(streaming_server_url);
let m3u_uri = stream.m3u_data_uri(streaming_server_url);
let file_name = m3u_uri.as_ref().map(|_| "playlist.m3u".to_owned());
let href = m3u_uri.or_else(|| download.to_owned());
let open_player = match &streaming {
Expand Down Expand Up @@ -143,8 +151,15 @@ pub struct LibraryItemDeepLinks {
pub external_player: Option<ExternalPlayerLink>,
}

impl From<&LibraryItem> for LibraryItemDeepLinks {
fn from(item: &LibraryItem) -> Self {
impl From<(&LibraryItem, Option<&StreamsItem>, Option<&Url>, &Settings)> for LibraryItemDeepLinks {
fn from(
(item, streams_item, streaming_server_url, settings): (
&LibraryItem,
Option<&StreamsItem>,
Option<&Url>,
&Settings,
),
) -> Self {
LibraryItemDeepLinks {
meta_details_videos: item
.behavior_hints
Expand All @@ -170,8 +185,29 @@ impl From<&LibraryItem> for LibraryItemDeepLinks {
utf8_percent_encode(video_id, URI_COMPONENT_ENCODE_SET)
)
}),
player: None, // TODO use StreamsBucket
external_player: None, // TODO use StreamsBucket
// We have the steam so use the same logic as in StreamDeepLinks
player: streams_item.map(|streams_item| match streams_item.stream.encode() {
Ok(encoded_stream) => format!(
"stremio:///player/{}/{}/{}/{}/{}/{}",
utf8_percent_encode(&encoded_stream, URI_COMPONENT_ENCODE_SET),
utf8_percent_encode(
streams_item.stream_transport_url.as_str(),
URI_COMPONENT_ENCODE_SET
),
utf8_percent_encode(
streams_item.meta_transport_url.as_str(),
URI_COMPONENT_ENCODE_SET
),
utf8_percent_encode(&streams_item.r#type, URI_COMPONENT_ENCODE_SET),
utf8_percent_encode(&streams_item.meta_id, URI_COMPONENT_ENCODE_SET),
utf8_percent_encode(&streams_item.video_id, URI_COMPONENT_ENCODE_SET)
),
Err(error) => ErrorLink::from(error).into(),
}),
// We have the steams bucket item so use the same logic as in StreamDeepLinks
external_player: streams_item.map(|item| {
ExternalPlayerLink::from((&item.stream, streaming_server_url, settings))
}),
}
}
}
Expand Down
19 changes: 13 additions & 6 deletions src/models/ctx/update_streams.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use enclose::enclose;
use futures::FutureExt;

use crate::constants::STREAMS_STORAGE_KEY;
use crate::models::ctx::{CtxError, CtxStatus};
use crate::runtime::msg::{Action, ActionCtx, Event, Internal, Msg};
use crate::runtime::{Effect, EffectFuture, Effects, Env, EnvFutureExt};
use crate::types::streams::{StreamsBucket, StreamsItem, StreamsItemKey};
use enclose::enclose;
use futures::FutureExt;

pub fn update_streams<E: Env + 'static>(
streams: &mut StreamsBucket,
Expand All @@ -23,21 +24,27 @@ pub fn update_streams<E: Env + 'static>(
}
Msg::Internal(Internal::StreamLoaded {
stream,
meta_id: Some(meta_id),
video_id: Some(video_id),
transport_url: Some(transport_url),
stream_request: Some(stream_request),
meta_request: Some(meta_request),
}) => {
let meta_id = &meta_request.path.id;
let video_id = &stream_request.path.id;

let key = StreamsItemKey {
meta_id: meta_id.to_owned(),
video_id: video_id.to_owned(),
};

let streams_item = StreamsItem {
stream: stream.to_owned(),
r#type: meta_request.path.r#type.to_owned(),
meta_id: meta_id.to_owned(),
video_id: video_id.to_owned(),
transport_url: transport_url.to_owned(),
meta_transport_url: meta_request.base.to_owned(),
stream_transport_url: stream_request.base.to_owned(),
mtime: E::now(),
};

streams.items.insert(key, streams_item);
Effects::msg(Msg::Internal(Internal::StreamsChanged(false)))
}
Expand Down
14 changes: 2 additions & 12 deletions src/models/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,8 @@ impl<E: Env + 'static> UpdateWithCtx<E> for Player {
)) {
Effects::msg(Msg::Internal(Internal::StreamLoaded {
stream: selected.stream.to_owned(),
meta_id: selected
.meta_request
.as_ref()
.map(|meta_request| meta_request.path.id.to_owned()),
video_id: selected
.stream_request
.as_ref()
.map(|stream_request| stream_request.path.id.to_owned()),
transport_url: selected
.stream_request
.as_ref()
.map(|stream_request| stream_request.base.to_owned()),
stream_request: selected.stream_request.to_owned(),
meta_request: selected.meta_request.to_owned(),
}))
.unchanged()
} else {
Expand Down
5 changes: 2 additions & 3 deletions src/runtime/msg/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,8 @@ pub enum Internal {
/// Dispatched when a new stream is loaded into the Player.
StreamLoaded {
stream: Stream,
meta_id: Option<String>,
video_id: Option<String>,
transport_url: Option<Url>,
stream_request: Option<ResourceRequest>,
meta_request: Option<ResourceRequest>,
},
/// Dispatched when library item needs to be updated in the memory, storage and API.
UpdateLibraryItem(LibraryItem),
Expand Down
8 changes: 5 additions & 3 deletions src/types/streams/streams_bucket.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::types::profile::UID;
use crate::types::streams::StreamsItem;
use std::collections::HashMap;

use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use std::collections::HashMap;

use crate::types::profile::UID;
use crate::types::streams::StreamsItem;

#[derive(Default, Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
Expand Down
7 changes: 5 additions & 2 deletions src/types/streams/streams_item.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
use crate::types::resource::Stream;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use url::Url;

use crate::types::resource::Stream;

#[serde_as]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StreamsItem {
pub stream: Stream,
pub r#type: String,
pub meta_id: String,
pub video_id: String,
pub transport_url: Url,
pub meta_transport_url: Url,
pub stream_transport_url: Url,
/// Modification time
#[serde(rename = "_mtime")]
pub mtime: DateTime<Utc>,
Expand Down
Loading

0 comments on commit 0ca1c1f

Please sign in to comment.