aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Cargo.toml5
-rw-r--r--common/object/src/lib.rs23
-rw-r--r--common/src/api.rs13
-rw-r--r--common/src/config.rs61
-rw-r--r--common/src/helpers.rs159
-rw-r--r--common/src/impl.rs116
-rw-r--r--common/src/jhls.rs5
-rw-r--r--common/src/lib.rs356
-rw-r--r--common/src/routes.rs13
-rw-r--r--common/src/user.rs2
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 {