Add video title and author to watch page
This commit is contained in:
		
							parent
							
								
									52e07b54dc
								
							
						
					
					
						commit
						8852a6f0c3
					
				
							
								
								
									
										58
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								index.js
									
									
									
									
									
								
							| @ -14,15 +14,19 @@ let sessions = []; | ||||
| const db = new sqlite3.Database("database.sqlite3"); | ||||
| 
 | ||||
| function dbGet(query, ...parameters) { | ||||
| 	return new Promise((resolve, reject) => db.get(query, parameters, (err, data) => err ? reject(err) : resolve(data))); | ||||
|     return new Promise((resolve, reject) => db.get(query, parameters, (err, data) => err ? reject(err) : resolve(data))); | ||||
| } | ||||
| 
 | ||||
| function dbAll(query, ...parameters) { | ||||
| 	return new Promise((resolve, reject) => db.all(query, parameters, (err, data) => err ? reject(err) : resolve(data))); | ||||
|     return new Promise((resolve, reject) => db.all(query, parameters, (err, data) => err ? reject(err) : resolve(data))); | ||||
| } | ||||
| 
 | ||||
| function dbRun(query, ...parameters) { | ||||
| 	return new Promise((resolve, reject) => db.run(query, parameters, (err, data) => err ? reject(err) : resolve(data))); | ||||
|     return new Promise((resolve, reject) => db.run(query, parameters, (err, data) => err ? reject(err) : resolve(data))); | ||||
| } | ||||
| 
 | ||||
| function videoPath(id) { | ||||
|     return `videos/${id}.webm`; | ||||
| } | ||||
| 
 | ||||
| function randomString(length) { | ||||
| @ -54,7 +58,7 @@ app.post("/api/register", async (req, res) => { | ||||
|         return res.status(400).json({ ok: false, error: "bad request" }); | ||||
|     } | ||||
| 
 | ||||
| 	const existingUser = await dbGet("SELECT * FROM users WHERE username = ?", username); | ||||
|     const existingUser = await dbGet("SELECT * FROM users WHERE username = ?", username); | ||||
| 
 | ||||
|     if (existingUser !== undefined) { | ||||
|         return res.status(400).json({ ok: false, error: "username taken" }); | ||||
| @ -62,7 +66,7 @@ app.post("/api/register", async (req, res) => { | ||||
| 
 | ||||
|     const passwordHash = await bcrypt.hash(password, 10); | ||||
| 
 | ||||
| 	await dbGet("INSERT INTO users (username, password) VALUES (?, ?)", username, passwordHash); | ||||
|     await dbGet("INSERT INTO users (username, password) VALUES (?, ?)", username, passwordHash); | ||||
| 
 | ||||
|     return res.status(200).json({ ok: true }); | ||||
| }); | ||||
| @ -107,16 +111,16 @@ app.get("/api/search", async (req, res) => { | ||||
|     } | ||||
| 
 | ||||
|     const [start, end] = [20 * page, 20]; | ||||
| 	const videos = await dbAll(` | ||||
| 		SELECT videos.*, users.username AS author | ||||
| 		FROM videos | ||||
| 		JOIN users ON users.id = videos.user_id | ||||
| 		WHERE title LIKE CONCAT('%', ?, '%') | ||||
| 		LIMIT ? | ||||
| 		OFFSET ? | ||||
| 	`, search, end, start);
 | ||||
|     const videos = await dbAll(` | ||||
|         SELECT videos.*, users.username AS author | ||||
|         FROM videos | ||||
|         JOIN users ON users.id = videos.user_id | ||||
|         WHERE title LIKE CONCAT('%', ?, '%') | ||||
|         LIMIT ? | ||||
|         OFFSET ? | ||||
|     `, search, end, start);
 | ||||
| 
 | ||||
| 	const { total } = await dbGet("SELECT COUNT(*) AS total FROM videos"); | ||||
|     const { total } = await dbGet("SELECT COUNT(*) AS total FROM videos"); | ||||
| 
 | ||||
|     return res.status(200).json({ ok: true, videos, total }); | ||||
| }); | ||||
| @ -155,7 +159,7 @@ app.get("/api/logout", authorized(), (req, res) => { | ||||
|     return res.status(200).json({ ok: true }); | ||||
| }); | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
|     if (!req.files || !req.files.video) { | ||||
| @ -169,7 +173,7 @@ app.post("/api/upload_video", authorized(), fileUpload({ limits: { fileSize: 2 * | ||||
|     const userId = req.user.id; | ||||
|     const id = randomString(4); | ||||
|     const tempPath = req.files.video.tempFilePath; | ||||
|     const newPath = path.join(dirname(), "videos", `${id}.mp4`); | ||||
|     const newPath = path.join(dirname(), videoPath(id)); | ||||
|     const thumbnailPath = path.join(dirname(), "videos", `${id}.png`); | ||||
| 
 | ||||
|     console.log(newPath); | ||||
| @ -197,7 +201,27 @@ app.post("/api/upload_video", authorized(), fileUpload({ limits: { fileSize: 2 * | ||||
|     await dbRun("INSERT INTO videos (id, user_id, title) VALUES (?, ?, ?)", id, userId, title); | ||||
| 
 | ||||
|     return res.status(200).json({ ok: true }); | ||||
| }) | ||||
| }); | ||||
| 
 | ||||
| app.get("/api/video-info", async (req, res) => { | ||||
|     const id = req.query["id"]; | ||||
| 
 | ||||
|     const video = await dbGet(` | ||||
|         SELECT videos.id, videos.title, users.username AS author | ||||
|         FROM videos | ||||
|         JOIN users ON users.id = videos.user_id | ||||
|         WHERE videos.id = ? | ||||
|         LIMIT 1 | ||||
|     `, id);
 | ||||
| 
 | ||||
|     if (!video) { | ||||
|         return res.status(404).json({ ok: false, error: "video not found" }); | ||||
|     } | ||||
| 
 | ||||
|     video.path = path.join("/", videoPath(id)); | ||||
| 
 | ||||
|     return res.status(200).json({ ok: true, video }); | ||||
| }); | ||||
| 
 | ||||
| app.use((err, req, res, next) => { | ||||
|     console.error(err); | ||||
|  | ||||
| @ -35,7 +35,7 @@ function displayHeader() { | ||||
|                 ${links} | ||||
|                 - | ||||
|                 <form id="search-form" method="GET" target="_self" action="/search"> | ||||
|                     <input type="text" id="search" name="query" placeholder="Search"> | ||||
|                     <input type="text" id="search" name="query" placeholder="Search" accesskey="s"> | ||||
|                     <input type="submit" value="Search"> | ||||
|                 </form> | ||||
|             </nav> | ||||
|  | ||||
| @ -72,7 +72,16 @@ input::file-selector-button { | ||||
| } | ||||
| 
 | ||||
| #video-player { | ||||
|     max-height: 80vh; | ||||
|     height: 60vh; | ||||
|     width: 100%; | ||||
|     background-color: black; | ||||
| } | ||||
| 
 | ||||
| #video-result { | ||||
|     width: 106vh; | ||||
|     display: none; | ||||
|     text-align: left; | ||||
|     margin: auto; | ||||
| } | ||||
| 
 | ||||
| .video-item { | ||||
| @ -130,6 +139,3 @@ a { | ||||
|     color: var(--red); | ||||
| } | ||||
| 
 | ||||
| a:visited { | ||||
|     color: #FF5722; | ||||
| } | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|     </head> | ||||
|     <body> | ||||
|         <h1>MaoTube</h1> | ||||
|         <form action="/api/upload_video" method="POST" enctype="multipart/form-data"> | ||||
|         <form action="/api/upload-video" method="POST" enctype="multipart/form-data"> | ||||
|             <label for="username"><p>Title</p></label> | ||||
|             <input type="text" name="title" autofocus> | ||||
|             <label for="password"><p>Video</p></label> | ||||
|  | ||||
| @ -7,19 +7,21 @@ | ||||
|     </head> | ||||
|     <body> | ||||
|         <h1>MaoTube</h1> | ||||
|         <form method="GET" target="_self" action="/search"> | ||||
|             <label for="query"><p>Search</p></label> | ||||
|             <input type="text" id="query" name="query" placeholder="..."> | ||||
|             <input type="submit" value="Search"> | ||||
|         </form> | ||||
|         <br> | ||||
|         <div id="result"> | ||||
|             <div id="video-result"> | ||||
|                 <video id="video-player"></video> | ||||
|                 <h1 id="video-title"></h1> | ||||
|                 <span id="video-author"></span> | ||||
|             </div> | ||||
| 
 | ||||
|             <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> | ||||
|  | ||||
| @ -1,13 +1,14 @@ | ||||
| 
 | ||||
| function error(message) { | ||||
|     const errorContainer = document.getElementById("mao-error"); | ||||
|     const errorElement = document.getElementById("mao-error-message"); | ||||
| 
 | ||||
|     errorElement.innerText = message; | ||||
|     document.getElementById("video-result").style.display = "none"; | ||||
| 
 | ||||
|     errorElement.innerText = message || "unknown error"; | ||||
|     errorContainer.classList.remove("hidden"); | ||||
| } | ||||
| 
 | ||||
| function main() { | ||||
| async function main() { | ||||
|     const params = new URLSearchParams(window.location.search); | ||||
|     const id = params.get("id"); | ||||
|     if (!id) { | ||||
| @ -15,17 +16,35 @@ function main() { | ||||
|         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"); | ||||
|     const info = await fetch(`/api/video-info?id=${id}`); | ||||
|     if (!info.ok) { | ||||
|         error("error fetching video info"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const json = await info.json(); | ||||
|     if (!json.ok) { | ||||
|         error(json.error); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const video = json.video; | ||||
| 
 | ||||
|     const player = document.getElementById("video-player"); | ||||
|     player.controls = true; | ||||
|     player.src = video.path; | ||||
|     player.onerror = () => { | ||||
|         error("unable to play video"); | ||||
|     } | ||||
|     player.onload = () => { | ||||
|         player.style.height = player.clientWidth / 16 * 9 + "px"; | ||||
|     } | ||||
| 
 | ||||
|     document.getElementById("video-title").innerText = video.title; | ||||
|     document.getElementById("video-author").innerText = "by " + video.author; | ||||
| 
 | ||||
|     document.getElementById("video-result").style.display = "block"; | ||||
| } | ||||
| 
 | ||||
| main(); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user