1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
/*
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) 2023 metamuffin <metamuffin.org>
*/
use super::error::MyError;
use super::player::player_uri;
use crate::uri;
use crate::{
library::{Directory, Item, Library, Node},
routes::ui::{
account::session::Session,
layout::{DynLayoutPage, LayoutPage},
},
CONF,
};
use anyhow::Context;
use log::info;
use rocket::{get, http::ContentType, State};
use std::{ops::Deref, path::PathBuf, sync::Arc};
use tokio::fs::File;
#[get("/library/<path..>")]
pub async fn r_library_node(
_sess: Session,
path: PathBuf,
library: &State<Library>,
) -> Result<DynLayoutPage<'_>, MyError> {
let node = library
.nested_path(&path)
.context("retrieving library node")?;
Ok(LayoutPage {
title: node.title().to_string(),
content: markup::new! {
@NodePage { node: node.clone() }
},
..Default::default()
})
}
markup::define! {
NodePage(node: Arc<Node>) {
@match node.deref() {
Node::Directory(dir) => { @DirectoryPage { dir: dir.clone() } }
Node::Item(item) => { @ItemPage { item: item.clone() } }
}
}
DirectoryCard(dir: Arc<Directory>) {
div.card.dir {
div.banner {
a[href=uri!(r_library_node(&dir.lib_path))] {
img[src=uri!(r_item_assets(&dir.lib_path))];
}
div.hover { a[href=uri!(r_library_node(&dir.lib_path))] { "Open" } }
}
p.title {
a[href=uri!(r_library_node(&dir.lib_path))] {
@dir.info.name
}
}
}
// a[href=&uri!(r_library_node(&dir.lib_path))] { @dir.info.name } }
}
DirectoryPage(dir: Arc<Directory>) {
div.page.dir {
h1 { @dir.info.name }
ul.directorylisting {
@for el in &dir.children {
li { @match el.deref().to_owned() {
Node::Directory(dir) => { @DirectoryCard { dir } }
Node::Item(item) => { @ItemCard { item } }
} }
}
}
}
}
ItemCard(item: Arc<Item>) {
div.card.item {
div.banner {
a[href=uri!(r_library_node(&item.lib_path))] {
img[src=uri!(r_item_assets(&item.lib_path))];
}
div.hover { a[href=&player_uri(&item.lib_path)] { "▶" } }
}
p.title {
a[href=uri!(r_library_node(&item.lib_path))] {
@item.info.title
}
}
}
}
ItemPage(item: Arc<Item>) {
// TODO different image here
img.backdrop[src=uri!(r_item_assets(&item.lib_path))];
div.page.item {
div.banner {
img[src=uri!(r_item_assets(&item.lib_path))];
}
div.title {
h1 { @item.info.title }
// TODO release date, duration, ratings
a.play[href=&player_uri(&item.lib_path)] { "Watch now" }
}
div.details {
h3 { @item.info.description_head }
p { @item.info.description }
}
}
}
}
#[get("/item_assets/<path..>")]
pub async fn r_item_assets(
_sess: Session,
path: PathBuf,
library: &State<Library>,
) -> Result<(ContentType, File), MyError> {
let node = library
.nested_path(&path)
.context("retrieving library node")?;
let path = if let Some(p) = node.banner() {
library.root_path.join(p)
} else {
CONF.asset_path.join("fallback.jpeg")
};
info!("loading asset from {path:?}");
Ok((ContentType::WEBP, File::open(path).await?))
}
|