Skip to content

Commit

Permalink
Merge pull request #11 from hanichris/testing
Browse files Browse the repository at this point in the history
Testing
  • Loading branch information
Chalo1996 authored Apr 28, 2023
2 parents 0abdfa9 + 9c4c1b4 commit c35fa15
Show file tree
Hide file tree
Showing 34 changed files with 565 additions and 167 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ commands
node_modules
*-lock.json
tsconfig.tsbuildinfo
STATE.md
SECRETS
3 changes: 2 additions & 1 deletion backend/example.env
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ NODE_ENV=development
JWT_SECRET=my_ultra_secure_secret
TOKEN_EXPIRES_IN=60
FRONTEND_ENDPOINT=http://localhost:3000
DEFAULT_THUMBNAIL=http://localhost:8000/api/v1/thumbnails/default.png
DEFAULT_AVATAR=http://localhost:8000/api/v1/thumbnails/avatar.png
DEFAULT_THUMBNAIL=http://localhost:8000/api/v1/thumbnails/video.png

S3_REGION=
AWS_ACCESS_KEY_ID=
Expand Down
1 change: 0 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@
"multer": "^1.4.5-lts.1",
"qs": "^6.11.0",
"redis": "^4.6.5",
"sha1": "^1.1.1",
"uuid": "^9.0.0",
"zod": "^3.20.2"
}
Expand Down
Binary file added backend/public/avatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added backend/public/video.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion backend/src/controllers/AppController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import Comment from "../models/comment.model"

export default class AppController {
static getStatus(req: Request, resp: Response, next: NextFunction) {
resp.status(200).json({ redis: redisClient.isAlive(), db: dbClient.isAlive() });
resp.status(200).json(
{
redis: redisClient.isAlive(),
db: dbClient.isAlive()
});
}

static async getStats(req: Request, resp: Response, next: NextFunction) {
Expand Down
23 changes: 19 additions & 4 deletions backend/src/controllers/AuthController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import jwt from "jsonwebtoken";
import User from "../models/user.model"
import bcrypt from "bcryptjs";
import createError from "../error";
import { ChannelModel as Channel } from "../models/channel.model";
import { randomUUID } from "crypto";

function exclude<User, Key extends keyof User>(
user: User,
Expand All @@ -20,7 +22,7 @@ function exclude<User, Key extends keyof User>(
return user;
}

const DEFAULT_THUMBNAIL = process.env.DEFAULT_THUMBNAIL as unknown as string;
const DEFAULT_AVATAR = process.env.DEFAULT_AVATAR as unknown as string;

class AuthController {
static async registerHandler(
Expand All @@ -34,10 +36,23 @@ class AuthController {
const user = new User({
...req.body,
"password": hash,
"avatar": DEFAULT_THUMBNAIL,
"avatar": DEFAULT_AVATAR,
});
await user.save();
// await ChannelController.createChannel(req, resp, next)

// create default channel
const channel = new Channel({
"name": randomUUID(),
"userId": user._id,
"imgUrl": user.avatar,
});
if (!channel) {
return next(createError(404, "Default User Channel could not be created!"));
}
await channel.save()
user.channels.push(channel)
await user.save()

const TOKEN_EXPIRES_IN = process.env.TOKEN_EXPIRES_IN as unknown as number;
const TOKEN_SECRET = process.env.JWT_SECRET as unknown as string;
const token = jwt.sign({ sub: user.id }, TOKEN_SECRET);
Expand Down Expand Up @@ -190,7 +205,7 @@ class AuthController {
createdAt: new Date(),
username: email,
email,
avatar: picture || DEFAULT_THUMBNAIL,
avatar: picture || DEFAULT_AVATAR,
password: "",
verified: true,
fromGoogle: true,
Expand Down
6 changes: 4 additions & 2 deletions backend/src/controllers/ChannelController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import User from "../models/user.model";
import Video from "../models/video.model";
import { ChannelModel as Channel } from "../models/channel.model";
import createError from '../error';
import { randomUUID } from "crypto";

const DEFAULT_AVATAR = process.env.DEFAULT_AVATAR as unknown as string;
const DEFAULT_THUMBNAIL = process.env.DEFAULT_THUMBNAIL as unknown as string;

class ChannelController {
Expand All @@ -15,9 +17,9 @@ class ChannelController {
}
try {
const channel = new Channel({
"name": req.body.channelName || user.username,
"name": req.body.channelName || randomUUID(),
"userId": userId,
"imgUrl": req.body.imgUrl || DEFAULT_THUMBNAIL,
"imgUrl": req.body.imgUrl || user.avatar,
...req.body
});
if (!channel) {
Expand Down
1 change: 1 addition & 0 deletions backend/src/controllers/DownloadController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class DownloadController {
const stream = Readable.from( response.Body as any );

// Send Video to the client
resp.status(200)
resp.set( 'Content-Type', response.ContentType );
resp.set( 'Content-Disposition', `attachment; filename=${ video.filename }` );
stream.pipe( resp );
Expand Down
57 changes: 49 additions & 8 deletions backend/src/controllers/StreamController.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,77 @@
import { NextFunction, Request, Response } from "express";
import createError from "../error";
import { S3 } from "@aws-sdk/client-s3";
import { S3, GetObjectCommand } from "@aws-sdk/client-s3";
import ffmpeg from 'fluent-ffmpeg';
import Video from "../models/video.model";
import User from "../models/user.model";
import { s3Config } from "../utils/aws";
import { config } from 'dotenv';
import { Readable } from 'stream';

config();

const s3: S3 = new S3( s3Config );
// Set the path to the ffmpeg binary
ffmpeg.setFfmpegPath('/usr/bin/ffmpeg');

// linux
// ffmpeg.setFfmpegPath('/usr/bin/ffmpeg');

// Windows
ffmpeg.setFfmpegPath("C:\\ProgramData\\chocolatey\\bin\\ffmpeg.exe");

class StreamingController {
static async getStream(req: Request, resp: Response, next: NextFunction) {
try {
const video = await Video.findById(req.params.id)
const video: any = await Video.findById(req.params.id)
if (!video) {
return next(createError(404, "Video not found!"));
}

// Convert the video file to a streamable format using ffmpeg
const { Body } = await s3.getObject({
const command = new GetObjectCommand({
Bucket: process.env.AWS_BUCKET_NAME,
Key: video.filename,
});
const streamable = ffmpeg(Body as any).format('hls').outputOptions('-hls_time 10');
const response = await s3.send( command);
const stream = Readable.from( response.Body as any );

resp.set('Content-Type', 'video/mp4');
resp.set('Transfer-Encoding', 'chunked');

let totalTime: number;
// Stream the video
resp.set('Content-Type', 'application/vnd.apple.mpegurl');
streamable.pipe(resp);
const proc = ffmpeg(stream)
//set the size
// .withSize('50%')
// set fps
.withFps(24)
.outputOptions(['-movflags isml+frag_keyframe'])
.toFormat('mp4')
.withAudioCodec('copy')
.on('start', commandLine => {
// something message for init process
console.log("Streaming started!")
})
.on('codecData', data => {
// HERE YOU GET THE TOTAL TIME
totalTime = parseInt(data.duration.replace(/:/g, ''))
})
.on('error', function(err: any,stdout:any,stderr:any) {
console.log('an error happened: ' + err.message);
console.log('ffmpeg stdout: ' + stdout);
console.log('ffmpeg stderr: ' + stderr);
})
.on('end', function() {
console.log('Processing finished !');
})
.on('progress', function(progress: any) {
// console.log('Processing: ' + progress.percent + '% done');
const time: number = parseInt(progress.timemark.replace(/:/g, ''))

// AND HERE IS THE CALCULATION
const percent = (time / totalTime) * 100
console.log(`Processing: ${percent >= 0 ? ~~percent : 0}% done`)
})
.pipe(resp, { end: true });
} catch (e) {
console.error(e);
return next(createError(500, "Failed to stream video!"));
Expand Down
13 changes: 12 additions & 1 deletion backend/src/controllers/UserController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,10 @@ class UserController {

static async like(req: Request, resp: Response, next: NextFunction) {
const userId = String(resp.locals.user._id)
console.log(userId)
const videoId = req.params.videoId;
try {
await Video.findByIdAndUpdate(videoId,{
await Video.findByIdAndUpdate(videoId, {
$addToSet:{likes:userId},
$pull:{dislikes:userId}
})
Expand Down Expand Up @@ -168,6 +169,16 @@ class UserController {
}
};

static async getAllUsers(req: Request, resp: Response, next: NextFunction) {
try {
const users = await User.find({ });
if (!users) return next(createError(404, "No Users found!"));
resp.status(200).json(users);
} catch (err) {
next(err);
}
};

}

export default UserController;
11 changes: 6 additions & 5 deletions backend/src/controllers/VideoController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class VideoController {
}

static async addTag(req: Request, resp: Response, next: NextFunction) {
if (!req?.param?.tag) {
if (!req?.body?.tags) {
return resp.status(404).json({ error: 'No tag found' });
}
const userId = String(resp.locals.user._id)
Expand All @@ -65,7 +65,7 @@ class VideoController {
return resp.status(404).json({ error: 'Video not found' });
}
const updatedVideo = await Video.findByIdAndUpdate(req.params.id,{
$addToSet:{tags:req.param.tag}
$addToSet:{tags:req.body.tag}
})
if (!updatedVideo?.isModified) {
return resp.status(404).json({ error: 'Video not found' });
Expand All @@ -74,7 +74,7 @@ class VideoController {
}

static async removeTag(req: Request, resp: Response, next: NextFunction) {
if (!req?.param?.tag) {
if (!req?.body?.tags) {
return resp.status(404).json({ error: 'No tag found' });
}
const userId = String(resp.locals.user._id)
Expand All @@ -87,7 +87,7 @@ class VideoController {
return resp.status(404).json({ error: 'Video not found' });
}
const updatedVideo = await Video.findByIdAndUpdate(req.params.id,{
$pull:{tags:req.param.tag}
$pull:{tags:req.body.tag}
})
if (!updatedVideo?.isModified) {
return resp.status(404).json({ error: 'Video not found' });
Expand Down Expand Up @@ -187,7 +187,8 @@ class VideoController {
};

static async getByTag(req: Request, resp: Response, next: NextFunction) {
const tags = req?.query?.tags?.toString().split(",");
let tags = req?.query?.tags?.toString().split(",");
tags = tags?.map((item: string) => (String(item.charAt(0))).toUpperCase() + item.slice(1))
try {
const videos = await Video.find({ tags: { $in: tags } }).limit(20);
if (!videos) return next(createError(404, "Videos not found!"));
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/auth.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ router.post("/login", validate(loginUserModel), AuthController.loginHandler); //
router.get("/logout", getAuthToken, requireLogin, AuthController.logoutHandler); // GET /auth/logout

// Reset user password route
router.post("/reset-password", validate(resetPasswordModel), AuthController.resetPasswordHandler); // POST /auth/reset-password
router.put("/reset-password", validate(resetPasswordModel), AuthController.resetPasswordHandler); // PUT /auth/reset-password

export default router;
3 changes: 3 additions & 0 deletions backend/src/routes/user.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const router = express.Router();

// router.use(getAuthToken, requireLogin);

// Get all users
router.get("/", getAuthToken, requireLogin, UserController.getAllUsers); // GET /users

// Get my profile route
router.get("/me", getAuthToken, requireLogin, UserController.getMeHandler); // GET /users/me

Expand Down
Loading

0 comments on commit c35fa15

Please sign in to comment.