Compare commits

...

2 Commits

Author SHA1 Message Date
1cc2908933
Add description and created fields to videos 2024-02-13 00:08:03 +01:00
3f1648da32
Create upload queue page in frontend 2024-02-13 00:07:28 +01:00
9 changed files with 95 additions and 27 deletions

Binary file not shown.

View File

@ -180,7 +180,10 @@ app.get("/api/logout", authorized(), (req, res) => {
}); });
app.post("/api/upload-video", authorized(), fileUpload({ limits: { fileSize: 2 ** 26 }, useTempFiles: true }), async (req, res) => { app.post("/api/upload-video", authorized(), fileUpload({ limits: { fileSize: 2 ** 26 }, useTempFiles: true }), async (req, res) => {
const { title } = req.body; const { title, description } = req.body;
if (!title) {
return res.status(400).json({ ok: false, error: "bad request" });
}
if (!req.files || !req.files.video) { if (!req.files || !req.files.video) {
return res.status(400).json({ ok: false, error: "bad request" }); return res.status(400).json({ ok: false, error: "bad request" });
@ -206,6 +209,7 @@ app.post("/api/upload-video", authorized(), fileUpload({ limits: { fileSize: 2 *
const queueItem = { const queueItem = {
videoId: id, videoId: id,
userId, userId,
title,
errors: [], errors: [],
progress: 0, progress: 0,
duration, duration,
@ -225,7 +229,10 @@ app.post("/api/upload-video", authorized(), fileUpload({ limits: { fileSize: 2 *
return; return;
} }
dbRun("INSERT INTO videos (id, user_id, title) VALUES (?, ?, ?)", id, userId, title); dbRun(
"INSERT INTO videos (id, user_id, title, description, created_at) VALUES (?, ?, ?, ?, ?)",
id, userId, title, description ?? "", new Date().toISOString()
);
const index = videoQueue.indexOf(item => item.videoId === queueItem.videoId) const index = videoQueue.indexOf(item => item.videoId === queueItem.videoId)
videoQueue.splice(index, 1); videoQueue.splice(index, 1);
@ -246,7 +253,7 @@ app.get("/api/video-info", async (req, res) => {
const id = req.query["id"]; const id = req.query["id"];
const video = await dbGet(` const video = await dbGet(`
SELECT videos.id, videos.title, users.username AS author SELECT videos.id, videos.title, videos.description, videos.created_at, users.username AS author
FROM videos FROM videos
JOIN users ON users.id = videos.user_id JOIN users ON users.id = videos.user_id
WHERE videos.id = ? WHERE videos.id = ?

View File

@ -8,6 +8,8 @@ CREATE TABLE videos (
id TEXT PRIMARY KEY NOT NULL, id TEXT PRIMARY KEY NOT NULL,
user_id INTEGER, user_id INTEGER,
title TEXT NOT NULL, title TEXT NOT NULL,
description TEXT NOT NULL,
created_at TEXT NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id) FOREIGN KEY(user_id) REFERENCES users(id)
); );

View File

@ -36,11 +36,11 @@ async function main() {
<li> <li>
<div class="video-item"> <div class="video-item">
<div class="video-image"> <div class="video-image">
<img class="shadow" src="/videos/${vid.id}.png" alt=""> <img class="shadow" src="/videos/${vid.videoId}.png" alt="">
<img class="non-shadow" src="/videos/${vid.id}.png" alt=""> <img class="non-shadow" src="/videos/${vid.videoId}.png" alt="">
</div> </div>
<span class="video-info"> <span class="video-info">
${vid.title} <b>${vid.title}</b>
<br> <br>
<p>Uploaded ${uploadedTime} of ${totalTime} (${percentage}%)</p> <p>Uploaded ${uploadedTime} of ${totalTime} (${percentage}%)</p>
<progress max="${vid.duration}" value="${vid.progress}">${percentage}%</progress> <progress max="${vid.duration}" value="${vid.progress}">${percentage}%</progress>

View File

@ -1,20 +1,39 @@
*, *::before, *::after {
box-sizing: border-box;
appearance: none;
}
:root { :root {
color-scheme: light dark; color-scheme: light dark;
--red: #c51e0e; --red: #c51e0e;
} }
@media (prefers-color-scheme: dark) {
:root {
--red: #F4511E;
}
}
*, *::before, *::after {
box-sizing: border-box;
appearance: none;
}
*:focus {
outline: 2px solid var(--red);
}
body { body {
margin: 0 auto; margin: 0 auto;
padding: 0; padding: 0;
text-align: center; text-align: center;
} }
a {
color: var(--red);
}
textarea, input {
font-family: sans-serif;
font-size: 0.8em;
}
nav { nav {
margin-bottom: 20px; margin-bottom: 20px;
} }
@ -135,7 +154,3 @@ input::file-selector-button {
font-weight: bold; font-weight: bold;
} }
a {
color: var(--red);
}

View File

@ -4,19 +4,36 @@
<meta charset="utf-8"> <meta charset="utf-8">
<title>MaoTube</title> <title>MaoTube</title>
<link rel="stylesheet" href="/style.css"> <link rel="stylesheet" href="/style.css">
<script defer src="/header.js"></script>
<script defer src="/helpers.js"></script>
<script defer src="script.js"></script>
</head> </head>
<body> <body>
<h1>MaoTube</h1> <h1>MaoTube</h1>
<form action="/api/upload-video" method="POST" enctype="multipart/form-data"> <form id="upload-form" method="POST" action="/api/upload-video" enctype="multipart/form-data">
<label for="username"><p>Title</p></label> <label for="title"><p>Title</p></label>
<input type="text" name="title" autofocus> <input type="text" name="title" id="title" required autofocus>
<label for="password"><p>Video</p></label> <label for="description"><p>Description</p></label>
<input type="file" name="video"> <textarea name="description" id="description"></textarea>
<br> <label for="video"><p>Video</p></label>
<br> <input type="file" name="video" id="video" required>
<br><br>
<input type="submit" id="submit" value="Upload"> <input type="submit" id="submit" value="Upload">
<br><br>
<a href="/queue">View upload queue</a>
</form> </form>
<script src="/header.js"></script>
<noscript>
<div class="mao-error">
<p>javascript not enabled</p>
<p>bottom text</p>
</div>
</noscript>
<div id="mao-error" class="mao-error hidden">
<p id="mao-error-message"></p>
<p>bottom text</p>
</div>
</body> </body>
</html> </html>

22
public/upload/script.js Normal file
View File

@ -0,0 +1,22 @@
document.getElementById("upload-form").addEventListener("submit", event => {
event.preventDefault();
const data = new FormData(event.target);
fetch("/api/upload-video", {
method: "POST",
body: data,
})
.then(response => response.json())
.then(response => {
if (!response.ok) {
error(response.error);
return;
}
location.href = "/queue";
})
.catch(err => {
error("failed to upload video");
});
});

View File

@ -4,6 +4,8 @@
<meta charset="utf-8"> <meta charset="utf-8">
<title>MaoTube</title> <title>MaoTube</title>
<link rel="stylesheet" href="/style.css"> <link rel="stylesheet" href="/style.css">
<script defer src="script.js"></script>
<script defer src="/header.js"></script>
</head> </head>
<body> <body>
<h1>MaoTube</h1> <h1>MaoTube</h1>
@ -12,7 +14,11 @@
<div id="video-result"> <div id="video-result">
<video id="video-player"></video> <video id="video-player"></video>
<h1 id="video-title"></h1> <h1 id="video-title"></h1>
<span id="video-author"></span> <p id="video-author"></p>
<br>
<hr>
<br>
<p id="video-description"></p>
</div> </div>
<noscript> <noscript>
@ -27,8 +33,6 @@
<p>bottom text</p> <p>bottom text</p>
</div> </div>
</div> </div>
<script src="script.js"></script>
<script src="/header.js"></script>
</body> </body>
</html> </html>

View File

@ -41,7 +41,8 @@ async function main() {
} }
document.getElementById("video-title").innerText = video.title; document.getElementById("video-title").innerText = video.title;
document.getElementById("video-author").innerText = "by " + video.author; document.getElementById("video-author").innerText = "by " + video.author + " - published " + new Date(video.created_at).toLocaleDateString();
document.getElementById("video-description").innerText = video.description;
document.getElementById("video-result").style.display = "block"; document.getElementById("video-result").style.display = "block";
} }