You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

382 lines
15 KiB

import {getClient} from "../utils/database.js";
import * as path from "node:path";
import * as fs from "node:fs";
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import jwt from "jsonwebtoken";
import {query} from "express-validator";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export async function upload(req, res) {
const fileBuffer = req.file.buffer;
let isGenerate = false;
while (isGenerate === false) {
const client = await getClient();
let letters = "0123456789ABCDEF";
let hex = '';
for (let i = 0; i < 16; i++)
hex += letters[(Math.floor(Math.random() * 16))];
const query = `SELECT * FROM videos WHERE slug = $1`;
const result = await client.query(query, [hex]);
client.end();
if (result.rows.length === 0) {
isGenerate = true;
req.body.slug = hex;
}
}
const finalName = req.body.slug + "." + req.file.originalname.split(".")[1];
const destinationPath = path.join(__dirname, "../uploads/videos/" + finalName)
fs.writeFileSync(destinationPath, fileBuffer);
const client = await getClient();
const video = {
title: req.body.title,
description: req.body.description,
//TODO thumbnail
file: "/api/media/video/" + finalName,
channel: req.body.channel,
slug: req.body.slug,
format: req.file.originalname.split(".")[1],
visibility: req.body.visibility,
}
const logger = req.body.logger;
logger.write("try to upload video");
const releaseDate = new Date(Date.now()).toISOString();
const query = `INSERT INTO videos (title, thumbnail, description, channel, visibility, file, slug, format, release_date) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`;
await client.query(query, [video.title, 'null', video.description, video.channel, video.visibility, video.file, video.slug, video.format, releaseDate]);
logger.write("successfully uploaded video", 200);
res.status(200).json({"message": "Successfully uploaded video"});
}
export async function uploadThumbnail(req, res) {
const fileBuffer = req.file.buffer;
const client = await getClient();
const videoId = req.body.video;
const videoSlugQuery = `SELECT * from videos WHERE id = $1`;
const result = await client.query(videoSlugQuery, [videoId]);
const fileName = result.rows[0].slug + "." + req.file.originalname.split(".")[1];
const destinationPath = path.join(__dirname, "../uploads/thumbnails/", fileName);
fs.writeFileSync(destinationPath, fileBuffer);
const logger = req.body.logger;
logger.action("try to add thumbnail to video " + req.body.video);
const file = "/api/media/thumbnail/" + fileName;
const updateQuery = `UPDATE videos SET thumbnail = $1 WHERE id = $2`;
await client.query(updateQuery, [file, req.body.video]);
logger.write("successfully uploaded thumbnail", 200);
res.status(200).json({"message": "Successfully uploaded thumbnail"});
}
export async function getById(req, res) {
const id = req.params.id;
const logger = req.body.logger;
logger.action("try to get video " + id);
const client = await getClient();
const query = `SELECT * FROM videos WHERE id = $1`;
const result = await client.query(query, [id]);
const video = result.rows[0];
// GET VIEWS AND LIKES COUNT
const viewsQuery = `SELECT COUNT(*) AS view_count FROM history WHERE video = $1`;
const viewsResult = await client.query(viewsQuery, [id]);
const likesQuery = `SELECT COUNT(*) AS like_count FROM likes WHERE video = $1`;
const likesResult = await client.query(likesQuery, [id]);
video.views = viewsResult.rows[0].view_count;
video.likes = likesResult.rows[0].like_count;
// GET COMMENTS
const commentsQuery = `SELECT c.id, c.content, c.created_at, u.username, u.picture FROM comments c JOIN users u ON c.author = u.id WHERE c.video = $1`;
const commentsResult = await client.query(commentsQuery, [id]);
video.comments = commentsResult.rows;
// GET CREATOR
const creatorQuery = `SELECT c.id, c.name, c.owner FROM channels c JOIN videos v ON c.id = v.channel WHERE v.id = $1`;
const creatorResult = await client.query(creatorQuery, [id]);
video.creator = creatorResult.rows[0];
// GET CREATOR PROFILE PICTURE
const profilePictureQuery = `SELECT picture FROM users WHERE id = $1`;
const profilePictureResult = await client.query(profilePictureQuery, [video.creator.owner]);
video.creator.profile_picture = profilePictureResult.rows[0].picture;
// GET CREATOR SUBSCRIBERS COUNT
const subscribersQuery = `SELECT COUNT(*) AS subscriber_count FROM subscriptions WHERE channel = $1`;
const subscribersResult = await client.query(subscribersQuery, [video.creator.id]);
video.creator.subscribers = subscribersResult.rows[0].subscriber_count;
// GET TAGS
const tagsQuery = `SELECT t.name FROM tags t JOIN video_tags vt ON t.id = vt.tag WHERE vt.video = $1`;
const tagsResult = await client.query(tagsQuery, [id]);
video.tags = tagsResult.rows.map(tag => tag.name);
logger.write("successfully get video " + id, 200);
res.status(200).json(video);
}
export async function getByChannel(req, res) {
const id = req.params.id;
const logger = req.body.logger;
logger.action("try to get video from channel " + id);
const client = await getClient();
const query = `SELECT * FROM videos WHERE channel = $1`;
const result = await client.query(query, [id]);
logger.write("successfully get video from channel " + id, 200);
res.status(200).json(result.rows);
}
export async function update(req, res) {
const id = req.params.id;
const logger = req.body.logger;
logger.action("try to update video " + id);
const client = await getClient();
const query = `UPDATE videos SET title = $1, description = $2, visibility = $3 WHERE id = $4`;
await client.query(query, [req.body.title, req.body.description, req.body.visibility, id]);
logger.write("successfully updated video", 200);
res.status(200).json({"message": "Successfully updated video"});
}
export async function updateVideo(req, res) {
const id = req.params.id;
const logger = req.body.logger;
logger.action("try to update video file " + id);
const client = await getClient();
const videoQuery = `SELECT slug, format FROM videos WHERE id = $1`;
const videoResult = await client.query(videoQuery, [id]);
const video = videoResult.rows[0];
const slug = video.slug;
const format = video.format;
const pathToDelete = path.join(__dirname, "../uploads/videos/", slug + "." + format );
fs.unlink(pathToDelete, (error) => {
if (error) {
logger.write(error, 500);
res.status(500).json({"message": "Failed to delete video"});
return
}
logger.action("successfully deleted video " + slug + "." + format );
const fileBuffer = req.file.buffer;
const finalName = slug + "." + format;
const destinationPath = path.join(__dirname, "../uploads/videos/" + finalName)
fs.writeFileSync(destinationPath, fileBuffer);
logger.write("successfully updated video", 200);
res.status(200).json({"message": "Successfully updated video"});
})
}
export async function del(req, res) {
const id = req.params.id;
const logger = req.body.logger;
logger.action("try to delete video " + id);
const client = await getClient();
const query = `SELECT slug, format, thumbnail FROM videos WHERE id = $1`;
const result = await client.query(query, [id]);
const video = result.rows[0];
const slug = video.slug;
const format = video.format;
const thumbnailFile = video.thumbnail.split("/")[4];
let pathToDelete = path.join(__dirname, "../uploads/videos/", slug + "." + format);
fs.unlink(pathToDelete, (error) => {
if (error) {
logger.write(error, 500);
res.status(500).json({"message": "Failed to delete video"});
return
}
pathToDelete = path.join(__dirname, "../uploads/thumbnails/", thumbnailFile);
fs.unlink(pathToDelete, async (error) => {
if (error) {
logger.write(error, 500);
res.status(500).json({"message": "Failed to delete video"});
return
}
const query = `DELETE FROM videos WHERE id = $1`;
await client.query(query, [id]);
logger.write("successfully deleted video", 200);
res.status(200).json({"message": "Successfully deleted video"});
})
})
}
export async function toggleLike(req, res) {
const id = req.params.id;
const logger = req.body.logger;
logger.action("try to toggle like on video " + id);
const token = req.headers.authorization.split(" ")[1];
const claims = jwt.decode(token);
const client = await getClient();
const userId = claims.id;
const getLikeQuery = `SELECT * FROM likes WHERE owner = $1 AND video = $2`;
const likeResult = await client.query(getLikeQuery, [userId, id]);
if (likeResult.rows.length === 0) {
const query = `INSERT INTO likes (video, owner) VALUES ($1, $2)`;
await client.query(query, [id, userId]);
// GET LIKES COUNT
const likesCountQuery = `SELECT COUNT(*) AS like_count FROM likes WHERE video = $1`;
const likesCountResult = await client.query(likesCountQuery, [id]);
const likesCount = likesCountResult.rows[0].like_count;
logger.write("no likes found adding likes for video " + id, 200);
res.status(200).json({"message": "Successfully added like", "likes": likesCount});
} else {
const query = `DELETE FROM likes WHERE owner = $1 AND video = $2`;
await client.query(query, [userId, id]);
// GET LIKES COUNT
const likesCountQuery = `SELECT COUNT(*) AS like_count FROM likes WHERE video = $1`;
const likesCountResult = await client.query(likesCountQuery, [id]);
const likesCount = likesCountResult.rows[0].like_count;
logger.write("likes found, removing like for video " + id, 200);
res.status(200).json({"message": "Successfully removed like", "likes": likesCount});
}
}
export async function addTags(req, res) {
const tags = req.body.tags;
const videoId = req.params.id;
const logger = req.body.logger;
logger.action("try to add tags to video " + videoId);
const client = await getClient();
// DECREASE USAGE COUNT FOR ALL TAGS
const decreaseUsageCountQuery = `UPDATE tags SET usage_count = usage_count - 1 WHERE id IN (SELECT tag FROM video_tags WHERE video = $1)`;
await client.query(decreaseUsageCountQuery, [videoId]);
// DELETE ALL TAGS FOR VIDEO
let deleteQuery = `DELETE FROM video_tags WHERE video = $1`;
await client.query(deleteQuery, [videoId]);
// INSERT NEW TAGS
for (const tag of tags) {
const tagQuery = `SELECT * FROM tags WHERE name = $1`;
const tagResult = await client.query(tagQuery, [tag]);
let id = null;
if (tagResult.rows.length === 0) {
const insertTagQuery = `INSERT INTO tags (name, usage_count) VALUES ($1, 1) RETURNING id`;
const result = await client.query(insertTagQuery, [tag]);
id = result.rows[0].id;
} else {
logger.write("Tag " + tag + " already exists for video " + videoId, 200);
const getTagQuery = `SELECT usage_count FROM tags WHERE name = $1`;
const getTagResult = await client.query(getTagQuery, [tag]);
const usageCount = getTagResult.rows[0].usage_count + 1;
const updateTagQuery = `UPDATE tags SET usage_count = $1 WHERE name = $2`;
await client.query(updateTagQuery, [usageCount, tag]);
id = tagResult.rows[0].id;
}
// INSERT INTO video_tags
const insertVideoTagQuery = `INSERT INTO video_tags (tag, video) VALUES ($1, $2)`;
await client.query(insertVideoTagQuery, [id, videoId]);
}
logger.write("successfully added tags to video " + videoId, 200);
await client.end();
res.status(200).json({"message": "Successfully added tags to video"});
}
export async function getSimilarVideos(req, res) {
const id = req.params.id;
const logger = req.body.logger;
logger.action("try to get similar videos for video " + id);
const client = await getClient();
// Get tags for the video
const tagsQuery = `SELECT t.name FROM tags t JOIN video_tags vt ON t.id = vt.tag WHERE vt.video = $1`;
const tagsResult = await client.query(tagsQuery, [id]);
const tags = tagsResult.rows.map(row => row.name);
if (tags.length === 0) {
logger.write("No tags found for video " + id, 404);
res.status(404).json({"message": "No similar videos found"});
return;
}
// Find similar videos based on tags which are not the same as the current video and limit to 10 results
const similarVideosQuery = `
SELECT v.id, v.title, v.thumbnail, v.file, v.slug, v.format, v.release_date, c.name AS creator_name, c.id AS creator_id, c.owner AS creator_owner
FROM videos v
JOIN video_tags vt ON v.id = vt.video
JOIN tags t ON vt.tag = t.id
JOIN channels c ON v.channel = c.id
WHERE t.name = ANY($1) AND v.id != $2
GROUP BY v.id, c.name, c.id
LIMIT 10;
`;
const result = await client.query(similarVideosQuery, [tags, id]);
for (let video of result.rows) {
// Get views count for each video
const viewsQuery = `SELECT COUNT(*) AS view_count FROM history WHERE video = $1`;
const viewsResult = await client.query(viewsQuery, [video.id]);
video.views = viewsResult.rows[0].view_count;
// Get creator profile picture
const profilePictureQuery = `SELECT picture FROM users WHERE id = $1`;
const profilePictureResult = await client.query(profilePictureQuery, [video.creator_owner]);
// Put creator info in video.creator
video.creator = {
id: video.creator_id,
name: video.creator_name,
profilePicture: profilePictureResult.rows[0].picture
};
// Remove creator_id and creator_name from the video object
delete video.creator_id;
delete video.creator_name;
}
logger.write("successfully retrieved similar videos for video " + id, 200);
res.status(200).json(result.rows);
}
export async function addViews(req, res) {
const id = req.params.id;
const logger = req.body.logger;
logger.action("try to add views for video " + id);
const token = req.headers.authorization.split(" ")[1];
const claims = jwt.decode(token);
const userId = claims.id;
// ADD VIEW TO HISTORY IF NOT EXISTS
const client = await getClient();
const query = `SELECT * FROM history WHERE video = $1 AND user_id = $2`;
const result = await client.query(query, [id, userId]);
if (result.rows.length === 0) {
const insertQuery = `INSERT INTO history (video, user_id) VALUES ($1, $2)`;
await client.query(insertQuery, [id, userId]);
}
logger.write("successfully added views for video " + id, 200);
res.status(200).json({"message": "Successfully added views"});
}