diff options
Diffstat (limited to 'common')
| -rw-r--r-- | common/Cargo.toml | 5 | ||||
| -rw-r--r-- | common/object/src/lib.rs | 23 | ||||
| -rw-r--r-- | common/src/api.rs | 13 | ||||
| -rw-r--r-- | common/src/config.rs | 61 | ||||
| -rw-r--r-- | common/src/helpers.rs | 159 | ||||
| -rw-r--r-- | common/src/impl.rs | 116 | ||||
| -rw-r--r-- | common/src/jhls.rs | 5 | ||||
| -rw-r--r-- | common/src/lib.rs | 356 | ||||
| -rw-r--r-- | common/src/routes.rs | 13 | ||||
| -rw-r--r-- | common/src/user.rs | 2 |
10 files changed, 133 insertions, 620 deletions
diff --git a/common/Cargo.toml b/common/Cargo.toml index b0ecc02..1d7d0a8 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -4,10 +4,5 @@ version = "0.1.0" edition = "2024" [dependencies] -serde = { version = "1.0.228", features = ["derive", "rc"] } -chrono = { version = "0.4.42", features = ["serde"] } -blake3 = "1.8.2" -hex = "0.4.3" jellystream-types = { path = "../stream/types" } jellyobject = { path = "object" } -base64 = "0.22.1" diff --git a/common/object/src/lib.rs b/common/object/src/lib.rs index 97d2650..9f9e0be 100644 --- a/common/object/src/lib.rs +++ b/common/object/src/lib.rs @@ -39,8 +39,15 @@ impl<'a> Object<'a> { values: &buf[1 + nf + nf..], }) } - pub fn get_aligned(&self, tag: Tag) -> Option<&[u32]> { - let index = self.tags.binary_search(&tag.0).ok()?; + fn find_field(&self, tag: Tag) -> Option<usize> { + // using partition as binary search for the first field (instead of regular binary_search that returns any) + let first = self.tags.partition_point(|&x| x >= tag.0); + self.tags + .get(first) + .is_some_and(|&x| x == tag.0) + .then_some(first) + } + fn get_aligned(&self, index: usize) -> Option<&[u32]> { let start_raw = *self.offsets.get(index)?; let end_raw = self .offsets @@ -53,8 +60,7 @@ impl<'a> Object<'a> { Some(&self.values[start as usize..end as usize]) } - pub fn get_unaligned(&self, tag: Tag) -> Option<&[u8]> { - let index = self.tags.binary_search(&tag.0).ok()?; + fn get_unaligned(&self, index: usize) -> Option<&[u8]> { let start_raw = *self.offsets.get(index)?; let end_raw = self .offsets @@ -69,15 +75,12 @@ impl<'a> Object<'a> { let values_u8: &[u8] = bytemuck::cast_slice(self.values); Some(&values_u8[start as usize..end as usize]) } - pub fn get_str(&self, tag: Tag) -> Option<&str> { - self.get_unaligned(tag).and_then(|b| str::from_utf8(b).ok()) - } - pub fn get<'b: 'a, T: Value<'b>>(&'b self, tag: TypedTag<T>) -> Option<T> { + let index = self.find_field(tag.0)?; if T::ALIGNED { - T::load_aligned(self.get_aligned(tag.0)?) + T::load_aligned(self.get_aligned(index)?) } else { - T::load_unaligned(self.get_unaligned(tag.0)?) + T::load_unaligned(self.get_unaligned(index)?) } } } diff --git a/common/src/api.rs b/common/src/api.rs index 04e221e..043de1b 100644 --- a/common/src/api.rs +++ b/common/src/api.rs @@ -4,17 +4,10 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ use crate::{ - url_enum, user::{NodeUserData, User}, - Node, NodeKind, }; -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; use std::{collections::BTreeMap, sync::Arc, time::Duration}; -type NodesWithUdata = Vec<(Arc<Node>, NodeUserData)>; - -#[derive(Serialize, Deserialize)] pub struct ApiNodeResponse { pub parents: NodesWithUdata, pub children: NodesWithUdata, @@ -22,38 +15,32 @@ pub struct ApiNodeResponse { pub userdata: NodeUserData, } -#[derive(Serialize, Deserialize)] pub struct ApiSearchResponse { pub count: usize, pub results: NodesWithUdata, pub duration: Duration, } -#[derive(Serialize, Deserialize)] pub struct ApiItemsResponse { pub count: usize, pub pages: usize, pub items: NodesWithUdata, } -#[derive(Serialize, Deserialize)] pub struct ApiHomeResponse { pub toplevel: NodesWithUdata, pub categories: Vec<(String, NodesWithUdata)>, } -#[derive(Serialize, Deserialize)] pub struct ApiStatsResponse { pub kinds: BTreeMap<NodeKind, StatsBin>, pub total: StatsBin, } -#[derive(Serialize, Deserialize)] pub struct ApiAdminUsersResponse { pub users: Vec<User>, } -#[derive(Serialize, Deserialize)] pub struct LogLine { pub time: DateTime<Utc>, pub module: Option<&'static str>, diff --git a/common/src/config.rs b/common/src/config.rs deleted file mode 100644 index 73e2a08..0000000 --- a/common/src/config.rs +++ /dev/null @@ -1,61 +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::user::PermissionSet; -use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, path::PathBuf}; - -#[derive(Debug, Deserialize, Serialize, Default)] -pub struct GlobalConfig { - pub hostname: String, - pub brand: String, - pub slogan: String, - #[serde(default = "return_true")] - pub tls: bool, - pub asset_path: PathBuf, - pub database_path: PathBuf, - pub cache_path: PathBuf, - pub media_path: PathBuf, - pub secrets_path: PathBuf, - #[serde(default = "max_in_memory_cache_size")] - pub max_in_memory_cache_size: usize, - #[serde(default)] - pub admin_username: Option<String>, - #[serde(default = "login_expire")] - pub login_expire: i64, - #[serde(default)] - pub default_permission_set: PermissionSet, -} - -#[derive(Serialize, Deserialize, Debug, Default)] -pub struct SecretsConfig { - #[serde(default)] - pub federation: HashMap<String, FederationAccount>, - #[serde(default)] - pub cookie_key: Option<String>, - #[serde(default)] - pub session_key: Option<String>, - #[serde(default)] - pub admin_password: Option<String>, -} -#[derive(Serialize, Deserialize, Debug)] -pub struct FederationAccount { - pub username: String, - pub password: String, - #[serde(default = "return_true")] - pub tls: bool, -} - -fn login_expire() -> i64 { - 60 * 60 * 24 -} -fn max_in_memory_cache_size() -> usize { - 200_000_000 -} - -fn return_true() -> bool { - true -} diff --git a/common/src/helpers.rs b/common/src/helpers.rs deleted file mode 100644 index e8489c4..0000000 --- a/common/src/helpers.rs +++ /dev/null @@ -1,159 +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::{CreditCategory, IdentifierType, PictureSlot}; -use std::{fmt::Display, ops::Deref, str::FromStr}; - -#[derive(PartialEq)] -pub struct SortAnyway<T>(pub T); - -impl<T: PartialEq> Eq for SortAnyway<T> { - fn assert_receiver_is_total_eq(&self) {} -} -#[allow(clippy::non_canonical_partial_ord_impl)] -impl<T: PartialOrd> PartialOrd for SortAnyway<T> { - fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { - self.0.partial_cmp(&other.0) - } -} -impl<T: PartialOrd> Ord for SortAnyway<T> { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.partial_cmp(other).unwrap() - } -} - -impl<T> Deref for SortAnyway<T> { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Display for CreditCategory { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - CreditCategory::Cast => "cast", - CreditCategory::Writing => "writing", - CreditCategory::Directing => "directing", - CreditCategory::Art => "art", - CreditCategory::Sound => "sound", - CreditCategory::Camera => "camera", - CreditCategory::Lighting => "lighting", - CreditCategory::Crew => "crew", - CreditCategory::Editing => "editing", - CreditCategory::Production => "production", - CreditCategory::Vfx => "vfx", - CreditCategory::CostumeMakeup => "costume_makeup", - CreditCategory::CreatedBy => "created_by", - CreditCategory::Performance => "performance", - CreditCategory::Instrument => "instrument", - CreditCategory::Vocal => "vocal", - CreditCategory::Arranger => "arranger", - CreditCategory::Producer => "producer", - CreditCategory::Engineer => "engineer", - }) - } -} -impl FromStr for CreditCategory { - type Err = (); - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(match s { - "cast" => CreditCategory::Cast, - "writing" => CreditCategory::Writing, - "directing" => CreditCategory::Directing, - "art" => CreditCategory::Art, - "sound" => CreditCategory::Sound, - "camera" => CreditCategory::Camera, - "lighting" => CreditCategory::Lighting, - "crew" => CreditCategory::Crew, - "editing" => CreditCategory::Editing, - "production" => CreditCategory::Production, - "vfx" => CreditCategory::Vfx, - "costume_makeup" => CreditCategory::CostumeMakeup, - "created_by" => CreditCategory::CreatedBy, - "performance" => CreditCategory::Performance, - "instrument" => CreditCategory::Instrument, - "vocal" => CreditCategory::Vocal, - "arranger" => CreditCategory::Arranger, - "producer" => CreditCategory::Producer, - "engineer" => CreditCategory::Engineer, - _ => return Err(()), - }) - } -} -impl Display for IdentifierType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - IdentifierType::MusicbrainzRecording => "musicbrainz_recording", - IdentifierType::MusicbrainzArtist => "musicbrainz_artist", - IdentifierType::MusicbrainzRelease => "musicbrainz_release", - IdentifierType::MusicbrainzReleaseGroup => "musicbrainz_release_group", - IdentifierType::Isrc => "isrc", - IdentifierType::TraktEpisode => "trakt_episode", - IdentifierType::TraktMovie => "trakt_movie", - IdentifierType::TraktSeason => "trakt_season", - IdentifierType::TraktShow => "trakt_show", - IdentifierType::Imdb => "imdb", - IdentifierType::TmdbMovie => "tmdb_movie", - IdentifierType::TmdbSeries => "tmdb_tv", - IdentifierType::Tvdb => "tvdb", - IdentifierType::Omdb => "omdb", - IdentifierType::YoutubeVideo => "youtube_video", - IdentifierType::YoutubeChannel => "youtube_channel", - IdentifierType::YoutubeChannelHandle => "youtube_channel_handle", - IdentifierType::Barcode => "barcode", - IdentifierType::AcoustIdTrack => "acoustid_track", - IdentifierType::Bandcamp => "bandcamp", - IdentifierType::VgmdbArtist => "vgmdb_artist", - }) - } -} -impl FromStr for IdentifierType { - type Err = (); - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(match s { - "musicbrainz_recording" => IdentifierType::MusicbrainzRecording, - "musicbrainz_artist" => IdentifierType::MusicbrainzArtist, - "musicbrainz_release" => IdentifierType::MusicbrainzRelease, - "musicbrainz_release_group" => IdentifierType::MusicbrainzReleaseGroup, - "isrc" => IdentifierType::Isrc, - "trakt_episode" => IdentifierType::TraktEpisode, - "trakt_movie" => IdentifierType::TraktMovie, - "trakt_season" => IdentifierType::TraktSeason, - "trakt_show" => IdentifierType::TraktShow, - "imdb" => IdentifierType::Imdb, - "tmdb_movie" => IdentifierType::TmdbMovie, - "tmdb_tv" => IdentifierType::TmdbSeries, - "tvdb" => IdentifierType::Tvdb, - "omdb" => IdentifierType::Omdb, - "youtube_video" => IdentifierType::YoutubeVideo, - "youtube_channel" => IdentifierType::YoutubeChannel, - "youtube_channel_handle" => IdentifierType::YoutubeChannelHandle, - "barcode" => IdentifierType::Barcode, - "acoustid_track" => IdentifierType::AcoustIdTrack, - "vgmdb_artist" => IdentifierType::VgmdbArtist, - _ => return Err(()), - }) - } -} -impl Display for PictureSlot { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - PictureSlot::Backdrop => "backdrop", - PictureSlot::Cover => "cover", - }) - } -} -impl FromStr for PictureSlot { - type Err = (); - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(match s { - "backdrop" => PictureSlot::Backdrop, - "cover" => PictureSlot::Cover, - _ => return Err(()), - }) - } -} diff --git a/common/src/impl.rs b/common/src/impl.rs deleted file mode 100644 index 422d26a..0000000 --- a/common/src/impl.rs +++ /dev/null @@ -1,116 +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::{Node, NodeID, NodeIDOrSlug, SourceTrack, SourceTrackKind}; -use serde::{Deserialize, Serialize}; -use std::{fmt::Display, str::FromStr}; - -impl SourceTrackKind { - pub fn letter(&self) -> char { - match self { - SourceTrackKind::Video { .. } => 'v', - SourceTrackKind::Audio { .. } => 'a', - SourceTrackKind::Subtitle => 's', - } - } -} -impl Display for SourceTrack { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let kspec = match &self.kind { - SourceTrackKind::Video { - width, height, fps, .. - } => { - format!("Video: {width}x{height} {}fps ", fps.unwrap_or(0.)) - } - SourceTrackKind::Audio { - channels, - sample_rate, - bit_depth, - } => format!( - "Audio: {channels}ch {sample_rate}Hz {}bits ", - bit_depth.unwrap_or(0) - ), - SourceTrackKind::Subtitle => "Subtitle: ".to_string(), - }; - f.write_fmt(format_args!( - "{} {:?} {} ({})", - kspec, self.name, self.language, self.codec - )) - } -} - -impl NodeID { - pub fn from_slug(slug: &str) -> Self { - let mut h = blake3::Hasher::new(); - h.update(slug.as_bytes()); - Self(*h.finalize().as_bytes()) - } - #[inline] - pub fn from_node(node: &Node) -> Self { - Self::from_slug(&node.slug) - } -} -impl Node { - #[inline] - pub fn id(&self) -> NodeID { - NodeID::from_node(self) - } -} -impl NodeID { - pub const MIN: NodeID = NodeID([0; 32]); - pub const MAX: NodeID = NodeID([255; 32]); -} - -impl FromStr for NodeID { - type Err = hex::FromHexError; - fn from_str(s: &str) -> Result<Self, Self::Err> { - if let Some(id) = s.strip_prefix("+") { - let mut k = [0; 32]; - hex::decode_to_slice(id, &mut k)?; - Ok(NodeID(k)) - } else { - Ok(NodeID::from_slug(s)) - } - } -} -impl Display for NodeID { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("+")?; - f.write_str(&hex::encode(self.0))?; - Ok(()) - } -} -impl Display for NodeIDOrSlug { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - NodeIDOrSlug::ID(x) => x.fmt(f), - NodeIDOrSlug::Slug(x) => x.fmt(f), - } - } -} -impl From<NodeID> for NodeIDOrSlug { - fn from(value: NodeID) -> Self { - Self::ID(value) - } -} -impl From<String> for NodeIDOrSlug { - fn from(value: String) -> Self { - Self::Slug(value) - } -} -impl Serialize for NodeID { - fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { - serializer.serialize_str(&hex::encode(self.0)) - } -} -impl<'de> Deserialize<'de> for NodeID { - fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { - let mut k = [0; 32]; - hex::decode_to_slice(String::deserialize(deserializer)?, &mut k).map_err(|_| { - <D::Error as serde::de::Error>::custom(format_args!("nodeid hex invalid")) - })?; - Ok(NodeID(k)) - } -} diff --git a/common/src/jhls.rs b/common/src/jhls.rs deleted file mode 100644 index 36a6db6..0000000 --- a/common/src/jhls.rs +++ /dev/null @@ -1,5 +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> -*/ diff --git a/common/src/lib.rs b/common/src/lib.rs index f73130f..9ab0b91 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,272 +1,148 @@ /* 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> + Copyright (C) 2025 metamuffin <metamuffin.org> */ #![feature(array_try_map)] pub mod api; -pub mod config; -pub mod helpers; -pub mod r#impl; -pub mod jhls; pub mod routes; pub mod user; -pub use jellystream_types as stream; - -pub use chrono; - -use serde::{Deserialize, Serialize}; -use std::{ - collections::{BTreeMap, BTreeSet}, - path::PathBuf, -}; - -#[macro_export] -macro_rules! url_enum { - ($(#[$a:meta])* enum $i:ident { $($(#[$va:meta])* $vi:ident = $vk:literal),*, }) => { - $(#[$a])* - pub enum $i { $($(#[$va])* $vi),* } - impl $i { - pub const ALL: &'static [$i] = &[$($i::$vi),*]; - pub fn to_str(&self) -> &'static str { match self { $(Self::$vi => $vk),* } } - pub fn from_str_opt(s: &str) -> Option<Self> { match s { $($vk => Some(Self::$vi) ),*, _ => None } } - } - impl std::fmt::Display for $i { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(self.to_str()) - } - } - impl std::str::FromStr for $i { - type Err = (); - fn from_str(s: &str) -> Result<Self, Self::Err> { - Self::from_str_opt(s).ok_or(()) - } - } - }; -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct NodeID(pub [u8; 32]); - -pub enum NodeIDOrSlug { - ID(NodeID), - Slug(String), -} - use jellyobject::{Object, Tag, TypedTag}; +pub use jellystream_types as stream; use std::marker::PhantomData; -macro_rules! keys { + +macro_rules! fields { ($($id:ident: $type:ty = $tag:literal $name:literal;)*) => { $(pub const $id: TypedTag<$type> = TypedTag(Tag($tag), PhantomData);)* }; } - -keys! { - N_KIND: Tag = 1 "kind"; - N_TITLE: &str = 2 "title"; - N_PARENT: u64 = 3 "parent"; - N_TAGLINE: &str = 4 "tagline"; - N_DESCRIPTION: &str = 5 "description"; - N_RELEASEDATE: u64 = 6 "releasedate"; - N_INDEX: u64 = 7 "index"; - N_SEASON_INDEX: u64 = 8 "season_index"; - N_MEDIA: Object = 9 "media"; - N_TAG: &str = 10 "tag"; - N_RATINGS: Object = 11 "ratings"; - N_PICTURES: Object = 12 "pictures"; - N_IDENTIFIERS: Object = 13 "identifiers"; - N_VISIBILITY: Tag = 14 "visibility"; - N_STORAGE_SIZE: u64 = 15 "storage_size"; - - LANG_NATIVE: &str = 0xa001 "native"; - LANG_ENG: &str = 0xa002 "eng"; - LANG_DEU: &str = 0xa003 "deu"; - LANG_JPN: &str = 0xa003 "jpn"; -} - -#[derive(Debug, Clone, Deserialize, Serialize, Default)] -pub struct Node { - pub slug: String, - pub parents: BTreeSet<NodeID>, - pub kind: NodeKind, - pub title: Option<String>, - pub subtitle: Option<String>, - pub tagline: Option<String>, - pub description: Option<String>, - pub release_date: Option<i64>, // in unix millis - pub index: Option<usize>, - pub season_index: Option<usize>, - pub media: Option<MediaInfo>, - pub federated: Option<String>, - pub tags: BTreeSet<String>, - pub ratings: BTreeMap<RatingType, f64>, - pub pictures: BTreeMap<PictureSlot, Asset>, - pub credits: BTreeMap<CreditCategory, Vec<Appearance>>, - pub identifiers: BTreeMap<IdentifierType, String>, - pub visibility: Visibility, - pub storage_size: u64, +macro_rules! enums { + ($($id:ident = $tag:literal $name:literal;)*) => { + $(pub const $id: Tag = Tag($tag);)* + }; } -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)] -#[serde(rename_all = "snake_case")] -pub enum PictureSlot { - Cover, - Backdrop, -} +fields! { + // Tag counter: 32 -#[repr(u8)] -#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)] -#[serde(rename_all = "snake_case")] -pub enum IdentifierType { - MusicbrainzRecording, - MusicbrainzArtist, - MusicbrainzRelease, - MusicbrainzReleaseGroup, - AcoustIdTrack, - YoutubeVideo, - YoutubeChannel, - YoutubeChannelHandle, - Bandcamp, - Isrc, - Barcode, - TraktMovie, - TraktShow, - TraktSeason, - TraktEpisode, - Imdb, - TmdbSeries, - TmdbMovie, - Tvdb, - Omdb, - VgmdbArtist, -} + NO_KIND: Tag = 1 "kind"; + NO_TITLE: &str = 2 "title"; + NO_PARENT: u64 = 3 "parent"; // multi + NO_TAGLINE: &str = 4 "tagline"; + NO_DESCRIPTION: &str = 5 "description"; + NO_RELEASEDATE: u64 = 6 "releasedate"; + NO_INDEX: u64 = 7 "index"; + NO_SEASON_INDEX: u64 = 8 "season_index"; + NO_TRACK: Object = 9 "track"; // multi + NO_CHAPTER: Object = 32 "chapter"; // multi + NO_TAG: &str = 10 "tag"; // multi + NO_RATINGS: Object = 11 "ratings"; + NO_PICTURES: Object = 12 "pictures"; + NO_IDENTIFIERS: Object = 13 "identifiers"; + NO_VISIBILITY: Tag = 14 "visibility"; + NO_STORAGE_SIZE: u64 = 15 "storage_size"; + NO_CREDIT: Object = 33 "credit"; // multi -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Hash)] -pub struct Asset(pub String); + CR_NODE: u64 = 34 "node"; + CR_KIND: Tag = 34 "kind"; + CR_JOB: &str = 34 "node"; -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Appearance { - pub jobs: Vec<String>, - pub characters: Vec<String>, - pub node: NodeID, -} + TR_KIND: Tag = 16 "kind"; + TR_SOURCE: &str = 17 "source"; + TR_NAME: &str = 18 "name"; + TR_CODEC: &str = 19 "codec"; + TR_LANGUAGE: Tag = 20 "language"; + TR_RATE: f64 = 23 "rate"; + TR_BIT_DEPTH: f64 = 25 "bit_depth"; + TR_CHANNELS: f64 = 28 "channels"; + TR_PIXEL_WIDTH: u32 = 26 "pixel_width"; + TR_PIXEL_HEIGHT: u32 = 27 "pixel_height"; -#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)] -#[serde(rename_all = "snake_case")] -pub enum CreditCategory { - Cast, - Writing, - Directing, - Art, - Sound, - Camera, - Lighting, - Crew, - Editing, - Production, - Vfx, - CostumeMakeup, - CreatedBy, - Performance, - Instrument, - Vocal, - Arranger, - Producer, - Engineer, -} + TRSOURCE_LOCAL_PATH: &str = 21 "local_path"; + TRSOURCE_LOCAL_TRACKNUM: u64 = 22 "local_tracknum"; -#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Default)] -#[serde(rename_all = "snake_case")] -pub enum Visibility { - Hidden, - Reduced, - #[default] - Visible, -} + CH_START: f64 = 29 "start"; + CH_END: f64 = 30 "end"; + CH_NAME: f64 = 31 "name"; -#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Default, PartialOrd, Ord)] -#[serde(rename_all = "snake_case")] -pub enum NodeKind { - #[default] - Unknown, - Movie, - Video, - Music, - ShortFormVideo, - Collection, - Channel, - Show, - Series, - Season, - Episode, -} + LANG_NATIVE: &str = 0xa001 "native"; + LANG_ENG: &str = 0xa002 "eng"; + LANG_DEU: &str = 0xa003 "deu"; + LANG_JPN: &str = 0xa003 "jpn"; -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "snake_case")] -pub enum TrackSource { - Local(PathBuf, u64), - Remote(usize), -} + PICT_COVER: &str = 0xd001 "cover"; + PICT_BACKDROP: &str = 0xd001 "backdrop"; -pub type TrackID = usize; + RTYP_IMDB: f64 = 0xf001 "imdb"; + RTYP_TMDB: f64 = 0xf002 "tmdb"; + RTYP_ROTTEN_TOMATOES: f64 = 0xf003 "rotten_tomatoes"; + RTYP_METACRITIC: f64 = 0xf004 "metacritic"; + RTYP_YOUTUBE_VIEWS: f64 = 0xf005 "youtube_views"; + RTYP_YOUTUBE_LIKES: f64 = 0xf006 "youtube_likes"; + RTYP_YOUTUBE_FOLLOWERS: f64 = 0xf007 "youtube_followers"; + RTYP_TRAKT: f64 = 0xf008 "trakt"; -#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq)] -pub struct LocalTrack { - pub path: PathBuf, - pub track: TrackID, -} + IDENT_MUSICBRAINZ_RECORDING: &str = 0xc001 "musicbrainz_recording"; + IDENT_MUSICBRAINZ_ARTIST: &str = 0xc002 "musicbrainz_artist"; + IDENT_MUSICBRAINZ_RELEASE: &str = 0xc003 "musicbrainz_release"; + IDENT_MUSICBRAINZ_RELEASE_GROUP: &str = 0xc004 "musicbrainz_release_group"; + IDENT_ACOUST_ID_TRACK: &str = 0xc005 "acoust_id_track"; + IDENT_YOUTUBE_VIDEO: &str = 0xc006 "youtube_video"; + IDENT_YOUTUBE_CHANNEL: &str = 0xc007 "youtube_channel"; + IDENT_YOUTUBE_CHANNEL_HANDLE: &str = 0xc008 "youtube_channel_handle"; + IDENT_BANDCAMP: &str = 0xc009 "bandcamp"; + IDENT_ISRC: &str = 0xc00a "isrc"; + IDENT_BARCODE: &str = 0xc00b "barcode"; + IDENT_TRAKT_MOVIE: &str = 0xc00c "trakt_movie"; + IDENT_TRAKT_SHOW: &str = 0xc00d "trakt_show"; + IDENT_TRAKT_SEASON: &str = 0xc00e "trakt_season"; + IDENT_TRAKT_EPISODE: &str = 0xc00f "trakt_episode"; + IDENT_IMDB: &str = 0xc010 "imdb"; + IDENT_TMDB_SERIES: &str = 0xc011 "tmdb_series"; + IDENT_TMDB_MOVIE: &str = 0xc012 "tmdb_movie"; + IDENT_TVDB: &str = 0xc013 "tvdb"; + IDENT_OMDB: &str = 0xc014 "omdb"; + IDENT_VGMDB_ARTIST: &str = 0xc015 "vgmdb_artist"; -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct MediaInfo { - pub duration: f64, // in seconds - pub tracks: Vec<SourceTrack>, - #[serde(default)] - pub chapters: Vec<Chapter>, } -#[derive(Debug, Clone, Deserialize, Serialize, Default)] -pub struct Chapter { - pub time_start: Option<f64>, - pub time_end: Option<f64>, - pub labels: Vec<(String, String)>, -} +enums! { + VISI_HIDDEN = 0xe001 "hidden"; + VISI_REDUCED = 0xe002 "reduced"; + VISI_VISIBLE = 0xe003 "visible"; -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct SourceTrack { - pub source: TrackSource, - pub kind: SourceTrackKind, - pub name: String, - pub codec: String, - pub language: String, - #[serde(default)] - pub federated: Vec<String>, -} + TRKIND_VIDEO = 0x1001 "video"; + TRKIND_AUDIO = 0x1001 "audio"; + TRKIND_TEXT = 0x1001 "text"; -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[serde(rename_all = "snake_case")] -pub enum RatingType { - Imdb, - Tmdb, - RottenTomatoes, - Metacritic, - YoutubeViews, - YoutubeLikes, - YoutubeFollowers, - Trakt, -} + KIND_MOVIE = 0xb001 "movie"; + KIND_VIDEO = 0xb002 "video"; + KIND_MUSIC = 0xb003 "music"; + KIND_SHORTFORMVIDEO = 0xb004 "shortformvideo"; + KIND_COLLECTION = 0xb005 "collection"; + KIND_CHANNEL = 0xb006 "channel"; + KIND_SHOW = 0xb007 "show"; + KIND_SERIES = 0xb008 "series"; + KIND_SEASON = 0xb009 "season"; + KIND_EPISODE = 0xb00a "episode"; -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -#[serde(rename_all = "snake_case")] -pub enum SourceTrackKind { - Video { - width: u64, - height: u64, - fps: Option<f64>, - }, - Audio { - channels: usize, - sample_rate: f64, - bit_depth: Option<usize>, - }, - Subtitle, + CRCAT_CAST = 0x2001 "cast"; + CRCAT_WRITING = 0x2002 "writing"; + CRCAT_DIRECTING = 0x2003 "directing"; + CRCAT_ART = 0x2004 "art"; + CRCAT_SOUND = 0x2005 "sound"; + CRCAT_CAMERA = 0x2006 "camera"; + CRCAT_LIGHTING = 0x2007 "lighting"; + CRCAT_CREW = 0x2008 "crew"; + CRCAT_EDITING = 0x2009 "editing"; + CRCAT_PRODUCTION = 0x200a "production"; + CRCAT_VFX = 0x200b "vfx"; + CRCAT_COSTUME_MAKEUP = 0x200c "costume_makeup"; + CRCAT_CREATED_BY = 0x200d "created_by"; + CRCAT_PERFORMANCE = 0x200e "performance"; + CRCAT_INSTRUMENT = 0x200f "instrument"; + CRCAT_VOCAL = 0x2010 "vocal"; + CRCAT_ARRANGER = 0x2011 "arranger"; + CRCAT_PRODUCER = 0x2012 "producer"; + CRCAT_ENGINEER = 0x2013 "engineer"; } diff --git a/common/src/routes.rs b/common/src/routes.rs index 1605624..b11a622 100644 --- a/common/src/routes.rs +++ b/common/src/routes.rs @@ -3,12 +3,12 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2026 metamuffin <metamuffin.org> */ -use crate::{CreditCategory, NodeID, PictureSlot, api::NodeFilterSort, user::ApiWatchedState}; +use crate::api::NodeFilterSort; pub fn u_home() -> String { "/home".to_owned() } -pub fn u_node_id(node: NodeID) -> String { +pub fn u_node_id(node: &str) -> String { format!("/n/{node}") } pub fn u_node_slug(node: &str) -> String { @@ -20,18 +20,13 @@ pub fn u_node_slug_player(node: &str) -> String { pub fn u_node_slug_player_time(node: &str, time: f64) -> String { format!("/n/{node}/player?t={time}") } -pub fn u_node_image(node: &str, slot: PictureSlot, size: usize) -> String { +pub fn u_node_image(node: &str, slot: &str, size: usize) -> String { format!("/n/{node}/image/{slot}?size={size}") } pub fn u_node_slug_watched(node: &str, state: ApiWatchedState) -> String { format!("/n/{node}/watched?state={state}") } -pub fn u_node_slug_person_asset( - node: &str, - group: CreditCategory, - index: usize, - size: usize, -) -> String { +pub fn u_node_slug_person_asset(node: &str, group: &str, index: usize, size: usize) -> String { format!("/n/{node}/person/{index}/asset?group={group}&size={size}") } pub fn u_node_slug_thumbnail(node: &str, time: f64, size: usize) -> String { diff --git a/common/src/user.rs b/common/src/user.rs index 9b90ec9..8302751 100644 --- a/common/src/user.rs +++ b/common/src/user.rs @@ -9,8 +9,6 @@ use std::{ fmt::Display, }; -use crate::url_enum; - #[rustfmt::skip] #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct User { |