From b9fc79e2162d116538f5e6ba7539e1070adcc3cb Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Tue, 17 Dec 2024 13:50:56 +0200 Subject: [PATCH 1/4] feat(stremio-core-kotlin): AndroidEnv - emit more events Signed-off-by: Lachezar Lechev --- .../src/commonMain/rust/env/env.rs | 87 ++++++++++++------- 1 file changed, 58 insertions(+), 29 deletions(-) diff --git a/stremio-core-kotlin/src/commonMain/rust/env/env.rs b/stremio-core-kotlin/src/commonMain/rust/env/env.rs index 8f8e0cbb..34be29eb 100644 --- a/stremio-core-kotlin/src/commonMain/rust/env/env.rs +++ b/stremio-core-kotlin/src/commonMain/rust/env/env.rs @@ -20,6 +20,7 @@ use stremio_core::{ analytics::Analytics, models::{ctx::Ctx, streaming_server::StreamingServer}, runtime::{msg::Event, Env, EnvError, EnvFuture, EnvFutureExt, TryEnvFuture}, + types::api::AuthRequest, }; use crate::{ @@ -113,35 +114,63 @@ impl AndroidEnv { } pub fn emit_to_analytics(event: &AndroidEvent, model: &AndroidModel, path: &str) { let (name, data) = match event { - AndroidEvent::CoreEvent(Event::PlayerPlaying { load_time, context }) => ( - "playerPlaying".to_owned(), - json!({ - "loadTime": load_time, - "player": context - }), - ), - AndroidEvent::CoreEvent(Event::PlayerStopped { context }) => { - ("playerStopped".to_owned(), json!({ "player": context })) - } - AndroidEvent::CoreEvent(Event::PlayerEnded { - context, - is_binge_enabled, - is_playing_next_video, - }) => ( - "playerEnded".to_owned(), - json!({ - "player": context, - "isBingeEnabled": is_binge_enabled, - "isPlayingNextVideo": is_playing_next_video - }), - ), - AndroidEvent::CoreEvent(Event::TraktPlaying { context }) => { - ("traktPlaying".to_owned(), json!({ "player": context })) - } - AndroidEvent::CoreEvent(Event::TraktPaused { context }) => { - ("traktPaused".to_owned(), json!({ "player": context })) - } - _ => return, + AndroidEvent::CoreEvent(core_event) => match core_event { + Event::UserAuthenticated { auth_request } => ( + "login".to_owned(), + json!({ + "type": match auth_request { + AuthRequest::Login { facebook, .. } if *facebook => "facebook", + AuthRequest::Login { .. } => "login", + AuthRequest::Facebook { .. } => "authWithFacebook", + AuthRequest::LoginWithToken { .. } => "loginWithToken", + AuthRequest::Register { .. } => "register", + }, + }), + ), + Event::AddonInstalled { transport_url, id } => ( + "installAddon".to_owned(), + json!({ + "addonTransportUrl": transport_url, + "addonID": id + }), + ), + Event::AddonUninstalled { transport_url, id } => ( + "removeAddon".to_owned(), + json!({ + "addonTransportUrl": transport_url, + "addonID": id + }), + ), + Event::PlayerPlaying { load_time, context } => ( + "playerPlaying".to_owned(), + json!({ + "loadTime": load_time, + "player": context + }), + ), + Event::PlayerStopped { context } => { + ("playerStopped".to_owned(), json!({ "player": context })) + } + Event::PlayerEnded { + context, + is_binge_enabled, + is_playing_next_video, + } => ( + "playerEnded".to_owned(), + json!({ + "player": context, + "isBingeEnabled": is_binge_enabled, + "isPlayingNextVideo": is_playing_next_video + }), + ), + Event::TraktPlaying { context } => { + ("traktPlaying".to_owned(), json!({ "player": context })) + } + Event::TraktPaused { context } => { + ("traktPaused".to_owned(), json!({ "player": context })) + } + _ => return, + }, }; ANALYTICS.emit(name, data, &model.ctx, &model.streaming_server, path); } From b73d1fd3fac1c3cdb66ca9d1a968c8e9a95578f4 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Tue, 17 Dec 2024 13:54:02 +0200 Subject: [PATCH 2/4] feat(stremio-core-protobuf): VideoDeepLinks for MetaDetails and Player Signed-off-by: Lachezar Lechev --- .../proto/stremio/core/types/video.proto | 19 +++++ stremio-core-protobuf/src/bridge/loadable.rs | 21 +++-- .../src/bridge/resource_loadable.rs | 22 ++++- .../src/model/fields/meta_details.rs | 82 +++++++++++++++++-- .../src/model/fields/player.rs | 44 +++++++--- 5 files changed, 159 insertions(+), 29 deletions(-) diff --git a/stremio-core-protobuf/proto/stremio/core/types/video.proto b/stremio-core-protobuf/proto/stremio/core/types/video.proto index c507d844..f50ccdf6 100644 --- a/stremio-core-protobuf/proto/stremio/core/types/video.proto +++ b/stremio-core-protobuf/proto/stremio/core/types/video.proto @@ -18,9 +18,28 @@ message Video { required bool upcoming = 8; required bool watched = 9; required bool current_video = 10; + // Watch progress percentage + optional double progress = 11; + // scheduled: bool, + + required VideoDeepLinks deep_links = 12; message SeriesInfo { required int64 season = 1; required int64 episode = 2; } +} + +message VideoDeepLinks { + required string meta_details_videos = 1; + required string meta_details_streams = 2; + // pub player: Option, + // pub external_player: Option, + optional string player = 3; + required ExternalPlayerLink external_player = 4; + + message ExternalPlayerLink { + optional string download = 1; + optional string streaming = 2; + } } \ No newline at end of file diff --git a/stremio-core-protobuf/src/bridge/loadable.rs b/stremio-core-protobuf/src/bridge/loadable.rs index 2d46a145..61eb41b0 100644 --- a/stremio-core-protobuf/src/bridge/loadable.rs +++ b/stremio-core-protobuf/src/bridge/loadable.rs @@ -7,7 +7,7 @@ use stremio_core::{ common::{Loadable, ResourceError}, ctx::{Ctx, CtxError}, link::LinkError, - streaming_server::PlaybackDevice, + streaming_server::{PlaybackDevice, StreamingServer}, }, runtime::EnvError, types::{ @@ -53,6 +53,8 @@ impl ToProtobuf< models::loadable_meta_item::Content, ( + &Ctx, + &StreamingServer, Option<&LibraryItem>, Option<&WatchedBitField>, Option<&String>, @@ -62,7 +64,9 @@ impl { fn to_protobuf( &self, - (library_item, watched, addon_name, meta_request): &( + (ctx, streaming_server, library_item, watched, addon_name, meta_request): &( + &Ctx, + &StreamingServer, Option<&LibraryItem>, Option<&WatchedBitField>, Option<&String>, @@ -70,9 +74,16 @@ impl ), ) -> models::loadable_meta_item::Content { match &self { - Loadable::Ready(ready) => models::loadable_meta_item::Content::Ready( - ready.to_protobuf::(&(*library_item, *watched, *addon_name, *meta_request)), - ), + Loadable::Ready(ready) => { + models::loadable_meta_item::Content::Ready(ready.to_protobuf::(&( + *ctx, + *streaming_server, + *library_item, + *watched, + *addon_name, + *meta_request, + ))) + } Loadable::Err(error) => models::loadable_meta_item::Content::Error(models::Error { message: error.to_string(), }), diff --git a/stremio-core-protobuf/src/bridge/resource_loadable.rs b/stremio-core-protobuf/src/bridge/resource_loadable.rs index 4aa39f44..ad7a60cd 100644 --- a/stremio-core-protobuf/src/bridge/resource_loadable.rs +++ b/stremio-core-protobuf/src/bridge/resource_loadable.rs @@ -6,6 +6,7 @@ use stremio_core::{ models::{ common::{DescriptorLoadable, ResourceLoadable}, ctx::Ctx, + streaming_server::StreamingServer, }, types::{ addon::{Descriptor, ResourceRequest}, @@ -60,18 +61,33 @@ impl ToProtobuf for ResourceLoadable, Option<&WatchedBitField>)> - for &ResourceLoadable +impl + ToProtobuf< + models::LoadableMetaItem, + ( + &Ctx, + &StreamingServer, + Option<&LibraryItem>, + Option<&WatchedBitField>, + ), + > for &ResourceLoadable { fn to_protobuf( &self, - (ctx, library_item, watched): &(&Ctx, Option<&LibraryItem>, Option<&WatchedBitField>), + (ctx, streming_server, library_item, watched): &( + &Ctx, + &StreamingServer, + Option<&LibraryItem>, + Option<&WatchedBitField>, + ), ) -> models::LoadableMetaItem { let addon_name = get_addon_name(ctx, &self.request.base); models::LoadableMetaItem { title: addon_name.to_string(), request: self.request.to_protobuf::(&()), content: self.content.to_protobuf::(&( + *ctx, + *streming_server, *library_item, *watched, Some(&addon_name), diff --git a/stremio-core-protobuf/src/model/fields/meta_details.rs b/stremio-core-protobuf/src/model/fields/meta_details.rs index 52336786..cd3b78f2 100644 --- a/stremio-core-protobuf/src/model/fields/meta_details.rs +++ b/stremio-core-protobuf/src/model/fields/meta_details.rs @@ -1,13 +1,19 @@ use boolinator::Boolinator; -use stremio_core::deep_links::MetaItemDeepLinks; + +use stremio_core::deep_links::{MetaItemDeepLinks, VideoDeepLinks}; use stremio_core::models::ctx::Ctx; -use stremio_core::models::meta_details::{MetaDetails, Selected}; +use stremio_core::models::{ + meta_details::{MetaDetails, Selected}, + streaming_server::StreamingServer, +}; use stremio_core::runtime::Env; use stremio_core::types::addon::ResourceRequest; use stremio_core::types::library::LibraryItem; use stremio_core::types::resource::{MetaItem, SeriesInfo, Video}; use stremio_core::types::watched_bitfield::WatchedBitField; +use url::Url; + use crate::bridge::{FromProtobuf, ToProtobuf}; use crate::protobuf::stremio::core::{models, types}; @@ -53,18 +59,25 @@ impl ToProtobuf< types::Video, ( + &Ctx, + Option<&Url>, + // &StreamingServer, Option<&LibraryItem>, Option<&WatchedBitField>, Option<&String>, + &ResourceRequest, ), > for Video { fn to_protobuf( &self, - (library_item, watched, addon_name): &( + (ctx, streaming_server_url, library_item, watched, addon_name, request): &( + &Ctx, + Option<&Url>, Option<&LibraryItem>, Option<&WatchedBitField>, Option<&String>, + &ResourceRequest, ), ) -> types::Video { types::Video { @@ -88,6 +101,23 @@ impl .and_then(|library_item| library_item.state.video_id.to_owned()) .map(|current_video_id| current_video_id == self.id) .unwrap_or_default(), + progress: library_item.and_then(|library_item| { + ctx.library + .items + .get(&library_item.id) + .filter(|library_item| Some(self.id.to_owned()) == library_item.state.video_id) + .map(|library_item| library_item.progress()) + }), + // scheduled: meta_item.preview.behavior_hints.has_scheduled_videos, + deep_links: VideoDeepLinks::from(( + self, + *request, + // necessary because Core doesn't use the + // preferred `Option<&Url>` format + &streaming_server_url.map(Clone::clone), + &ctx.profile.settings, + )) + .to_protobuf::(&()), } } } @@ -109,10 +139,32 @@ impl FromProtobuf