diff --git a/api/Cargo.toml b/api/Cargo.toml index 3e899d7..1c528cf 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -6,7 +6,8 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rocket = "0.4" +rocket = "0.5.0-rc.1" +tokio = "1.0" serde = { version = "1.0", features = [ "derive" ] } base64 = "0.13.0" @@ -14,3 +15,7 @@ base64 = "0.13.0" version = "0.4.10" default-features = false features = ["serve", "json"] + +[dependencies.rocket_dyn_templates] +version = "0.1.0-rc.1" +features = ["tera"] \ No newline at end of file diff --git a/api/src/main.rs b/api/src/main.rs index ddcc9d6..2d34581 100644 --- a/api/src/main.rs +++ b/api/src/main.rs @@ -1,17 +1,20 @@ #![feature(decl_macro)] #[macro_use] extern crate rocket; use std::env; +use rocket_dyn_templates::Template; -mod video; +mod page; -fn main() { +#[tokio::main] +async fn main() { // emoji's crash my terminal - env::set_var("ROCKET_CLI_COLORS", "off"); + env::set_var("ROCKET_CLI_COLORS", "false"); /* * Some of the target vars that we look for * CLIP_DIR */ - let _ = rocket::ignite() - .mount("/api", routes![video::list_categories, video::list_videos]) - .launch(); + let _ = rocket::build() + .mount("/", routes![page::home, page::category, page::video, page::files]) + .attach(Template::fairing()) + .launch().await; } diff --git a/api/src/page.rs b/api/src/page.rs new file mode 100644 index 0000000..8987841 --- /dev/null +++ b/api/src/page.rs @@ -0,0 +1,36 @@ +use serde::Serialize; +use rocket_dyn_templates::Template; +use rocket::fs::NamedFile; +use std::path::{Path, PathBuf}; +use std::collections::HashMap; + + +#[get("/")] +pub async fn home() -> Template { + // WARN: this is just to get the templates to behave but we're still + // doing everything the browser for the home page + let mut h: HashMap<&'static str, &'static str> = HashMap::new(); + h.insert("script_src", "/js/index.js"); + h.insert("page", "home"); + + return Template::render("list", &h); +} + +#[get("/category/")] +pub async fn category(cat: String) -> Template { + let mut h: HashMap<&'static str, &'static str> = HashMap::new(); + h.insert("script_src", "/js/category.js"); + h.insert("page", "category"); + + return Template::render("list", &h); +} + +#[get("/clip/")] +pub async fn video(id: String) -> Template { + return Template::render("video", &{}) +} + +#[get("/")] +pub async fn files(file: PathBuf) -> Option { + NamedFile::open(Path::new("static/").join(file)).await.ok() +} diff --git a/api/static/style.css b/api/static/css/style.css similarity index 100% rename from api/static/style.css rename to api/static/css/style.css diff --git a/api/static/favicon.png b/api/static/favicon.png new file mode 100644 index 0000000..56a6400 --- /dev/null +++ b/api/static/favicon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0cfdedb04d45802c1c008c9610bda2df8e3482f195bd254c11ebe07205e2bd5d +size 8560 diff --git a/api/static/js/collection.js b/api/static/js/collection.js new file mode 100644 index 0000000..1b5d4b7 --- /dev/null +++ b/api/static/js/collection.js @@ -0,0 +1,50 @@ +"use strict"; +// This module takes care of pulling down videos for the given category +class Video { + constructor(raw) { + this.title = raw['name']; + this.category = raw['category']; + this.thumbnail_b64 = raw['thumbnail']; + } + title_link() { + let container = document.createElement('h2'); + let link = document.createElement('a'); + link.href = `/video?c=${this.category}&v=${this.title}`; + link.text = this.title; + container.appendChild(link); + return container; + } +} +function get_category() { + // Used to modify the DOM + let params = (new URL(document.location.toString())).searchParams; + return params.get('c'); +} +function base_url() { + const loc = document.location; + return loc.protocol + '//' + loc.host; +} +function fetch_videos() { + const category = get_category(); + if (!category) { + return []; + } + const endpoint = base_url() + `/api/categories?c=${category}`; + let xml = new XMLHttpRequest(); + xml.open('GET', endpoint, false); // sync request + xml.send(null); // no params required + if (xml.getResponseHeader('Content-Type') == 'application/json') { + let raw = JSON.parse(xml.responseText); + for (const vid of raw['videos']) { + console.log(vid); + } + } + return []; +} +function ready(e) { + if (document.readyState != 'complete') { + return e; + } + const video_data = fetch_videos(); +} +document.addEventListener('readystatechange', ready); diff --git a/api/static/js/index.js b/api/static/js/index.js new file mode 100644 index 0000000..b0b96d7 --- /dev/null +++ b/api/static/js/index.js @@ -0,0 +1,57 @@ +"use strict"; +class Category { + constructor(raw) { + this.name = raw['name']; + this.thumbnail_b64 = raw['thumbnail']; + } + title_link() { + let container = document.createElement('h2'); + let link = document.createElement('a'); + link.href = `/collection?c=${this.name}`; + link.text = this.name; + container.appendChild(link); + return container; + } + thumbnail_div() { + let nail = document.createElement('img'); + nail.className = 'pure-img'; + if (!(this.thumbnail_b64 == null || this.thumbnail_b64.length == 0)) { + nail.setAttribute('src', `data:image/jpg;base64,${this.thumbnail_b64}`); + } + else { + nail.setAttribute('src', '/cantfindshit.gif'); + } + return nail; + } + as_div() { + let container = document.createElement('div'); + container.className = 'video-block'; + let title = this.title_link(); + let thumbnail = this.thumbnail_div(); + container.appendChild(title); + container.appendChild(thumbnail); + // Dump gallery onto the main page + document.getElementById('main-container').appendChild(container); + return container; + } +} +function ready_handler(e) { + // Only let this make a get request once we're ready on the page + if (document.readyState != 'complete') { + return e; + } + // All we do here is basically make a get request to /api/categories + const endpoint = 'http://localhost/api/categories'; + let xml = new XMLHttpRequest(); + xml.open('GET', endpoint, false); // sync request + xml.send(null); // nothing required for stuff + if (xml.getResponseHeader('Content-Type') == 'application/json') { + let raw = JSON.parse(xml.responseText); + for (const cat_raw of raw['categories']) { + let cat = new Category(cat_raw); + cat.as_div(); + } + } + return e; +} +document.addEventListener('readystatechange', ready_handler); diff --git a/api/templates/list.html.tera b/api/templates/list.html.tera new file mode 100644 index 0000000..56b1ceb --- /dev/null +++ b/api/templates/list.html.tera @@ -0,0 +1,37 @@ + + + + + + + + Shockrah's Clips + + {% if page == "category" %} + + + + + + + {# Otherwise we defautl to the home tags #} + {% else %} + + + + + + + {% endif %} + + + +
+
+

+ +
+
+ +