update
Some checks failed
ci/woodpecker/push/build Pipeline failed

This commit is contained in:
JMARyA 2024-12-15 00:31:39 +01:00
parent 09beb0bcc2
commit bb61c16429
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
5 changed files with 108 additions and 60 deletions

View file

@ -74,6 +74,7 @@ async fn launch() -> _ {
routes![ routes![
pages::assets::video_file, pages::assets::video_file,
pages::assets::video_thumbnail, pages::assets::video_thumbnail,
pages::assets::fav_icon,
pages::index::search, pages::index::search,
pages::index::channel_page, pages::index::channel_page,
pages::yt::yt_tags, pages::yt::yt_tags,

View file

@ -1,4 +1,9 @@
use rocket::{fs::NamedFile, get, State}; use rocket::{
fs::NamedFile,
get,
http::{ContentType, Status},
State,
};
use crate::library::Library; use crate::library::Library;
@ -29,3 +34,11 @@ pub async fn video_thumbnail(v: &str, library: &State<Library>) -> Option<NamedF
NamedFile::open(format!("{thumbnail_path}.jpg")).await.ok() NamedFile::open(format!("{thumbnail_path}.jpg")).await.ok()
} }
#[get("/favicon")]
pub async fn fav_icon() -> (Status, (ContentType, &'static [u8])) {
(
Status::Ok,
(ContentType::PNG, include_bytes!("../../src/icon.png")),
)
}

View file

@ -28,6 +28,27 @@ impl<'r> FromRequest<'r> for HTMX {
} }
} }
pub fn htmx_link(
url: &str,
class: &str,
onclick: &str,
content: PreEscaped<String>,
) -> PreEscaped<String> {
html!(
a class=(class) onclick=(onclick) href=(url) hx-get=(url) hx-target="#main_content" hx-push-url="true" hx-swap="innerHTML" {
(content);
};
)
}
pub fn script(script: &str) -> PreEscaped<String> {
html!(
script {
(PreEscaped(script))
};
)
}
pub fn shell(content: PreEscaped<String>, title: &str) -> PreEscaped<String> { pub fn shell(content: PreEscaped<String>, title: &str) -> PreEscaped<String> {
html! { html! {
html { html {
@ -38,11 +59,25 @@ pub fn shell(content: PreEscaped<String>, title: &str) -> PreEscaped<String> {
meta name="viewport" content="width=device-width, initial-scale=1.0"; meta name="viewport" content="width=device-width, initial-scale=1.0";
}; };
body class="bg-black text-white" { body class="bg-black text-white" {
header class="bg-gray-800 text-white shadow-md py-2" {
(script(include_str!("../scripts/header.js")));
div class="flex justify-start px-6" {
(htmx_link("/", "flex items-center space-x-2", "stopAllVideos()", html!(
img src="/favicon" alt="Logo" class="w-10 h-10 rounded-md";
span class="font-semibold text-xl" { "WatchDogs" };
)))
};
};
};
div id="main_content" { div id="main_content" {
(content) (content)
}; };
} };
}
} }
} }
@ -105,74 +140,63 @@ pub fn format_number(num: i32) -> String {
} }
pub async fn video_element_wide(video: &mut Video) -> PreEscaped<String> { pub async fn video_element_wide(video: &mut Video) -> PreEscaped<String> {
html!( htmx_link(
a href=(format!("/watch?v={}", video.id)) class="flex items-center w-full p-4 bg-gray-900 shadow-lg rounded-lg overflow-hidden mb-2 mt-2" { &format!("/watch?v={}", video.id),
div class="flex-shrink-0" { "flex items-center w-full p-4 bg-gray-900 shadow-lg rounded-lg overflow-hidden mb-2 mt-2",
img width="480" src=(format!("/video/thumbnail?v={}", video.id)) alt="Video Thumbnail" class="w-48 h-32 object-cover rounded-md"; "stopAllVideos()",
}; html!(
div class="flex-shrink-0" {
div class="flex flex-col flex-grow ml-4" { img width="480" src=(format!("/video/thumbnail?v={}", video.id)) alt="Video Thumbnail" class="w-48 h-32 object-cover rounded-md";
h3 class="text-lg font-semibold truncate mb-1" {
( video.title )
}; };
@if let Some(meta) = video.youtube_meta().await { div class="flex flex-col flex-grow ml-4" {
div class="text-sm text-gray-400 mb-2" { h3 class="text-lg font-semibold truncate mb-1" {
span class="font-medium" { ( meta.uploader_name ) } ( video.title )
span { " - " }
span { ( format_date(&meta.upload_date) ) }
};
div class="text-sm text-gray-400" {
span { ( format_number(meta.views) ) }
span { " views" }
span { " - " }
span class="ml-2 bg-black text-white text-xs px-2 py-1 rounded-sm opacity-90" {
(( format_seconds_to_hhmmss(video.duration) ))
}; };
};
};
};
};
)
}
pub async fn video_element(video: &mut Video) -> PreEscaped<String> { @if let Some(meta) = video.youtube_meta().await {
html!( div class="text-sm text-gray-400 mb-2" {
a href=(format!("/watch?v={}", video.id)) class="max-w-sm mx-auto p-4 max-h-60 aspect-video" { span class="font-medium" { ( meta.uploader_name ) }
div class="bg-gray-900 shadow-lg rounded-lg overflow-hidden" { span { " - " }
div class="relative" { span { ( format_date(&meta.upload_date) ) }
img width="480" src=(format!("/video/thumbnail?v={}", video.id)) alt="Video Thumbnail" class="w-full h-auto object-cover aspect-video";
span class="absolute bottom-2 right-2 bg-black text-white text-xs px-2 py-1 rounded-sm opacity-90" {
(( format_seconds_to_hhmmss(video.duration) ))
}; };
};
div class="bg-gray-900 shadow-lg rounded-lg overflow-hidden" { div class="text-sm text-gray-400" {
div class="p-4" { span { ( format_number(meta.views) ) }
h3 class="text-lg font-semibold truncate" { span { " views" }
( video.title ) span { " - " }
span class="ml-2 bg-black text-white text-xs px-2 py-1 rounded-sm opacity-90" {
(( format_seconds_to_hhmmss(video.duration) ))
}; };
}; };
}; };
}; };
}; ),
) )
} }
pub fn header(query: &str) -> PreEscaped<String> { pub async fn video_element(video: &mut Video) -> PreEscaped<String> {
html!( htmx_link(
header style="padding: 10px 0; display: flex; justify-content: space-between;" { &format!("/watch?v={}", video.id),
a href="/" style="text-decoration: none; margin-left: 20px;" { "max-w-sm mx-auto p-4 max-h-60 aspect-video",
div style="margin-right: 20px;display:flex;align-items: center" { "stopAllVideos()",
img src="/icon" width="64" style="margin-top: -25px;margin-right: 15px;border-radius: 20%;"; html!(
p style="font-size: 42px;" { "WatchDogs" }; div class="bg-gray-900 shadow-lg rounded-lg overflow-hidden" {
div class="relative" {
img width="480" src=(format!("/video/thumbnail?v={}", video.id)) alt="Video Thumbnail" class="w-full h-auto object-cover aspect-video";
span class="absolute bottom-2 right-2 bg-black text-white text-xs px-2 py-1 rounded-sm opacity-90" {
(( format_seconds_to_hhmmss(video.duration) ))
};
};
div class="bg-gray-900 shadow-lg rounded-lg overflow-hidden" {
div class="p-4" {
h3 class="text-lg font-semibold truncate" {
( video.title )
};
};
};
}; };
}; ),
div style="width: 35px;" {};
div style="flex-grow: 1; text-align: center;" {
(search_bar(query));
};
};
) )
} }

View file

@ -6,7 +6,10 @@ use rocket::{
}; };
use serde_json::json; use serde_json::json;
use crate::{library::Library, pages::components::video_element}; use crate::{
library::Library,
pages::components::{htmx_link, video_element},
};
use super::{ use super::{
api_response, api_response,
@ -69,7 +72,7 @@ pub async fn index_page(htmx: HTMX, library: &State<Library>) -> (Status, (Conte
h1 class="text-center text-4xl font-extrabold leading-tight mt-8" { "Directories:" }; h1 class="text-center text-4xl font-extrabold leading-tight mt-8" { "Directories:" };
div class="flex flex-wrap p-10" { div class="flex flex-wrap p-10" {
@for dir in library.get_directories().await { @for dir in library.get_directories().await {
a class="px-3 py-2 m-2 bg-purple-500 text-white rounded-full cursor-pointer hover:bg-purple-600" href=(format!("/d/{dir}")) { (dir) }; (htmx_link(&format!("/d/{dir}"), "px-3 py-2 m-2 bg-purple-500 text-white rounded-full cursor-pointer hover:bg-purple-600", "", html! { (dir) }));
br; br;
}; };
}; };

7
src/scripts/header.js Normal file
View file

@ -0,0 +1,7 @@
function stopAllVideos() {
const videos = document.querySelectorAll('video');
videos.forEach(video => {
video.pause();
});
}