Skip to content

Commit

Permalink
feat: streaming-server urls bucket
Browse files Browse the repository at this point in the history
  • Loading branch information
kKaskak committed Oct 3, 2024
1 parent 416b2f9 commit a0ca367
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 26 deletions.
3 changes: 3 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ pub const CATALOG_PREVIEW_SIZE: usize = 100;
pub const LIBRARY_RECENT_COUNT: usize = 200;
pub const NOTIFICATION_ITEMS_COUNT: usize = 100;

pub const SERVER_URL_BUCKET_MAX_ITEMS: usize = 5;
pub const SERVER_URL_BUCKET_DEFAULT_ITEM_ID: &str = "0";

/// A `LibraryItem` is considered watched once we've watched more than the `duration * threshold`:
///
/// `LibraryItem.state.time_watched` > `LibraryItem.state.duration` * [`WATCHED_THRESHOLD_COEF`]
Expand Down
54 changes: 42 additions & 12 deletions src/models/streaming_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ use crate::types::empty_string_as_null;
use crate::types::profile::{AuthKey, Profile};
use crate::types::streaming_server::{
CreateMagnetRequest, CreateTorrentBlobRequest, DeviceInfo, GetHTTPSResponse, NetworkInfo,
Settings, SettingsResponse, Statistics, StatisticsRequest, TorrentStatisticsRequest,
ServerUrlBucket, Settings, SettingsResponse, Statistics, StatisticsRequest,
TorrentStatisticsRequest,
};
use crate::types::torrent::InfoHash;

Expand All @@ -43,7 +44,7 @@ pub struct Selected {
pub struct StreamingServer {
pub selected: Selected,
pub settings: Loadable<Settings, EnvError>,
pub base_url: Option<Url>,
pub base_url_bucket: ServerUrlBucket,
pub remote_url: Option<Url>,
pub playback_devices: Loadable<Vec<PlaybackDevice>, EnvError>,
pub network_info: Loadable<NetworkInfo, EnvError>,
Expand All @@ -68,7 +69,10 @@ impl StreamingServer {
statistics: None,
},
settings: Loadable::Loading,
base_url: None,
base_url_bucket: ServerUrlBucket::new(
profile.uid().to_owned(),
profile.settings.streaming_server_url.to_owned(),
),
remote_url: None,
playback_devices: Loadable::Loading,
network_info: Loadable::Loading,
Expand All @@ -88,7 +92,13 @@ impl<E: Env + 'static> UpdateWithCtx<E> for StreamingServer {
let settings_effects = eq_update(&mut self.settings, Loadable::Loading);
let network_info_effects = eq_update(&mut self.network_info, Loadable::Loading);
let device_info_effects = eq_update(&mut self.device_info, Loadable::Loading);
let base_url_effects = eq_update(&mut self.base_url, None);
let base_url_bucket_effects = eq_update(
&mut self.base_url_bucket,
ServerUrlBucket::new(
ctx.profile.uid().to_owned(),
ctx.profile.settings.streaming_server_url.to_owned(),
),
);
let remote_url_effects = eq_update(&mut self.remote_url, None);
Effects::many(vec![
get_settings::<E>(&self.selected.transport_url),
Expand All @@ -100,7 +110,7 @@ impl<E: Env + 'static> UpdateWithCtx<E> for StreamingServer {
.join(settings_effects)
.join(network_info_effects)
.join(device_info_effects)
.join(base_url_effects)
.join(base_url_bucket_effects)
.join(remote_url_effects)
}
Msg::Action(Action::StreamingServer(ActionStreamingServer::UpdateSettings(
Expand Down Expand Up @@ -229,7 +239,10 @@ impl<E: Env + 'static> UpdateWithCtx<E> for StreamingServer {
self.settings = Loadable::Loading;
self.network_info = Loadable::Loading;
self.device_info = Loadable::Loading;
self.base_url = None;
self.base_url_bucket = ServerUrlBucket::new(
ctx.profile.uid().to_owned(),
ctx.profile.settings.streaming_server_url.to_owned(),
);
self.remote_url = None;
self.torrent = None;
self.statistics = None;
Expand All @@ -249,20 +262,31 @@ impl<E: Env + 'static> UpdateWithCtx<E> for StreamingServer {
&mut self.settings,
Loadable::Ready(settings.values.to_owned()),
);
let base_url_effects =
eq_update(&mut self.base_url, Some(settings.base_url.to_owned()));
let base_url_bucket_effects = eq_update(
&mut self.base_url_bucket,
ServerUrlBucket::new(
ctx.profile.uid().to_owned(),
self.selected.transport_url.to_owned(),
),
);
let remote_url_effects = update_remote_url::<E>(
&mut self.remote_url,
&self.selected,
&settings.values,
ctx,
);
settings_effects
.join(base_url_effects)
.join(base_url_bucket_effects)
.join(remote_url_effects)
}
Err(error) => {
let base_url_effects = eq_update(&mut self.base_url, None);
let base_url_bucket_effects = eq_update(
&mut self.base_url_bucket,
ServerUrlBucket::new(
ctx.profile.uid().to_owned(),
self.selected.transport_url.to_owned(),
),
);
let remote_url_effects = eq_update(&mut self.remote_url, None);
let playback_devices_effects =
eq_update(&mut self.playback_devices, Loadable::Err(error.to_owned()));
Expand All @@ -273,7 +297,7 @@ impl<E: Env + 'static> UpdateWithCtx<E> for StreamingServer {
let settings_effects =
eq_update(&mut self.settings, Loadable::Err(error.to_owned()));
let torrent_effects = eq_update(&mut self.torrent, None);
base_url_effects
base_url_bucket_effects
.join(remote_url_effects)
.join(playback_devices_effects)
.join(network_info_effects)
Expand Down Expand Up @@ -326,7 +350,13 @@ impl<E: Env + 'static> UpdateWithCtx<E> for StreamingServer {
match result {
Ok(_) => Effects::none().unchanged(),
Err(error) => {
let base_url_effects = eq_update(&mut self.base_url, None);
let base_url_effects = eq_update(
&mut self.base_url_bucket,
ServerUrlBucket::new(
ctx.profile.uid().to_owned(),
self.selected.transport_url.to_owned(),
),
);
let remote_url_effects = eq_update(&mut self.remote_url, None);
let playback_devices_effects =
eq_update(&mut self.playback_devices, Loadable::Err(error.to_owned()));
Expand Down
6 changes: 6 additions & 0 deletions src/types/streaming_server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ pub use settings::*;
mod statistics;
pub use statistics::*;

mod server_url_item;
pub use server_url_item::*;

mod server_url_bucket;
pub use server_url_bucket::*;

use super::resource::SeriesInfo;
use crate::types::{torrent::InfoHash, DefaultOnBool};

Expand Down
108 changes: 108 additions & 0 deletions src/types/streaming_server/server_url_bucket.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use super::ServerUrlItem;
use crate::{
constants::{SERVER_URL_BUCKET_DEFAULT_ITEM_ID, SERVER_URL_BUCKET_MAX_ITEMS},
types::profile::UID,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
use url::Url;

#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
pub struct ServerUrlBucket {
/// User ID
pub uid: UID,
/// [`HashMap`] Key is the [`ServerUrlItem`]`.id`.
pub items: HashMap<String, ServerUrlItem>,
}

impl ServerUrlBucket {
/// Create a new [`ServerUrlBucket`] with the base URL inserted.
pub fn new(uid: UID, base_url: Url) -> Self {
let mut items = HashMap::new();

let server_url_item = ServerUrlItem {
id: SERVER_URL_BUCKET_DEFAULT_ITEM_ID.to_string(),
url: base_url.clone(),
mtime: Self::current_timestamp() as i64,
selected: true,
};

// Use the item's id as the key in the HashMap
items.insert(server_url_item.id.clone(), server_url_item);

ServerUrlBucket { uid, items }
}

fn current_timestamp() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_secs()
}

pub fn merge_bucket(&mut self, bucket: ServerUrlBucket) {
if self.uid == bucket.uid {
self.merge_items(bucket.items.into_values().collect());
}
}

pub fn merge_items(&mut self, items: Vec<ServerUrlItem>) {
for new_item in items.into_iter() {
match self.items.get_mut(&new_item.id) {
Some(item) => {
*item = new_item;
}
None => {
if self.items.len() < SERVER_URL_BUCKET_MAX_ITEMS {
self.items.insert(new_item.id.to_owned(), new_item);
} else {
let oldest_item_id_option = self
.items
.values()
.filter(|item| item.id != SERVER_URL_BUCKET_DEFAULT_ITEM_ID)
.min_by_key(|item| item.mtime)
.map(|item| item.id.clone());

if let Some(oldest_item_id) = oldest_item_id_option {
if new_item.mtime > self.items[&oldest_item_id].mtime {
self.items.remove(&oldest_item_id);
self.items.insert(new_item.id.to_owned(), new_item);
}
}
}
}
}
}
}

pub fn edit_item(&mut self, id: &str, new_url: Url) -> Result<(), String> {
if let Some(item) = self.items.get_mut(id) {
item.url = new_url;
item.mtime = Self::current_timestamp() as i64;
Ok(())
} else {
Err("Item not found".to_string())
}
}

/// Delete an item by its ID
pub fn delete_item(&mut self, id: &str) -> Result<(), String> {
if id == SERVER_URL_BUCKET_DEFAULT_ITEM_ID {
return Err("Cannot remove the base URL item.".to_string());
}
if self.items.remove(id).is_some() {
Ok(())
} else {
Err("Item not found".to_string())
}
}

pub fn selected_item(&self) -> Option<&ServerUrlItem> {
self.items.values().find(|item| item.selected)
}

pub fn selected_item_url(&self) -> Option<Url> {
self.selected_item().map(|item| item.url.clone())
}
}
26 changes: 26 additions & 0 deletions src/types/streaming_server/server_url_item.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use serde::{Deserialize, Serialize};
use url::Url;

/// Server URL Item
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct ServerUrlItem {
/// Unique ID
pub id: String,
/// URL
pub url: Url,
/// Timestamp
pub mtime: i64,
/// Selected
pub selected: bool,
}

impl ServerUrlItem {
pub fn new(id: String, url: Url, mtime: i64) -> Self {
ServerUrlItem {
id,
url,
mtime,
selected: false,
}
}
}
15 changes: 12 additions & 3 deletions stremio-core-web/src/model/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,10 @@ impl WebModel {
WebModelField::ContinueWatchingPreview => serialize_continue_watching_preview(
&self.continue_watching_preview,
&self.ctx.streams,
self.streaming_server.base_url.as_ref(),
self.streaming_server
.base_url_bucket
.selected_item_url()
.as_ref(),
&self.ctx.profile.settings,
),
WebModelField::Board => {
Expand All @@ -143,13 +146,19 @@ impl WebModel {
WebModelField::Library => serialize_library(
&self.library,
&self.ctx,
self.streaming_server.base_url.as_ref(),
self.streaming_server
.base_url_bucket
.selected_item_url()
.as_ref(),
"library".to_owned(),
),
WebModelField::ContinueWatching => serialize_library(
&self.continue_watching,
&self.ctx,
self.streaming_server.base_url.as_ref(),
self.streaming_server
.base_url_bucket
.selected_item_url()
.as_ref(),
"continuewatching".to_owned(),
),
WebModelField::Search => {
Expand Down
4 changes: 3 additions & 1 deletion stremio-core-web/src/model/serialize_discover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,9 @@ pub fn serialize_discover(
stream,
deep_links: StreamDeepLinks::from((
stream,
&streaming_server.base_url,
&streaming_server
.base_url_bucket
.selected_item_url(),
&ctx.profile.settings,
))
.into_web_deep_links(),
Expand Down
12 changes: 8 additions & 4 deletions stremio-core-web/src/model/serialize_meta_details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ pub fn serialize_meta_details<E: Env + 'static>(
deep_links: VideoDeepLinks::from((
video,
request,
&streaming_server.base_url,
&streaming_server.base_url_bucket.selected_item_url(),
&ctx.profile.settings,
))
.into_web_deep_links(),
Expand All @@ -184,7 +184,7 @@ pub fn serialize_meta_details<E: Env + 'static>(
progress: None,
deep_links: StreamDeepLinks::from((
stream,
&streaming_server.base_url,
&streaming_server.base_url_bucket.selected_item_url(),
&ctx.profile.settings,
))
.into_web_deep_links(),
Expand Down Expand Up @@ -257,7 +257,9 @@ pub fn serialize_meta_details<E: Env + 'static>(
|| {
StreamDeepLinks::from((
stream,
&streaming_server.base_url,
&streaming_server
.base_url_bucket
.selected_item_url(),
&ctx.profile.settings,
))
},
Expand All @@ -266,7 +268,9 @@ pub fn serialize_meta_details<E: Env + 'static>(
stream,
request,
&meta_item.request,
&streaming_server.base_url,
&streaming_server
.base_url_bucket
.selected_item_url(),
&ctx.profile.settings,
))
},
Expand Down
6 changes: 3 additions & 3 deletions stremio-core-web/src/model/serialize_player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub fn serialize_player<E: stremio_core::runtime::Env + 'static>(
stream: &selected.stream,
deep_links: StreamDeepLinks::from((
&selected.stream,
&streaming_server.base_url,
&streaming_server.base_url_bucket.selected_item_url(),
&ctx.profile.settings,
))
.into_web_deep_links(),
Expand Down Expand Up @@ -150,7 +150,7 @@ pub fn serialize_player<E: stremio_core::runtime::Env + 'static>(
deep_links: VideoDeepLinks::from((
video,
request,
&streaming_server.base_url,
&streaming_server.base_url_bucket.selected_item_url(),
&ctx.profile.settings,
))
.into_web_deep_links(),
Expand Down Expand Up @@ -231,7 +231,7 @@ pub fn serialize_player<E: stremio_core::runtime::Env + 'static>(
video,
stream_request,
meta_request,
&streaming_server.base_url,
&streaming_server.base_url_bucket.selected_item_url(),
&ctx.profile.settings,
))
.into_web_deep_links(),
Expand Down
Loading

0 comments on commit a0ca367

Please sign in to comment.