aboutsummaryrefslogtreecommitdiff
path: root/server/src/routes/ui/node.rs
blob: f216df2e212830aae6ae48a2559d46bfa409ad4a (plain)
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
/*
    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::{
    library::{Directory, Item, Library, Node},
    routes::ui::{
        account::session::Session,
        layout::{DynLayoutPage, LayoutPage},
    },
};
use anyhow::{anyhow, Context};
use log::info;
use rocket::{get, http::ContentType, uri, 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")?
        .clone();
    Ok(LayoutPage {
        title: format!("{}", node.title()),
        content: markup::new! {
            @NodePage { node: node.clone() }
        },
    })
}

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 { a[href=&uri!(r_library_node(&dir.lib_path)).to_string()] { @dir.data.name } }
    }
    DirectoryPage(dir: Arc<Directory>) {
        div.page.dir {
            h1 { @dir.data.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)).to_string()] {
                    img[src=uri!(r_item_assets(&item.lib_path)).to_string()];
                }
                div.hover { a[href=&player_uri(&item.lib_path)] { "▶" } }
            }
            p.title {
                a[href=uri!(r_library_node(&item.lib_path)).to_string()] {
                    @item.info.title
                }
            }
        }
    }
    ItemPage(item: Arc<Item>) {
        // TODO different image here
        img.backdrop[src=uri!(r_item_assets(&item.lib_path)).to_string()];
        div.page.item {
            div.banner {
                img[src=uri!(r_item_assets(&item.lib_path)).to_string()];
            }
            div.title {
                h1 { @item.info.title }
                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")?
        .get_item()?
        .clone();
    let path = node.fs_path.parent().unwrap().join(
        node.info
            .banner
            .clone()
            .ok_or(anyhow!("no banner available"))?,
    );
    info!("loading asset from {path:?}");
    Ok((ContentType::WEBP, File::open(path).await?))
}