From 57e248bb2dfc72d23f1fdfa5f8482f46912c3c3a Mon Sep 17 00:00:00 2001 From: Theis Pieter Hollebeek Date: Fri, 19 Jan 2024 03:10:56 +0100 Subject: [PATCH 1/7] search/login/register --- index.js | 27 ++++++++++++++++++++-- package-lock.json | 11 ++++++++- package.json | 3 ++- public/index.html | 3 +-- public/login/index.html | 35 +++++++++++++++++++++++++++++ public/login/script.js | 46 ++++++++++++++++++++++++++++++++++++++ public/register/index.html | 35 +++++++++++++++++++++++++++++ public/register/script.js | 46 ++++++++++++++++++++++++++++++++++++++ public/script.js | 3 --- public/search/index.html | 30 +++++++++++++++++++++++++ public/search/script.js | 38 +++++++++++++++++++++++++++++++ public/style.css | 41 +++++++++++++++++++++++++++++++++ 12 files changed, 309 insertions(+), 9 deletions(-) create mode 100644 public/login/index.html create mode 100644 public/login/script.js create mode 100644 public/register/index.html create mode 100644 public/register/script.js delete mode 100644 public/script.js create mode 100644 public/search/index.html create mode 100644 public/search/script.js diff --git a/index.js b/index.js index 498265a..13c247c 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,7 @@ import bcrypt from "bcrypt"; import fileUpload from "express-fileupload"; import path from "path"; import childProcess from "child_process"; +import levenshtein from "js-levenshtein"; const users = []; let sessions = []; @@ -32,12 +33,12 @@ app.post("/api/register", async (req, res) => { return res.status(400).json({ ok: false, error: "bad request" }); } const existingUser = users.find(user => user.username === username); - if (existingUser === undefined) { + if (existingUser !== undefined) { return res.status(400).json({ ok: false, error: "username taken" }); } const passwordHash = await bcrypt.hash(password, 10); const id = users.length; - const user = { id, username, passwordHash }; + const user = { id, username, password: passwordHash }; users.push(user); return res.status(200).json({ ok: true, user }); }); @@ -63,6 +64,28 @@ app.post("/api/login", async (req, res) => { return res.status(200).json({ ok: true, session }); }); + +app.get("/api/search", async (req, res) => { + const page = +req.query.page || 0; + const search = req.query.query; + if (!search) { + return res.status(400).json({ ok: false, error: "bad request" }); + } + const [start, end] = [20 * page, 20 * (page + 1)]; + const returnedVideos = videos + .map(video => ({dist: levenshtein(search, video.title), ...video})) + .toSorted((a, b) => a.dist - b.dist) + .slice(start, end) + .map(video => { + const user = users.find(user => user.id === v.userId); + if (!user) { + return {...video, author: "[Liberal]"}; + } + return {...video, author: user.username}; + }); + return res.status(200).json({ ok: true, videos: returnedVideos, total: videos.length }); +}); + function authorized() { return (req, res, next) => { const token = (() => { diff --git a/package-lock.json b/package-lock.json index 0d304d4..88e4b0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "bcrypt": "^5.1.1", "cors": "^2.8.5", "express": "^4.18.2", - "express-fileupload": "^1.4.3" + "express-fileupload": "^1.4.3", + "js-levenshtein": "^1.1.6" } }, "node_modules/@mapbox/node-pre-gyp": { @@ -668,6 +669,14 @@ "node": ">=8" } }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", diff --git a/package.json b/package.json index 75792e9..e114af8 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "bcrypt": "^5.1.1", "cors": "^2.8.5", "express": "^4.18.2", - "express-fileupload": "^1.4.3" + "express-fileupload": "^1.4.3", + "js-levenshtein": "^1.1.6" } } diff --git a/public/index.html b/public/index.html index 24c799b..438ec15 100644 --- a/public/index.html +++ b/public/index.html @@ -4,11 +4,10 @@ MaoTube -

MaoTube

-
+
diff --git a/public/login/index.html b/public/login/index.html new file mode 100644 index 0000000..a1fd655 --- /dev/null +++ b/public/login/index.html @@ -0,0 +1,35 @@ + + + + + MaoTube + + + +

MaoTube

+
+ + + + +
+
+ +
+
+
+ + +
+ + + + diff --git a/public/login/script.js b/public/login/script.js new file mode 100644 index 0000000..f689adc --- /dev/null +++ b/public/login/script.js @@ -0,0 +1,46 @@ +function error(message) { + const errorContainer = document.getElementById("mao-error"); + const errorElement = document.getElementById("mao-error-message"); + + errorElement.innerText = message; + errorContainer.classList.remove("hidden"); +} + +function displayResponse(response) { + if (!response.ok) { + error(response.error); + return; + } + window.location.href = "/"; +} + +function click() { + const username = document.getElementById("username").value; + const password = document.getElementById("password").value; + + if (username.trim().length === 0) { + error("username cannot be empty"); + return; + } else if (password.trim().length === 0) { + error("password cannot be empty"); + return; + } + const method = "POST"; + const body = JSON.stringify({ username, password }); + const headers = new Headers({ "Content-Type": "application/json" }); + return fetch("/api/login", { + method, + body, + headers, + }) + .then(v => v.json()) + .then(displayResponse); + +} + +function main() { + const submit = document.getElementById("submit"); + submit.addEventListener("click", () => click()) +} + +main(); diff --git a/public/register/index.html b/public/register/index.html new file mode 100644 index 0000000..1a311d5 --- /dev/null +++ b/public/register/index.html @@ -0,0 +1,35 @@ + + + + + MaoTube + + + +

MaoTube

+
+ + + + +
+
+ +
+
+
+ + +
+ + + + diff --git a/public/register/script.js b/public/register/script.js new file mode 100644 index 0000000..ca6b8a1 --- /dev/null +++ b/public/register/script.js @@ -0,0 +1,46 @@ +function error(message) { + const errorContainer = document.getElementById("mao-error"); + const errorElement = document.getElementById("mao-error-message"); + + errorElement.innerText = message; + errorContainer.classList.remove("hidden"); +} + +function displayResponse(response) { + if (!response.ok) { + error(response.error); + return; + } + window.location.href = "/login"; +} + +function click() { + const username = document.getElementById("username").value; + const password = document.getElementById("password").value; + + if (username.trim().length === 0) { + error("username cannot be empty"); + return; + } else if (password.trim().length === 0) { + error("password cannot be empty"); + return; + } + const method = "POST"; + const body = JSON.stringify({ username, password }); + const headers = new Headers({ "Content-Type": "application/json" }); + return fetch("/api/register", { + method, + body, + headers, + }) + .then(v => v.json()) + .then(displayResponse); + +} + +function main() { + const submit = document.getElementById("submit"); + submit.addEventListener("click", () => click()) +} + +main(); diff --git a/public/script.js b/public/script.js deleted file mode 100644 index b28b04f..0000000 --- a/public/script.js +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/public/search/index.html b/public/search/index.html new file mode 100644 index 0000000..a8b63e4 --- /dev/null +++ b/public/search/index.html @@ -0,0 +1,30 @@ + + + + + MaoTube + + + +

MaoTube

+
+ + +
+
+
+ + +
+ + + + diff --git a/public/search/script.js b/public/search/script.js new file mode 100644 index 0000000..e154ab0 --- /dev/null +++ b/public/search/script.js @@ -0,0 +1,38 @@ + +function error(message) { + const errorContainer = document.getElementById("mao-error"); + const errorElement = document.getElementById("mao-error-message"); + + errorElement.innerText = message; + errorContainer.classList.remove("hidden"); +} + +function displayResponse(response) { + if (!response.ok) { + error(response.error); + return; + } + const { videos, total } = response; + if (videos.length === 0) { + error("search returned no results"); + return; + } + const resultElement = document.getElementById("result"); + resultElement.innerHTML = `

Showing ${videos.length}/${total} results.

` + + ""; +} + +function main() { + const params = new URLSearchParams(window.location.search); + return fetch(`/api/search?${params.toString()}`) + .then(v => v.json()) + .then(displayResponse); +} + +main(); diff --git a/public/style.css b/public/style.css index 4751a62..a4d0111 100644 --- a/public/style.css +++ b/public/style.css @@ -12,3 +12,44 @@ body { padding: 2rem; text-align: center; } + +.mao-error { + display: flex; + flex-direction: column; + background: url("/chairman_1.jpg"); + background-size: auto 600px; + background-repeat: no-repeat; + background-position: center center; + height: 600px; +} + +.hidden { + display: none; +} + +.mao-error p { + color: #fff; + text-transform: uppercase; + font-weight: bold; + font-family: "Impact", "Bebas", "League Gothic", "Oswald", "Coluna", "Ubuntu Condensed", system-ui, sans-serif; + text-shadow: + 3px 3px 0 black, + -3px -3px 0 black, + 3px -3px 0 black, + -3px 3px 0 black, + + -3px 0px 0 black, + 3px 0px 0 black, + 0px 3px 0 black, + 0px -3px 0 black; + font-size: 2em; +} + +.mao-error p:last-child { + margin-top: auto; +} + +ul#video-list { + padding: 0; + list-style: none; +} From 9257928d379b9dd88b5629af82187b108cd3a3e5 Mon Sep 17 00:00:00 2001 From: Theis Pieter Hollebeek Date: Fri, 19 Jan 2024 03:44:55 +0100 Subject: [PATCH 2/7] file upload --- .gitignore | 3 ++- index.js | 38 ++++++++++++++++++++++++-------------- package-lock.json | 21 +++++++++++++++++++++ package.json | 1 + public/index.html | 5 +++++ public/upload/index.html | 21 +++++++++++++++++++++ videos/.gitkeep | 0 7 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 public/upload/index.html create mode 100644 videos/.gitkeep diff --git a/.gitignore b/.gitignore index f9a75c5..3190fb6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ videos/* - +!videos/.gitkeep +tmp/ diff --git a/index.js b/index.js index 13c247c..9ef1b2d 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,8 @@ import fileUpload from "express-fileupload"; import path from "path"; import childProcess from "child_process"; import levenshtein from "js-levenshtein"; +import cookieParser from "cookie-parser"; +import { fileURLToPath } from 'url'; const users = []; let sessions = []; @@ -14,14 +16,19 @@ function randomString(length) { const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"; let result = ""; for (let i = 0; i < length; ++i) { - result += chars[chars.length * Math.random()]; + result += chars[Math.floor(chars.length * Math.random())]; } return result; } +function dirname() { + return path.dirname(fileURLToPath(import.meta.url)); +} + const app = express(); app.use(cors()); app.use(express.json()); +app.use(cookieParser()); app.use(express.urlencoded({ extended: true })); app.use("/", express.static("public/")); @@ -77,7 +84,7 @@ app.get("/api/search", async (req, res) => { .toSorted((a, b) => a.dist - b.dist) .slice(start, end) .map(video => { - const user = users.find(user => user.id === v.userId); + const user = users.find(user => user.id === video.userId); if (!user) { return {...video, author: "[Liberal]"}; } @@ -89,7 +96,7 @@ app.get("/api/search", async (req, res) => { function authorized() { return (req, res, next) => { const token = (() => { - if ("token" in req.cookies) { + if (req.cookies && "token" in req.cookies) { return req.cookies["token"]; } else if ("token" in req.query) { return req.query["token"]; @@ -100,13 +107,13 @@ function authorized() { } })(); if (token === null) { - return res.status(400).json({ ok: false, error: "unathorized" }); + return res.status(400).json({ ok: false, error: "unauthorized" }); } const session = sessions.find(session => session.token === token); if (session === undefined) { - return res.status(400).json({ ok: false, error: "unathorized" }); + return res.status(400).json({ ok: false, error: "unauthorized" }); } - const user = user.find(user => user.id === session.id); + const user = users.find(user => user.id === session.userId); if (user === undefined) { throw new Error("error: session with invalid userId"); } @@ -122,28 +129,31 @@ app.get("/api/logout", authorized(), (req, res) => { app.post("/api/upload_video", authorized(), fileUpload({ limits: { fileSize: 2 ** 26 }, useTempFiles: true }), async (req, res) => { const { title } = req.body; - if (req.files === undefined || req.files === null || req.files.length !== 1) { + if (!req.files || !req.files.video) { return res.status(400).json({ ok: false, error: "bad request" }); } - if (req.files[0].mimetype !== "video/mp4") { + if (req.files.video.mimetype !== "video/mp4") { return res.status(400).json({ ok: false, error: "bad mimetype" }); } const userId = req.user.id; const id = randomString(4); - const tempPath = req.files[0].tempFilePath; - const newPath = path.join("/videos", id, ".mp4"); + const tempPath = req.files.video.tempFilePath; + const newPath = path.join(dirname(), "videos", `${id}.mp4`); + console.log(newPath); const exitCode = await new Promise((resolve, _reject) => { - const process = childProcess.spawn("HandBrakeCLI", ["-i", tempPath, "-o", newPath, "-Z", "Social 25 MB 5 Minutes 360p60"]); + const process = childProcess.spawn("HandBrakeCLI", ["-i", tempPath, "-o", newPath, "-Z", "Social 50 MB 10 Minutes 480p30"]); process.stderr.on("data", (data) => { - conole.error(data); + console.error(data.toString()); }); process.on("close", (code) => { resolve(code); }) - }); + }) if (exitCode !== 0) { - throw new Error("handbrake failed"); + console.log(":/"); + // throw new Error("handbrake failed"); + return res.status(500).json({ ok: false, error: "server error" }); } const video = { diff --git a/package-lock.json b/package-lock.json index 88e4b0d..0f269a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "bcrypt": "^5.1.1", + "cookie-parser": "^1.4.6", "cors": "^2.8.5", "express": "^4.18.2", "express-fileupload": "^1.4.3", @@ -249,6 +250,26 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "dependencies": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", diff --git a/package.json b/package.json index e114af8..557fd78 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "type": "module", "dependencies": { "bcrypt": "^5.1.1", + "cookie-parser": "^1.4.6", "cors": "^2.8.5", "express": "^4.18.2", "express-fileupload": "^1.4.3", diff --git a/public/index.html b/public/index.html index 438ec15..311d847 100644 --- a/public/index.html +++ b/public/index.html @@ -7,6 +7,11 @@

MaoTube

+ register - + login - + upload +
+
diff --git a/public/upload/index.html b/public/upload/index.html new file mode 100644 index 0000000..36a3c15 --- /dev/null +++ b/public/upload/index.html @@ -0,0 +1,21 @@ + + + + + MaoTube + + + +

MaoTube

+ + + + + +
+
+ +
+ + + diff --git a/videos/.gitkeep b/videos/.gitkeep new file mode 100644 index 0000000..e69de29 From b0a0264949b67f7ec0938c1deb615c151ff14357 Mon Sep 17 00:00:00 2001 From: Theis Pieter Hollebeek Date: Fri, 19 Jan 2024 03:48:01 +0100 Subject: [PATCH 3/7] header --- public/index.html | 18 ++++++++++++------ public/login/index.html | 13 ++++++++++++- public/register/index.html | 13 ++++++++++++- public/search/index.html | 13 ++++++++++++- public/upload/index.html | 13 ++++++++++++- 5 files changed, 60 insertions(+), 10 deletions(-) diff --git a/public/index.html b/public/index.html index 311d847..f01503e 100644 --- a/public/index.html +++ b/public/index.html @@ -6,12 +6,18 @@ -

MaoTube

- register - - login - - upload -
-
+
+

MaoTube

+ +
+
+
diff --git a/public/login/index.html b/public/login/index.html index a1fd655..4e29d13 100644 --- a/public/login/index.html +++ b/public/login/index.html @@ -6,7 +6,18 @@ -

MaoTube

+
+

MaoTube

+ +
+
+
diff --git a/public/register/index.html b/public/register/index.html index 1a311d5..e703637 100644 --- a/public/register/index.html +++ b/public/register/index.html @@ -6,7 +6,18 @@ -

MaoTube

+
+

MaoTube

+ +
+
+
diff --git a/public/search/index.html b/public/search/index.html index a8b63e4..ed21770 100644 --- a/public/search/index.html +++ b/public/search/index.html @@ -6,7 +6,18 @@ -

MaoTube

+
+

MaoTube

+ +
+
+
diff --git a/public/upload/index.html b/public/upload/index.html index 36a3c15..c1f2f7a 100644 --- a/public/upload/index.html +++ b/public/upload/index.html @@ -6,7 +6,18 @@ -

MaoTube

+
+

MaoTube

+ +
+
+
From 7d830830f6af1bcda0847da633ff44209ea35ec0 Mon Sep 17 00:00:00 2001 From: Theis Pieter Hollebeek Date: Fri, 19 Jan 2024 03:59:53 +0100 Subject: [PATCH 4/7] header.js --- public/header.js | 37 +++++++++++++++++++++++++++++++++++++ public/index.html | 17 ++++------------- public/login/index.html | 14 ++------------ public/register/index.html | 14 ++------------ public/search/index.html | 20 ++++++-------------- public/upload/index.html | 14 ++------------ 6 files changed, 53 insertions(+), 63 deletions(-) create mode 100644 public/header.js diff --git a/public/header.js b/public/header.js new file mode 100644 index 0000000..90f7a86 --- /dev/null +++ b/public/header.js @@ -0,0 +1,37 @@ +function displayHeader() { + const links = [ + { + href: "/", + name: "Home", + }, + { + href: "/register/", + name: "Register", + }, + { + href: "/login/", + name: "Login", + }, + { + href: "/upload/", + name: "Upload", + }, + ].map(({name, href}) => { + if (href === window.location.pathname) { + return `${name}` + } else { + return `${name}` + } + }).join(" - "); + + document.querySelector("h1").outerHTML = ` +
+

MaoTube

+ +
+ ` +} + +displayHeader(); diff --git a/public/index.html b/public/index.html index f01503e..02aed75 100644 --- a/public/index.html +++ b/public/index.html @@ -6,26 +6,17 @@ -
-

MaoTube

- -
-
-
+

MaoTube

- + +
The chairman The chairman The chairman + diff --git a/public/login/index.html b/public/login/index.html index 4e29d13..934d7a0 100644 --- a/public/login/index.html +++ b/public/login/index.html @@ -6,18 +6,7 @@ -
-

MaoTube

- -
-
-
+

MaoTube

@@ -41,6 +30,7 @@
+ diff --git a/public/register/index.html b/public/register/index.html index e703637..8b69018 100644 --- a/public/register/index.html +++ b/public/register/index.html @@ -6,18 +6,7 @@ -
-

MaoTube

- -
-
-
+

MaoTube

@@ -41,6 +30,7 @@
+ diff --git a/public/search/index.html b/public/search/index.html index ed21770..a0f1844 100644 --- a/public/search/index.html +++ b/public/search/index.html @@ -6,23 +6,14 @@ -
-

MaoTube

- -
-
-
-
- +

MaoTube

+ + +

+
+ diff --git a/public/upload/index.html b/public/upload/index.html index c1f2f7a..ed868c2 100644 --- a/public/upload/index.html +++ b/public/upload/index.html @@ -6,18 +6,7 @@ -
-

MaoTube

- -
-
-
+

MaoTube

@@ -27,6 +16,7 @@
+ From cd6c8c88b517d8fc425aecb23a71cb46a602460f Mon Sep 17 00:00:00 2001 From: Theis Pieter Hollebeek Date: Fri, 19 Jan 2024 04:04:21 +0100 Subject: [PATCH 5/7] fill in query from params --- public/search/script.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/search/script.js b/public/search/script.js index e154ab0..165e7b6 100644 --- a/public/search/script.js +++ b/public/search/script.js @@ -30,6 +30,8 @@ function displayResponse(response) { function main() { const params = new URLSearchParams(window.location.search); + const searchElement = document.getElementById("query"); + searchElement.value = params.get("query") || ""; return fetch(`/api/search?${params.toString()}`) .then(v => v.json()) .then(displayResponse); From 484b343b83222136f042f215a1c7c80108aeb66e Mon Sep 17 00:00:00 2001 From: Theis Pieter Hollebeek Date: Fri, 19 Jan 2024 04:22:22 +0100 Subject: [PATCH 6/7] video player --- index.js | 11 +++++------ public/search/script.js | 2 +- public/style.css | 4 ++++ public/watch/index.html | 32 ++++++++++++++++++++++++++++++++ public/watch/script.js | 31 +++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 public/watch/index.html create mode 100644 public/watch/script.js diff --git a/index.js b/index.js index 9ef1b2d..1b0d56c 100644 --- a/index.js +++ b/index.js @@ -79,9 +79,10 @@ app.get("/api/search", async (req, res) => { return res.status(400).json({ ok: false, error: "bad request" }); } const [start, end] = [20 * page, 20 * (page + 1)]; - const returnedVideos = videos - .map(video => ({dist: levenshtein(search, video.title), ...video})) - .toSorted((a, b) => a.dist - b.dist) + const withDistance = videos + .map(video => ({dist: levenshtein(search, video.title), ...video})); + withDistance.sort((a, b) => a.dist - b.dist); + const returnedVideos = withDistance .slice(start, end) .map(video => { const user = users.find(user => user.id === video.userId); @@ -151,9 +152,7 @@ app.post("/api/upload_video", authorized(), fileUpload({ limits: { fileSize: 2 * }) }) if (exitCode !== 0) { - console.log(":/"); - // throw new Error("handbrake failed"); - return res.status(500).json({ ok: false, error: "server error" }); + throw new Error("handbrake failed"); } const video = { diff --git a/public/search/script.js b/public/search/script.js index 165e7b6..3051e50 100644 --- a/public/search/script.js +++ b/public/search/script.js @@ -22,7 +22,7 @@ function displayResponse(response) { + "
    " + videos .map(v => { - return `
  • ${v.title} - ${v.author}

  • ` + return `
  • ${v.title} - ${v.author}

  • ` }) .join("") + "
"; diff --git a/public/style.css b/public/style.css index a4d0111..c4e6f7b 100644 --- a/public/style.css +++ b/public/style.css @@ -53,3 +53,7 @@ ul#video-list { padding: 0; list-style: none; } + +#video-player { + max-height: 80vh; +} diff --git a/public/watch/index.html b/public/watch/index.html new file mode 100644 index 0000000..5ef78bb --- /dev/null +++ b/public/watch/index.html @@ -0,0 +1,32 @@ + + + + + MaoTube + + + +

MaoTube

+
+ + + +
+
+
+ + +
+ + + + + diff --git a/public/watch/script.js b/public/watch/script.js new file mode 100644 index 0000000..b9add8a --- /dev/null +++ b/public/watch/script.js @@ -0,0 +1,31 @@ + +function error(message) { + const errorContainer = document.getElementById("mao-error"); + const errorElement = document.getElementById("mao-error-message"); + + errorElement.innerText = message; + errorContainer.classList.remove("hidden"); +} + +function main() { + const params = new URLSearchParams(window.location.search); + const id = params.get("id"); + if (!id) { + error("invalid id parameter"); + return; + } + + const result = document.getElementById("result"); + + const video = document.createElement("video"); + video.controls = true; + video.id = "video-player"; + video.src = `/videos/${id}.mp4`; + result.appendChild(video); + video.onerror = () => { + video.remove(); + error("invalid id parameter"); + } +} + +main(); From 8f9d8c40781b0d698166036bdb33fbf441dda12a Mon Sep 17 00:00:00 2001 From: Theis Pieter Hollebeek Date: Fri, 19 Jan 2024 05:51:00 +0100 Subject: [PATCH 7/7] sans-serif --- public/style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/public/style.css b/public/style.css index c4e6f7b..e43ef4e 100644 --- a/public/style.css +++ b/public/style.css @@ -11,6 +11,7 @@ body { margin: 0 auto; padding: 2rem; text-align: center; + font-family: system-ui, sans-serif; } .mao-error {