watchdogs/src/pages/index.rs
JMARyA fb55d396f8
Some checks failed
ci/woodpecker/push/build Pipeline failed
ogp
2025-02-23 23:39:25 +01:00

227 lines
6.3 KiB
Rust

use based::page;
use based::request::respond_html;
use based::ui::components::prelude::{InfinityScroll, Shell};
use based::ui::components::ColoredSpinner;
use based::ui::prelude::*;
use based::ui::primitives::div::Center;
use based::{
auth::MaybeUser,
request::{
api::{vec_to_api, FallibleApiResponse},
RequestContext, StringResponse,
},
};
use maud::{html, PreEscaped, Render};
use rocket::{get, State};
use serde_json::json;
use crate::config::Config;
use crate::library::Video;
use crate::pages::components::{Title, VerticalVideoGrid, VerticalVideoGridRaw};
use crate::{library::Library, pages::components::video_element};
use super::components::DirectoryBadge;
use super::{
api_response,
components::{render_page, video_element_wide},
};
#[macro_export]
macro_rules! check_private {
($conf:ident, $user:ident, $shell:ident, $ctx:ident) => {
if $conf.general.private && $user.user().is_none() {
return $crate::pages::index::is_private_page($shell, $ctx).await;
}
};
}
#[get("/search?<query>&<offset>")]
pub async fn search(
query: &str,
offset: Option<i64>,
library: &State<Library>,
conf: &State<Config>,
user: MaybeUser,
shell: &State<Shell>,
ctx: RequestContext,
) -> Option<serde_json::Value> {
// todo : check_private!(conf, user, shell, ctx);
const NUM_OF_RESULTS: i64 = 20;
// get start parameter for search result chunks
let start = offset.unwrap_or(0);
let mut video_matches = library.search_video(query, start, NUM_OF_RESULTS).await;
Some(json!(vec_to_api(&mut video_matches).await))
}
#[get("/latest.json")]
pub async fn latest_api(
library: &State<Library>,
user: MaybeUser,
conf: &State<Config>,
shell: &State<Shell>,
ctx: RequestContext,
) -> FallibleApiResponse {
// todo : check_private!(conf, user, shell, ctx);
let videos = library.get_newly_added(24, 0).await;
let vid_api = vec_to_api(&videos).await;
return Ok(serde_json::json!(vid_api));
}
#[allow(non_snake_case)]
pub async fn VideoList(videos: &[Video]) -> PreEscaped<String> {
let video_elements = html! {
@for mut vid in videos {
( video_element_wide(&mut vid).await );
};
};
Padding(video_elements).all(ScreenValue::_6).render()
}
#[get("/latest?<offset>")]
pub async fn latest_page(
ctx: RequestContext,
library: &State<Library>,
user: MaybeUser,
shell: &State<Shell>,
conf: &State<Config>,
offset: Option<u32>,
) -> StringResponse {
check_private!(conf, user, shell, ctx);
let mut videos: Vec<_> = library
.get_newly_added(21, offset.unwrap_or_default() as i64)
.await;
let has_content = !videos.is_empty();
let video_elements = VerticalVideoGrid(&mut videos).await;
if ctx.is_htmx && !ctx.htmx_redirect {
return respond_html(
Div()
.vanish()
.push(video_elements)
.push_if(has_content, || {
Width(
ScreenValue::fit,
Margin(InfinityScroll(
ColoredSpinner(Purple::_600),
&format!("/latest?offset={}", offset.unwrap_or_default() + 21),
))
.x(ScreenValue::auto),
)
})
.render()
.0,
);
}
let content = Div()
.vanish()
.push(Title("Recent videos"))
.push(video_elements)
.push(Width(
ScreenValue::fit,
Margin(InfinityScroll(
ColoredSpinner(Purple::_600),
&format!("/latest?offset={}", offset.unwrap_or_default() + 21),
))
.x(ScreenValue::auto),
))
.render();
render_page(&shell, ctx, content, "Recent videos", user.into()).await
}
#[get("/d/<dir>")]
pub async fn dir_page(
ctx: RequestContext,
dir: &str,
library: &State<Library>,
user: MaybeUser,
shell: &State<Shell>,
conf: &State<Config>,
) -> StringResponse {
check_private!(conf, user, shell, ctx);
if dir.ends_with(".json") {
let dir_videos = library
.get_directory_videos(dir.split_once(".json").map(|x| x.0).unwrap_or_default())
.await;
return api_response(&json!(vec_to_api(&dir_videos).await));
}
let dir_videos = library.get_directory_videos(dir).await;
let video_elements = html! {
@for mut vid in dir_videos {
( video_element_wide(&mut vid).await );
};
};
let content = Div()
.vanish()
.push(Title(dir.to_string()))
.push(Padding(video_elements).all(ScreenValue::_6))
.render();
render_page(&shell, ctx, content, dir, user.into()).await
}
pub async fn is_private_page(shell: &Shell, ctx: RequestContext) -> StringResponse {
page!(
shell,
ctx,
"WatchDogs",
Margin(Center(Text("This is a private instance").bold()._4xl())).top(ScreenValue::_12)
)
}
#[get("/")]
pub async fn index_page(
ctx: RequestContext,
library: &State<Library>,
user: MaybeUser,
shell: &State<Shell>,
conf: &State<Config>,
) -> StringResponse {
check_private!(conf, user, shell, ctx);
let random_video_elements = html! {
@for mut vid in library.get_random_videos(3).await {
( video_element(&mut vid).await );
};
};
let newly_added_elements = html! {
@for mut vid in library.get_newly_added(3, 0).await {
( video_element(&mut vid).await );
};
};
let directories = library.get_directories().await;
let content = Div()
.vanish()
.push(Title("Random Videos"))
.push(VerticalVideoGridRaw(random_video_elements))
.push(Title(Link("/latest", "Latest Videos").use_htmx()))
.push(VerticalVideoGridRaw(newly_added_elements))
.push(Title("Directories:"))
.push(
Padding(
Flex(
Div()
.vanish()
.push_for_each(&directories, |dir: &_| DirectoryBadge(dir)),
)
.wrap(Wrap::Wrap)
.justify(Justify::Evenly),
)
.all(ScreenValue::_10),
)
.render();
render_page(&shell, ctx, content, "WatchDogs", user.into()).await
}