Skip to content

Commit

Permalink
Merge branch 'development' of github.com:Stremio/stremio-core into su…
Browse files Browse the repository at this point in the history
…rround_sound_enabled
  • Loading branch information
unclekingpin committed Nov 25, 2023
2 parents 75dd52f + 0745d79 commit afef088
Show file tree
Hide file tree
Showing 35 changed files with 400 additions and 15 deletions.
1 change: 1 addition & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub const PROFILE_STORAGE_KEY: &str = "profile";
pub const LIBRARY_STORAGE_KEY: &str = "library";
pub const LIBRARY_RECENT_STORAGE_KEY: &str = "library_recent";
pub const STREAMS_STORAGE_KEY: &str = "streams";
pub const SEARCH_HISTORY_STORAGE_KEY: &str = "search_history";
pub const NOTIFICATIONS_STORAGE_KEY: &str = "notifications";
pub const LIBRARY_COLLECTION_NAME: &str = "libraryItem";
pub const SEARCH_EXTRA_NAME: &str = "search";
Expand Down
12 changes: 11 additions & 1 deletion src/deep_links/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub struct ExternalPlayerLink {
pub file_name: Option<String>,
}

/// Using &Option<Url> is not encouraged, use `.as_ref()` to get an `Option<&Url>` instead!
/// 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))
Expand All @@ -64,6 +64,8 @@ impl From<(&Stream, Option<&Url>, &Settings)> for ExternalPlayerLink {
///
/// [`StreamingServer::base_url`]: crate::models::streaming_server::StreamingServer::base_url
fn from((stream, streaming_server_url, settings): (&Stream, Option<&Url>, &Settings)) -> Self {
// Use streaming_server_url from settings if streaming_server is reachable
let streaming_server_url = streaming_server_url.map(|_| &settings.streaming_server_url);
let http_regex = Regex::new(r"https?://").unwrap();
let download = stream.download_url();
let streaming = stream.streaming_url(streaming_server_url);
Expand Down Expand Up @@ -110,6 +112,14 @@ impl From<(&Stream, Option<&Url>, &Settings)> for ExternalPlayerLink {
ios: Some(format!("infuse://x-callback-url/play?url={url}")),
..Default::default()
}),
"iina" => Some(OpenPlayerLink {
macos: Some(format!("iina://weblink?url={url}")),
..Default::default()
}),
"mpv" => Some(OpenPlayerLink {
macos: Some(format!("mpv://{url}")),
..Default::default()
}),
_ => None,
},
None => None,
Expand Down
17 changes: 16 additions & 1 deletion src/models/catalogs_with_extra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,22 @@ impl<E: Env + 'static> UpdateWithCtx<E> for CatalogsWithExtra {
let selected_effects = selected_update(&mut self.selected, selected);
let catalogs_effects =
catalogs_update::<E>(&mut self.catalogs, &self.selected, None, &ctx.profile);
selected_effects.join(catalogs_effects)
let search_effects = match &self.selected {
Some(Selected { extra, .. }) => match extra
.iter()
.find(|ExtraValue { name, .. }| name == "search")
{
Some(ExtraValue { value, .. }) => {
Effects::msg(Msg::Internal(Internal::CatalogsWithExtraSearch {
query: value.to_owned(),
}))
.unchanged()
}
None => Effects::none().unchanged(),
},
None => Effects::none().unchanged(),
};
selected_effects.join(catalogs_effects).join(search_effects)
}
Msg::Action(Action::Unload) => {
let selected_effects = eq_update(&mut self.selected, None);
Expand Down
18 changes: 16 additions & 2 deletions src/models/ctx/ctx.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::constants::LIBRARY_COLLECTION_NAME;
use crate::models::common::{DescriptorLoadable, ResourceLoadable};
use crate::models::ctx::{
update_library, update_notifications, update_profile, update_streams, update_trakt_addon,
CtxError,
update_library, update_notifications, update_profile, update_search_history, update_streams,
update_trakt_addon, CtxError,
};
use crate::runtime::msg::{Action, ActionCtx, Event, Internal, Msg};
use crate::runtime::{Effect, EffectFuture, Effects, Env, EnvFutureExt, Update};
Expand All @@ -14,6 +14,7 @@ use crate::types::library::LibraryBucket;
use crate::types::notifications::NotificationsBucket;
use crate::types::profile::{Auth, AuthKey, Profile};
use crate::types::resource::MetaItem;
use crate::types::search_history::SearchHistoryBucket;
use crate::types::streams::StreamsBucket;

#[cfg(test)]
Expand Down Expand Up @@ -44,6 +45,8 @@ pub struct Ctx {
#[serde(skip)]
pub streams: StreamsBucket,
#[serde(skip)]
pub search_history: SearchHistoryBucket,
#[serde(skip)]
#[cfg_attr(test, derivative(Default(value = "CtxStatus::Ready")))]
pub status: CtxStatus,
#[serde(skip)]
Expand All @@ -59,11 +62,13 @@ impl Ctx {
library: LibraryBucket,
streams: StreamsBucket,
notifications: NotificationsBucket,
search_history: SearchHistoryBucket,
) -> Self {
Self {
profile,
library,
streams,
search_history,
notifications,
trakt_addon: None,
notification_catalogs: vec![],
Expand All @@ -90,6 +95,8 @@ impl<E: Env + 'static> Update<E> for Ctx {
let library_effects =
update_library::<E>(&mut self.library, &self.profile, &self.status, msg);
let streams_effects = update_streams::<E>(&mut self.streams, &self.status, msg);
let search_history_effects =
update_search_history::<E>(&mut self.search_history, &self.status, msg);
let trakt_addon_effects = update_trakt_addon::<E>(
&mut self.trakt_addon,
&self.profile,
Expand All @@ -111,6 +118,7 @@ impl<E: Env + 'static> Update<E> for Ctx {
.join(profile_effects)
.join(library_effects)
.join(streams_effects)
.join(search_history_effects)
.join(trakt_addon_effects)
.join(notifications_effects)
}
Expand All @@ -134,6 +142,8 @@ impl<E: Env + 'static> Update<E> for Ctx {
msg,
);
let streams_effects = update_streams::<E>(&mut self.streams, &self.status, msg);
let search_history_effects =
update_search_history::<E>(&mut self.search_history, &self.status, msg);
let ctx_effects = match &self.status {
CtxStatus::Loading(loading_auth_request)
if loading_auth_request == auth_request =>
Expand All @@ -160,6 +170,7 @@ impl<E: Env + 'static> Update<E> for Ctx {
.join(streams_effects)
.join(trakt_addon_effects)
.join(notifications_effects)
.join(search_history_effects)
.join(ctx_effects)
}
_ => {
Expand All @@ -182,11 +193,14 @@ impl<E: Env + 'static> Update<E> for Ctx {
&self.status,
msg,
);
let search_history_effects =
update_search_history::<E>(&mut self.search_history, &self.status, msg);
profile_effects
.join(library_effects)
.join(streams_effects)
.join(trakt_addon_effects)
.join(notifications_effects)
.join(search_history_effects)
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/models/ctx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use update_profile::*;
mod update_streams;
use update_streams::*;

mod update_search_history;
use update_search_history::*;

mod update_trakt_addon;
use update_trakt_addon::*;

Expand Down
63 changes: 63 additions & 0 deletions src/models/ctx/update_search_history.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use enclose::enclose;
use futures::FutureExt;

use crate::constants::SEARCH_HISTORY_STORAGE_KEY;
use crate::models::ctx::{CtxError, CtxStatus};
use crate::runtime::msg::{Action, ActionCtx, Event, Internal};
use crate::runtime::{Effect, EffectFuture, Effects, Env, EnvFutureExt};
use crate::{runtime::msg::Msg, types::search_history::SearchHistoryBucket};

pub fn update_search_history<E: Env + 'static>(
search_history: &mut SearchHistoryBucket,
status: &CtxStatus,
msg: &Msg,
) -> Effects {
match msg {
Msg::Action(Action::Ctx(ActionCtx::Logout)) | Msg::Internal(Internal::Logout) => {
let next_search_history = SearchHistoryBucket::default();
*search_history = next_search_history;
Effects::msg(Msg::Internal(Internal::SearchHistoryChanged))
}
Msg::Action(Action::Ctx(ActionCtx::ClearSearchHistory)) => {
search_history.items.clear();
Effects::msg(Msg::Internal(Internal::SearchHistoryChanged))
}
Msg::Internal(Internal::CatalogsWithExtraSearch { query }) => {
search_history.items.insert(query.to_owned(), E::now());
Effects::msg(Msg::Internal(Internal::SearchHistoryChanged))
}
Msg::Internal(Internal::CtxAuthResult(auth_request, result)) => match (status, result) {
(CtxStatus::Loading(loading_auth_request), Ok((auth, ..)))
if loading_auth_request == auth_request =>
{
let next_search_history = SearchHistoryBucket::new(Some(auth.user.id.to_owned()));
*search_history = next_search_history;
Effects::msg(Msg::Internal(Internal::SearchHistoryChanged))
}
_ => Effects::none().unchanged(),
},
Msg::Internal(Internal::SearchHistoryChanged) => {
Effects::one(push_search_history_to_storage::<E>(search_history)).unchanged()
}
_ => Effects::none().unchanged(),
}
}

fn push_search_history_to_storage<E: Env + 'static>(
search_history: &SearchHistoryBucket,
) -> Effect {
EffectFuture::Sequential(
E::set_storage(SEARCH_HISTORY_STORAGE_KEY, Some(&search_history))
.map(
enclose!((search_history.uid => uid) move |result| match result {
Ok(_) => Msg::Event(Event::SearchHistoryPushedToStorage { uid }),
Err(error) => Msg::Event(Event::Error {
error: CtxError::from(error),
source: Box::new(Event::SearchHistoryPushedToStorage { uid }),
})
}),
)
.boxed_env(),
)
.into()
}
32 changes: 31 additions & 1 deletion src/runtime/env.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::addon_transport::{AddonHTTPTransport, AddonTransport, UnsupportedTransport};
use crate::constants::{
LIBRARY_RECENT_STORAGE_KEY, LIBRARY_STORAGE_KEY, PROFILE_STORAGE_KEY, SCHEMA_VERSION,
SCHEMA_VERSION_STORAGE_KEY, STREAMS_STORAGE_KEY,
SCHEMA_VERSION_STORAGE_KEY, SEARCH_HISTORY_STORAGE_KEY, STREAMS_STORAGE_KEY,
};
use crate::models::ctx::Ctx;
use crate::models::streaming_server::StreamingServer;
Expand Down Expand Up @@ -498,6 +498,12 @@ fn migrate_storage_schema_to_v9<E: Env>() -> TryEnvFuture<()> {
}

fn migrate_storage_schema_to_v10<E: Env>() -> TryEnvFuture<()> {
E::set_storage::<()>(SEARCH_HISTORY_STORAGE_KEY, None)
.and_then(|_| E::set_storage(SCHEMA_VERSION_STORAGE_KEY, Some(&10)))
.boxed_env()
}

fn migrate_storage_schema_to_v11<E: Env>() -> TryEnvFuture<()> {
E::get_storage::<serde_json::Value>(PROFILE_STORAGE_KEY)
.and_then(|mut profile| {
match profile
Expand Down Expand Up @@ -572,6 +578,18 @@ mod test {
);
}

fn assert_storage_shema_version(schema_v: u32) {
let storage = STORAGE.read().expect("Should lock");

assert_eq!(
&schema_v.to_string(),
storage
.get(SCHEMA_VERSION_STORAGE_KEY)
.expect("Should have the schema set"),
"Scheme version should be {schema_v}"
);
}

#[tokio::test]
async fn test_migration_to_latest_version() {
{
Expand Down Expand Up @@ -898,6 +916,18 @@ mod test {

#[tokio::test]
async fn test_migration_from_9_to_10() {
let _test_env_guard = TestEnv::reset().expect("Should lock TestEnv");

migrate_storage_schema_to_v10::<TestEnv>()
.await
.expect("Should migrate");

{
assert_storage_shema_version(10);
}
}

async fn test_migration_from_10_to_11() {
{
let _test_env_guard = TestEnv::reset().expect("Should lock TestEnv");
let profile_before = json!({
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/msg/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{
types::{
addon::Descriptor,
api::AuthRequest,
library::LibraryItemId,
library::{LibraryItemId, LibraryItem},
profile::Settings as ProfileSettings,
resource::{MetaItemId, MetaItemPreview, Video},
},
Expand All @@ -45,6 +45,7 @@ pub enum ActionCtx {
ToggleLibraryItemNotifications(LibraryItemId, bool),
/// Dismiss all Notification for a given [`MetaItemId`].
DismissNotificationItem(MetaItemId),
ClearSearchHistory,
PushUserToAPI,
PullUserFromAPI,
PushAddonsToAPI,
Expand Down Expand Up @@ -85,10 +86,14 @@ pub enum ActionMetaDetails {
/// Marks the [`LibraryItem`] as watched.
///
/// Applicable when you have single-video (e.g. a movie) and multi-video (e.g. a movie series) item.
///
/// [`LibraryItem`]: crate::types::library::LibraryItem
MarkAsWatched(bool),
/// Marks the given [`Video`] of the [`LibraryItem`] as watched.
///
/// Applicable only when you have a multi-video (e.g. movie series) item.
///
/// [`LibraryItem`]: crate::types::library::LibraryItem
MarkVideoAsWatched(Video, bool),
}

Expand Down
3 changes: 3 additions & 0 deletions src/runtime/msg/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ pub enum Event {
StreamsPushedToStorage {
uid: UID,
},
SearchHistoryPushedToStorage {
uid: UID,
},
NotificationsPushedToStorage {
ids: Vec<String>,
},
Expand Down
8 changes: 8 additions & 0 deletions src/runtime/msg/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ pub enum Internal {
stream_request: Option<ResourceRequest>,
meta_request: Option<ResourceRequest>,
},
/// Dispatched when requesting search on catalogs.
CatalogsWithExtraSearch {
query: String,
},
/// Dispatched when library item needs to be updated in the memory, storage and API.
UpdateLibraryItem(LibraryItem),
/// Dispatched when some of auth, addons or settings changed.
Expand All @@ -66,9 +70,13 @@ pub enum Internal {
LibraryChanged(bool),
/// Dispatched when streams bucket changes with a flag if its already persisted.
StreamsChanged(bool),
/// Search history has changed.
SearchHistoryChanged,
/// User notifications have changed
NotificationsChanged,
/// Dismiss all Notifications for a given [`MetaItemId`].
///
/// [`MetaItemId`]: crate::types::resource::MetaItemId
DismissNotificationItem(LibraryItemId),
/// Result for loading link code.
LinkCodeResult(Result<LinkCodeResponse, LinkError>),
Expand Down
1 change: 1 addition & 0 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod library;
pub mod notifications;
pub mod profile;
pub mod resource;
pub mod search_history;
pub mod streaming_server;
pub mod streams;

Expand Down
9 changes: 3 additions & 6 deletions src/types/resource/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,9 @@ impl Stream {
}
pub fn streaming_url(&self, streaming_server_url: Option<&Url>) -> Option<String> {
match (&self.source, streaming_server_url) {
(StreamSource::Url { url }, _) if url.scheme() != "magnet" => {
match (streaming_server_url, &self.behavior_hints.proxy_headers) {
(
Some(streaming_server_url),
Some(StreamProxyHeaders { request, response }),
) => {
(StreamSource::Url { url }, Some(streaming_server_url)) if url.scheme() != "magnet" => {
match &self.behavior_hints.proxy_headers {
Some(StreamProxyHeaders { request, response }) => {
let mut streaming_url = streaming_server_url.to_owned();
let mut proxy_query = form_urlencoded::Serializer::new(String::new());
let origin = format!("{}://{}", url.scheme(), url.authority());
Expand Down
2 changes: 2 additions & 0 deletions src/types/search_history/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod search_history_bucket;
pub use search_history_bucket::*;
Loading

0 comments on commit afef088

Please sign in to comment.