aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-02-19 12:44:54 +0100
committermetamuffin <metamuffin@disroot.org>2026-02-19 12:44:54 +0100
commitb732b3022e931cd49ebee64fa140aeec3ae55cbc (patch)
treebc87d4ac8670ade2ee31fa7a470916cd8d5eaec1
parenta197ab4dc250311255056d4b36a6da8653e1040c (diff)
downloadjellything-b732b3022e931cd49ebee64fa140aeec3ae55cbc.tar
jellything-b732b3022e931cd49ebee64fa140aeec3ae55cbc.tar.bz2
jellything-b732b3022e931cd49ebee64fa140aeec3ae55cbc.tar.zst
remove old logic crate
-rw-r--r--Cargo.lock17
-rw-r--r--Cargo.toml13
-rw-r--r--logic/Cargo.toml17
-rw-r--r--logic/src/assets.rs57
-rw-r--r--logic/src/filter_sort.rs95
-rw-r--r--logic/src/home.rs138
-rw-r--r--logic/src/items.rs36
-rw-r--r--logic/src/lib.rs59
-rw-r--r--logic/src/login.rs23
-rw-r--r--logic/src/node.rs163
10 files changed, 6 insertions, 612 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c1c21c0..f1f910f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1850,23 +1850,6 @@ dependencies = [
]
[[package]]
-name = "jellylogic"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "bincode",
- "env_logger",
- "jellycommon",
- "jellydb",
- "jellyimport",
- "jellytranscoder",
- "log",
- "rand 0.9.2",
- "serde",
- "tokio",
-]
-
-[[package]]
name = "jellyobject"
version = "0.1.0"
dependencies = [
diff --git a/Cargo.toml b/Cargo.toml
index 8a5d846..765d373 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,24 +1,23 @@
[workspace]
members = [
"cache",
+ "cache/tools",
"common",
+ "common/object",
"database",
"ebml_derive",
"import",
"import/fallback_generator",
- "logic",
+ "kv",
+ "remuxer",
"server",
- "tool",
- "transcoder",
"stream",
"stream/types",
+ "tool",
+ "transcoder",
"ui",
"ui/client-scripts",
"ui/client-style",
- "remuxer",
- "common/object",
- "kv",
- "cache/tools",
]
resolver = "3"
default-members = ["server"]
diff --git a/logic/Cargo.toml b/logic/Cargo.toml
deleted file mode 100644
index 883fe5e..0000000
--- a/logic/Cargo.toml
+++ /dev/null
@@ -1,17 +0,0 @@
-[package]
-name = "jellylogic"
-version = "0.1.0"
-edition = "2024"
-
-[dependencies]
-jellyimport = { path = "../import" }
-jellycommon = { path = "../common" }
-jellydb = { path = "../database" }
-jellytranscoder = { path = "../transcoder" }
-log = "0.4.28"
-anyhow = "1.0.100"
-serde = { version = "1.0.228", features = ["derive", "rc"] }
-bincode = { version = "2.0.1", features = ["serde", "derive"] }
-rand = "0.9.2"
-env_logger = "0.11.8"
-tokio = { workspace = true }
diff --git a/logic/src/assets.rs b/logic/src/assets.rs
deleted file mode 100644
index 462c8bf..0000000
--- a/logic/src/assets.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2026 metamuffin <metamuffin.org>
-*/
-
-use crate::{DATABASE, session::Session};
-use anyhow::{Result, anyhow};
-
-pub async fn get_node_thumbnail(_session: &Session, id: NodeID, t: f64) -> Result<Asset> {
- let node = DATABASE
- .get_node(id)?
- .ok_or(anyhow!("node does not exist"))?;
-
- let media = node.media.as_ref().ok_or(anyhow!("no media"))?;
- let (thumb_track_index, _thumb_track) = media
- .tracks
- .iter()
- .enumerate()
- .find(|(_i, t)| matches!(t.kind, SourceTrackKind::Video { .. }))
- .ok_or(anyhow!("no video track to create a thumbnail of"))?;
- let source = media
- .tracks
- .get(thumb_track_index)
- .ok_or(anyhow!("no source"))?;
- let thumb_track_source = source.source.clone();
-
- if t < 0. || t > media.duration {
- Err(anyhow!("thumbnail instant not within media duration"))?
- }
-
- let step = 8.;
- let t = (t / step).floor() * step;
-
- Ok(match thumb_track_source {
- TrackSource::Local(path, _) => {
- Asset(jellytranscoder::thumbnail::create_thumbnail(&path, t)?)
- }
- TrackSource::Remote(_) => {
- // // TODO in the new system this is preferrably a property of node ext for regular fed
- // let session = fed
- // .get_session(
- // thumb_track
- // .federated
- // .last()
- // .ok_or(anyhow!("federation broken"))?,
- // )
- // .await?;
-
- // async_cache_file("fed-thumb", (id.0, t as i64), |out| {
- // session.node_thumbnail(out, id.0.into(), 2048, t)
- // })
- // .await?
- todo!()
- }
- })
-}
diff --git a/logic/src/filter_sort.rs b/logic/src/filter_sort.rs
deleted file mode 100644
index afa36f8..0000000
--- a/logic/src/filter_sort.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2026 metamuffin <metamuffin.org>
-*/
-use std::sync::Arc;
-
-pub fn filter_and_sort_nodes(
- f: &NodeFilterSort,
- default_sort: (SortProperty, SortOrder),
- nodes: &mut Vec<(Arc<Node>, NodeUserData)>,
-) {
- let sort_prop = f.sort_by.unwrap_or(default_sort.0);
- nodes.retain(|(node, _udata)| {
- let mut o = true;
- if let Some(prop) = &f.filter_kind {
- o = false;
- for p in prop {
- o |= match p {
- // FilterProperty::FederationLocal => node.federated.is_none(),
- // FilterProperty::FederationRemote => node.federated.is_some(),
- FilterProperty::KindMovie => node.kind == NodeKind::Movie,
- FilterProperty::KindVideo => node.kind == NodeKind::Video,
- FilterProperty::KindShortFormVideo => node.kind == NodeKind::ShortFormVideo,
- FilterProperty::KindMusic => node.kind == NodeKind::Music,
- FilterProperty::KindCollection => node.kind == NodeKind::Collection,
- FilterProperty::KindChannel => node.kind == NodeKind::Channel,
- FilterProperty::KindShow => node.kind == NodeKind::Show,
- FilterProperty::KindSeries => node.kind == NodeKind::Series,
- FilterProperty::KindSeason => node.kind == NodeKind::Season,
- FilterProperty::KindEpisode => node.kind == NodeKind::Episode,
- // FilterProperty::Watched => udata.watched == WatchedState::Watched,
- // FilterProperty::Unwatched => udata.watched == WatchedState::None,
- // FilterProperty::WatchProgress => {
- // matches!(udata.watched, WatchedState::Progress(_))
- // }
- _ => false, // TODO
- }
- }
- }
- match sort_prop {
- SortProperty::ReleaseDate => o &= node.release_date.is_some(),
- SortProperty::Duration => o &= node.media.is_some(),
- _ => (),
- }
- o
- });
- match sort_prop {
- SortProperty::Duration => {
- nodes.sort_by_key(|(n, _)| (n.media.as_ref().unwrap().duration * 1000.) as i64)
- }
- SortProperty::ReleaseDate => {
- nodes.sort_by_key(|(n, _)| n.release_date.expect("asserted above"))
- }
- SortProperty::Title => nodes.sort_by(|(a, _), (b, _)| a.title.cmp(&b.title)),
- SortProperty::Index => nodes.sort_by(|(a, _), (b, _)| {
- a.index
- .unwrap_or(usize::MAX)
- .cmp(&b.index.unwrap_or(usize::MAX))
- }),
- SortProperty::RatingRottenTomatoes => nodes.sort_by_cached_key(|(n, _)| {
- SortAnyway(*n.ratings.get(&RatingType::RottenTomatoes).unwrap_or(&0.))
- }),
- SortProperty::RatingMetacritic => nodes.sort_by_cached_key(|(n, _)| {
- SortAnyway(*n.ratings.get(&RatingType::Metacritic).unwrap_or(&0.))
- }),
- SortProperty::RatingImdb => nodes.sort_by_cached_key(|(n, _)| {
- SortAnyway(*n.ratings.get(&RatingType::Imdb).unwrap_or(&0.))
- }),
- SortProperty::RatingTmdb => nodes.sort_by_cached_key(|(n, _)| {
- SortAnyway(*n.ratings.get(&RatingType::Tmdb).unwrap_or(&0.))
- }),
- SortProperty::RatingYoutubeViews => nodes.sort_by_cached_key(|(n, _)| {
- SortAnyway(*n.ratings.get(&RatingType::YoutubeViews).unwrap_or(&0.))
- }),
- SortProperty::RatingYoutubeLikes => nodes.sort_by_cached_key(|(n, _)| {
- SortAnyway(*n.ratings.get(&RatingType::YoutubeLikes).unwrap_or(&0.))
- }),
- SortProperty::RatingYoutubeFollowers => nodes.sort_by_cached_key(|(n, _)| {
- SortAnyway(*n.ratings.get(&RatingType::YoutubeFollowers).unwrap_or(&0.))
- }),
- SortProperty::RatingLikesDivViews => nodes.sort_by_cached_key(|(n, _)| {
- SortAnyway(
- *n.ratings.get(&RatingType::YoutubeLikes).unwrap_or(&0.)
- / (1. + *n.ratings.get(&RatingType::YoutubeViews).unwrap_or(&0.)),
- )
- }),
- SortProperty::RatingUser => nodes.sort_by_cached_key(|(_, u)| u.rating),
- }
-
- match f.sort_order.unwrap_or(default_sort.1) {
- SortOrder::Ascending => (),
- SortOrder::Descending => nodes.reverse(),
- }
-}
diff --git a/logic/src/home.rs b/logic/src/home.rs
deleted file mode 100644
index 73fc182..0000000
--- a/logic/src/home.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2026 metamuffin <metamuffin.org>
-*/
-
-use crate::{DATABASE, node::DatabaseNodeUserDataExt, session::Session};
-use anyhow::{Context, Result};
-
-pub fn home(session: &Session) -> Result<ApiHomeResponse> {
- let mut items = DATABASE.list_nodes_with_udata(&session.user.name)?;
-
- let mut toplevel = DATABASE
- .get_node_children(NodeID::from_slug("library"))
- .context("root node missing")?
- .into_iter()
- .map(|n| DATABASE.get_node_with_userdata(n, session))
- .collect::<anyhow::Result<Vec<_>>>()?;
- toplevel.sort_by_key(|(n, _)| n.index.unwrap_or(usize::MAX));
-
- let mut categories = Vec::<(String, Vec<_>)>::new();
-
- categories.push((
- "home.bin.continue_watching".to_string(),
- items
- .iter()
- .filter(|(_, u)| matches!(u.watched, WatchedState::Progress(_)))
- .cloned()
- .collect(),
- ));
- categories.push((
- "home.bin.watchlist".to_string(),
- items
- .iter()
- .filter(|(_, u)| matches!(u.watched, WatchedState::Pending))
- .cloned()
- .collect(),
- ));
-
- items.retain(|(n, _)| matches!(n.visibility, Visibility::Visible));
-
- items.sort_by_key(|(n, _)| n.release_date.map(|d| -d).unwrap_or(i64::MAX));
-
- categories.push((
- "home.bin.latest_video".to_string(),
- items
- .iter()
- .filter(|(n, _)| matches!(n.kind, NodeKind::Video))
- .take(16)
- .cloned()
- .collect(),
- ));
- categories.push((
- "home.bin.latest_music".to_string(),
- items
- .iter()
- .filter(|(n, _)| matches!(n.kind, NodeKind::Music))
- .take(16)
- .cloned()
- .collect(),
- ));
- categories.push((
- "home.bin.latest_short_form".to_string(),
- items
- .iter()
- .filter(|(n, _)| matches!(n.kind, NodeKind::ShortFormVideo))
- .take(16)
- .cloned()
- .collect(),
- ));
-
- items.sort_by_key(|(n, _)| {
- n.ratings
- .get(&RatingType::Trakt)
- .map(|x| (*x * -1000.) as i32)
- .unwrap_or(0)
- });
-
- categories.push((
- "home.bin.max_rating".to_string(),
- items
- .iter()
- .filter(|(n, _)| n.ratings.contains_key(&RatingType::Trakt))
- .filter(|(n, _)| matches!(n.kind, NodeKind::Movie | NodeKind::Show))
- .take(16)
- .cloned()
- .collect(),
- ));
-
- items.retain(|(n, _)| {
- matches!(
- n.kind,
- NodeKind::Video | NodeKind::Movie | NodeKind::Episode | NodeKind::Music
- )
- });
-
- categories.push((
- "home.bin.daily_random".to_string(),
- (0..16)
- .flat_map(|i| Some(items[cheap_daily_random(i).checked_rem(items.len())?].clone()))
- .collect(),
- ));
-
- {
- let mut items = items.clone();
- items.retain(|(_, u)| matches!(u.watched, WatchedState::Watched));
- categories.push((
- "home.bin.watch_again".to_string(),
- (0..16)
- .flat_map(|i| Some(items[cheap_daily_random(i).checked_rem(items.len())?].clone()))
- .collect(),
- ));
- }
-
- items.retain(|(n, _)| matches!(n.kind, NodeKind::Music));
- categories.push((
- "home.bin.daily_random_music".to_string(),
- (0..16)
- .flat_map(|i| Some(items[cheap_daily_random(i).checked_rem(items.len())?].clone()))
- .collect(),
- ));
-
- Ok(ApiHomeResponse {
- toplevel,
- categories,
- })
-}
-
-fn cheap_daily_random(i: usize) -> usize {
- xorshift(xorshift(Utc::now().num_days_from_ce() as u64) + i as u64) as usize
-}
-
-fn xorshift(mut x: u64) -> u64 {
- x ^= x << 13;
- x ^= x >> 7;
- x ^= x << 17;
- x
-}
diff --git a/logic/src/items.rs b/logic/src/items.rs
deleted file mode 100644
index c618b9b..0000000
--- a/logic/src/items.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2026 metamuffin <metamuffin.org>
-*/
-
-use crate::{DATABASE, filter_sort::filter_and_sort_nodes, session::Session};
-use anyhow::Result;
-
-pub fn all_items(
- session: &Session,
- page: Option<usize>,
- filter: NodeFilterSort,
-) -> Result<ApiItemsResponse> {
- let mut items = DATABASE.list_nodes_with_udata(session.user.name.as_str())?;
-
- items.retain(|(n, _)| matches!(n.visibility, Visibility::Visible));
-
- filter_and_sort_nodes(
- &filter,
- (SortProperty::Title, SortOrder::Ascending),
- &mut items,
- );
-
- let page_size = 100;
- let page = page.unwrap_or(0);
- let offset = page * page_size;
- let from = offset.min(items.len());
- let to = (offset + page_size).min(items.len());
- let max_page = items.len().div_ceil(page_size);
- Ok(ApiItemsResponse {
- count: items.len(),
- pages: max_page,
- items: items[from..to].to_vec(),
- })
-}
diff --git a/logic/src/lib.rs b/logic/src/lib.rs
deleted file mode 100644
index 7a1bf46..0000000
--- a/logic/src/lib.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2026 metamuffin <metamuffin.org>
-*/
-#![feature(duration_constructors)]
-
-pub mod assets;
-pub mod filter_sort;
-pub mod home;
-pub mod items;
-pub mod login;
-pub mod node;
-pub mod permission;
-pub mod session;
-pub mod stats;
-
-use anyhow::Context;
-use anyhow::Result;
-use serde::{Deserialize, Serialize};
-use std::path::PathBuf;
-use std::sync::LazyLock;
-use std::sync::Mutex;
-
-#[rustfmt::skip]
-#[derive(Debug, Deserialize, Serialize, Default)]
-pub struct Config {
- login_expire: i64,
- session_key: Option<String>,
- admin_username:Option<String>,
- admin_password:Option<String>,
- database_path: PathBuf,
-}
-
-pub static CONF_PRELOAD: Mutex<Option<Config>> = Mutex::new(None);
-static CONF: LazyLock<Config> = LazyLock::new(|| {
- CONF_PRELOAD
- .lock()
- .unwrap()
- .take()
- .expect("logic config not preloaded. logic error")
-});
-
-static DATABASE_PRELOAD: Mutex<Option<Database>> = Mutex::new(None);
-static DATABASE: LazyLock<Database> = LazyLock::new(|| {
- DATABASE_PRELOAD
- .lock()
- .unwrap()
- .take()
- .expect("database not preloaded. logic error")
-});
-
-pub fn init_database() -> Result<()> {
- let database = Database::open(&CONF.database_path)
- .context("opening database")
- .unwrap();
- *DATABASE_PRELOAD.lock().unwrap() = Some(database);
- Ok(())
-}
diff --git a/logic/src/login.rs b/logic/src/login.rs
deleted file mode 100644
index 0d616ff..0000000
--- a/logic/src/login.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2026 metamuffin <metamuffin.org>
-*/
-use crate::{CONF, DATABASE, session::create};
-use anyhow::{Result, anyhow};
-use argon2::{Argon2, PasswordHasher, password_hash::Salt};
-use log::info;
-use std::{collections::HashSet, time::Duration};
-
-pub fn create_admin_account() -> Result<()> {
- if let Some(username) = &CONF.admin_username
- && let Some(password) = &CONF.admin_password
- {
- DATABASE
- .create_admin_user(username, hash_password(username, password))
- .unwrap();
- } else {
- info!("admin account disabled")
- }
- Ok(())
-}
diff --git a/logic/src/node.rs b/logic/src/node.rs
deleted file mode 100644
index 723b2f7..0000000
--- a/logic/src/node.rs
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2026 metamuffin <metamuffin.org>
-*/
-use crate::{DATABASE, filter_sort::filter_and_sort_nodes, session::Session};
-use anyhow::{Result, anyhow};
-use std::{cmp::Reverse, collections::BTreeMap, sync::Arc};
-
-pub fn get_node(
- session: &Session,
- id: NodeID,
- children: bool,
- parents: bool,
- filter: NodeFilterSort,
-) -> Result<ApiNodeResponse> {
- let (node, udata) = DATABASE.get_node_with_userdata(id, session)?;
-
- let mut children = if children {
- DATABASE
- .get_node_children(id)?
- .into_iter()
- .map(|c| DATABASE.get_node_with_userdata(c, session))
- .collect::<anyhow::Result<Vec<_>>>()?
- } else {
- Vec::new()
- };
-
- let mut parents = if parents {
- node.parents
- .iter()
- .map(|pid| DATABASE.get_node_with_userdata(*pid, session))
- .collect::<anyhow::Result<Vec<_>>>()?
- } else {
- Vec::new()
- };
-
- let mut similar = get_similar_media(session, &node)?;
-
- similar.retain(|(n, _)| n.visibility >= Visibility::Reduced);
- children.retain(|(n, _)| n.visibility >= Visibility::Reduced);
- parents.retain(|(n, _)| n.visibility >= Visibility::Reduced);
-
- filter_and_sort_nodes(
- &filter,
- match node.kind {
- NodeKind::Channel => (SortProperty::ReleaseDate, SortOrder::Descending),
- NodeKind::Season | NodeKind::Show => (SortProperty::Index, SortOrder::Ascending),
- _ => (SortProperty::Title, SortOrder::Ascending),
- },
- &mut children,
- );
-
- Ok(ApiNodeResponse {
- children,
- parents,
- node,
- userdata: udata,
- })
-}
-
-pub fn get_similar_media(session: &Session, node: &Node) -> Result<Vec<(Arc<Node>, NodeUserData)>> {
- let this_id = NodeID::from_slug(&node.slug);
- let mut ranking = BTreeMap::<NodeID, usize>::new();
- for tag in &node.tags {
- let nodes = DATABASE.get_tag_nodes(tag)?;
- let weight = 1_000_000 / nodes.len();
- for n in nodes {
- if n != this_id {
- *ranking.entry(n).or_default() += weight;
- }
- }
- }
- let mut ranking = ranking.into_iter().collect::<Vec<_>>();
- ranking.sort_by_key(|(_, k)| Reverse(*k));
- ranking
- .into_iter()
- .take(32)
- .map(|(pid, _)| DATABASE.get_node_with_userdata(pid, session))
- .collect::<anyhow::Result<Vec<_>>>()
-}
-
-pub trait DatabaseNodeUserDataExt {
- fn get_node_with_userdata(
- &self,
- id: NodeID,
- session: &Session,
- ) -> Result<(Arc<Node>, NodeUserData)>;
-}
-impl DatabaseNodeUserDataExt for Database {
- fn get_node_with_userdata(
- &self,
- id: NodeID,
- session: &Session,
- ) -> Result<(Arc<Node>, NodeUserData)> {
- Ok((
- self.get_node(id)?.ok_or(anyhow!("node does not exist"))?,
- self.get_node_udata(id, &session.user.name)?
- .unwrap_or_default(),
- ))
- }
-}
-
-pub fn get_nodes_modified_since(_session: &Session, since: u64) -> Result<Vec<NodeID>> {
- let mut nodes = DATABASE.get_nodes_modified_since(since)?;
- nodes.retain(|id| {
- DATABASE.get_node(*id).is_ok_and(|n| {
- n.as_ref()
- .is_some_and(|n| n.visibility >= Visibility::Reduced)
- })
- });
- Ok(nodes)
-}
-
-pub fn get_node_by_eid(
- _session: &Session,
- ty: IdentifierType,
- value: &str,
-) -> Result<Option<NodeID>> {
- DATABASE.get_node_by_identifier(ty, value)
-}
-pub fn node_id_to_slug(_session: &Session, id: NodeID) -> Result<String> {
- Ok(DATABASE
- .get_node(id)?
- .ok_or(anyhow!("node does not exist"))?
- .slug
- .to_owned())
-}
-
-pub fn update_node_userdata_watched(
- session: &Session,
- node: NodeID,
- state: WatchedState,
-) -> Result<()> {
- // TODO perm
- DATABASE.update_node_udata(node, &session.user.name, |udata| {
- udata.watched = state;
- Ok(())
- })
-}
-pub fn update_node_userdata_watched_progress(
- session: &Session,
- node: NodeID,
- time: f64,
-) -> Result<()> {
- // TODO perm
- DATABASE.update_node_udata(node, &session.user.name, |udata| {
- udata.watched = match udata.watched {
- WatchedState::None | WatchedState::Pending | WatchedState::Progress(_) => {
- WatchedState::Progress(time)
- }
- WatchedState::Watched => WatchedState::Watched,
- };
- Ok(())
- })
-}
-pub fn update_node_userdata_rating(session: &Session, node: NodeID, rating: i32) -> Result<()> {
- // TODO perm
- DATABASE.update_node_udata(node, &session.user.name, |udata| {
- udata.rating = rating;
- Ok(())
- })
-}