Compare commits
2 Commits
07ba96295d
...
1cc2908933
Author | SHA1 | Date | |
---|---|---|---|
1cc2908933 | |||
3f1648da32 |
BIN
database.sqlite3
BIN
database.sqlite3
Binary file not shown.
13
index.js
13
index.js
@ -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 = ?
|
||||||
|
@ -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)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -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
22
public/upload/script.js
Normal 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");
|
||||||
|
});
|
||||||
|
});
|
@ -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>
|
||||||
|
|
||||||
|
@ -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";
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user