From 6b1c3227fbd19111693017dbf24df867d4eb6725 Mon Sep 17 00:00:00 2001
From: astria
Date: Sun, 31 Aug 2025 12:16:09 +0200
Subject: [PATCH 1/8] Added branch features/loading
---
documentation.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
create mode 100644 documentation.md
diff --git a/documentation.md b/documentation.md
new file mode 100644
index 0000000..3796d59
--- /dev/null
+++ b/documentation.md
@@ -0,0 +1,49 @@
+# 3RESIT Freetube
+
+## Sommaire
+
+1) Introduction au projet
+2) Organisation
+2) Les technologies utilisées
+ 1) Le serveur
+ 2) Le site web
+ 3) La base de données
+3) Le serveur
+ 1) Les dépendances
+ 2) Le fonctionnement
+4) Le site web
+ 1) Les dépendances
+ 2) Le fonctionnement
+5) La base de données
+ 1) Diagramme des tables
+6) Installation
+ 1) Docker Compose
+ 2) Script Shell
+ 3) Manuelle
+
+## Introduction
+
+Pour ce projet il nous a été demandé de recréer une plateforme similaire a Youtube nommée Freetube. Cette application web devait être gratuite et sans publicités. Nous avions la main libre sur le choix de la pile technologique utilisée et sur l'organisation du projet.
+
+## Organisation
+
+J'ai commencé par faire un plan détaillés de toute les routes et vérifications a effectué pour chaque fonctionnalité, puis faire un plan de la base de données. Ceci allait définir toute la structure du projet.
+
+Pour ce qui est du développement, j'ai choisis de procéder fonctionnalité par fonctionnalité en commençant par le serveur et la base de données pour les intégrer ensuite dans le site web. Pour séparer toute ces parties j'ai utilisé **git** en créant plusieurs branches, une par fonctionnalité.
+
+## Les technologies utilisées
+
+### Le serveur
+Le serveur utilise **NodeJS**, j'ai choisis ce langage car il permet d'implementer une **API REST** efficacement grâce a son système d'asynchronisation natif très performant. Etant créer a partir du **Javascript** il est aussi plus simple a comprendre et a écrire. Même si NodeJS n'est pas le plus connu en terme de rapidité d'éxecution ce n'est pas un problème dans notre situation car nous travaillons avec une **API** qui ajoutera un temps de latence supplémentaire.
+
+### Le site web
+Le site web est programmé en **ReactJS** avec **Vite** ce qui donne un **backend** et un **frontend** dans le même langage ce qui permet une maintenance et des mises à jour plus simple. Tout comme NodeJS, ReactJS et créé a partir de Javascript, il bénéficie donc de la même intégration de l'asynchrone natif. Le système de **composant** de ReactJS permet aussi une gestion de mise à jour de l'interface en temps réel plus simple a mettre en place et évite la duplication de code.
+
+### La base données
+La base de données et une base **PostgreSQL**, un système basé sur le langage SQL largement connu. PostgreSQL est une alternative **OpenSource** à **MySQL**. Il possède une très bonne intégration du **JSON** très utilisé comme moyen d'envoyer des données via **requête HTTP** utilisé dans les API REST.
+
+## Le serveur
+
+### Les dépendances
+
+Pour l'API REST j'ai choisis d'utiliser **ExpressJS** couplé avec **express-validator**
\ No newline at end of file
From 3ec09e404bfe94bc57713c26da03bd80818e5740 Mon Sep 17 00:00:00 2001
From: astria
Date: Sun, 31 Aug 2025 12:30:35 +0200
Subject: [PATCH 2/8] Added upload video loading
---
backend/logs/access.log | 59 +++++++++++++++++++++++
frontend/src/modals/LoadingVideoModal.jsx | 17 +++++++
frontend/src/pages/AddVideo.jsx | 14 +++++-
3 files changed, 88 insertions(+), 2 deletions(-)
create mode 100644 frontend/src/modals/LoadingVideoModal.jsx
diff --git a/backend/logs/access.log b/backend/logs/access.log
index 3fcfa30..552e604 100644
--- a/backend/logs/access.log
+++ b/backend/logs/access.log
@@ -11402,3 +11402,62 @@
[2025-08-27 14:02:56.751] [undefined] GET(/:id/history): successfully retrieved history of user 4 with status 200
[2025-08-27 14:02:56.755] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
[2025-08-27 14:02:56.761] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-08-31 10:18:51.355] [undefined] GET(/:id/history): try to retrieve history of user 1
+[2025-08-31 10:18:51.361] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:18:51.367] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:18:51.373] [undefined] GET(/:id/history): successfully retrieved history of user 1 with status 200
+[2025-08-31 10:18:51.384] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-08-31 10:18:55.307] [undefined] GET(/:id): try to get channel with id 1
+[2025-08-31 10:18:55.354] [undefined] GET(/:id/stats): try to get stats
+[2025-08-31 10:18:55.360] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
+[2025-08-31 10:18:55.371] [undefined] GET(/:id/stats): Successfully get stats with status 200
+[2025-08-31 10:19:10.594] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:19:10.599] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:22:07.050] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:22:07.056] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:22:30.580] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:22:30.586] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:22:48.827] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:22:48.834] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:22:56.007] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:22:56.012] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:23:10.939] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:23:10.945] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:23:11.668] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:23:11.673] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:23:47.510] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:23:47.516] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:23:53.769] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:23:53.775] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:25:15.205] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:25:15.210] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:25:35.308] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:25:35.313] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:25:52.991] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:25:52.997] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:26:48.298] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:26:48.304] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:26:55.482] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:26:55.488] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:27:21.463] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:27:21.469] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:28:55.696] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:28:55.701] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:29:12.334] [undefined] POST(/): try to upload video with status undefined
+[2025-08-31 10:29:12.342] [undefined] POST(/): successfully uploaded video with status 200
+[2025-08-31 10:29:12.457] [undefined] POST(/thumbnail): try to add thumbnail to video 4
+[2025-08-31 10:29:12.464] [undefined] POST(/thumbnail): successfully uploaded thumbnail with status 200
+[2025-08-31 10:29:12.492] [undefined] PUT(/:id/tags): try to add tags to video 4
+[2025-08-31 10:29:12.505] [undefined] PUT(/:id/tags): successfully added tags to video 4 with status 200
+[2025-08-31 10:29:45.158] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-08-31 10:29:45.164] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-08-31 10:29:58.657] [undefined] POST(/): try to upload video with status undefined
+[2025-08-31 10:29:58.663] [undefined] POST(/): successfully uploaded video with status 200
+[2025-08-31 10:29:58.774] [undefined] POST(/thumbnail): try to add thumbnail to video 5
+[2025-08-31 10:29:58.780] [undefined] POST(/thumbnail): successfully uploaded thumbnail with status 200
+[2025-08-31 10:29:58.805] [undefined] PUT(/:id/tags): try to add tags to video 5
+[2025-08-31 10:29:58.820] [undefined] PUT(/:id/tags): successfully added tags to video 5 with status 200
+[2025-08-31 10:29:58.856] [undefined] GET(/:id): try to get channel with id 1
+[2025-08-31 10:29:58.869] [undefined] GET(/:id/stats): try to get stats
+[2025-08-31 10:29:58.875] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
+[2025-08-31 10:29:58.885] [undefined] GET(/:id/stats): Successfully get stats with status 200
diff --git a/frontend/src/modals/LoadingVideoModal.jsx b/frontend/src/modals/LoadingVideoModal.jsx
new file mode 100644
index 0000000..3416584
--- /dev/null
+++ b/frontend/src/modals/LoadingVideoModal.jsx
@@ -0,0 +1,17 @@
+
+
+export default function LoadingVideoModal({state, message}) {
+ return state === "loading" && (
+
+
+ {/* Spinner */}
+
+
+
+
+
{message}
+
+
+ );
+
+}
\ No newline at end of file
diff --git a/frontend/src/pages/AddVideo.jsx b/frontend/src/pages/AddVideo.jsx
index 9802935..511d06e 100644
--- a/frontend/src/pages/AddVideo.jsx
+++ b/frontend/src/pages/AddVideo.jsx
@@ -4,13 +4,15 @@ import Tag from "../components/Tag.jsx";
import { getChannel, searchByUsername } from "../services/user.service.js";
import { uploadVideo, uploadThumbnail, uploadTags } from "../services/video.service.js";
import UserCard from "../components/UserCard.jsx";
-
+import LoadingVideoModal from "../modals/LoadingVideoModal.jsx";
+import { useNavigate } from "react-router-dom";
export default function AddVideo() {
const storedUser = localStorage.getItem("user");
const user = storedUser ? JSON.parse(storedUser) : null;
const token = localStorage.getItem("token");
+ const navigation = useNavigate();
const [videoTitle, setVideoTitle] = useState("");
const [videoDescription, setVideoDescription] = useState("");
@@ -23,6 +25,8 @@ export default function AddVideo() {
const [authorizedUsers, setAuthorizedUsers] = useState([]);
const [searchResults, setSearchResults] = useState([]);
const [alerts, setAlerts] = useState([]);
+ const [loadingState, setLoadingState] = useState("none");
+ const [loadingMessage, setLoadingMessage] = useState("");
useEffect(() => {
fetchChannel();
@@ -53,6 +57,8 @@ export default function AddVideo() {
e.preventDefault();
console.log(channel)
+ setLoadingState("loading");
+ setLoadingMessage("Envoie de la vidéo...");
if (!videoTitle || !videoDescription || !videoThumbnail || !videoFile) {
addAlert('error', 'Veuillez remplir tous les champs requis.');
@@ -77,6 +83,8 @@ export default function AddVideo() {
const request = await uploadVideo(formData, token, addAlert);
+ setLoadingMessage("Envoie de la miniature...");
+
// If the video was successfully created, we can now upload the thumbnail
const response = await request.json();
const videoId = response.id;
@@ -86,6 +94,7 @@ export default function AddVideo() {
thumbnailFormData.append("channel", channel.id.toString());
await uploadThumbnail(thumbnailFormData, token, addAlert);
+ setLoadingMessage("Envoie des tags...");
// if the thumbnail was successfully uploaded, we can send the tags
const body = {
tags: videoTags,
@@ -93,6 +102,7 @@ export default function AddVideo() {
};
await uploadTags(body, videoId, token, addAlert);
// If everything is successful, redirect to the video management page
+ navigation("/manage-channel/" + channel.id);
addAlert('success', 'Vidéo ajoutée avec succès !');
@@ -345,7 +355,7 @@ export default function AddVideo() {
-
+
);
From 298d49aecb44fc5e564c43f138696068f7841e3e Mon Sep 17 00:00:00 2001
From: astria
Date: Wed, 3 Sep 2025 19:36:17 +0200
Subject: [PATCH 3/8] Fix See Later artefacts
---
.../app/controllers/playlist.controller.js | 47 ++++++++++---------
backend/logs/access.log | 23 +++++++++
2 files changed, 48 insertions(+), 22 deletions(-)
diff --git a/backend/app/controllers/playlist.controller.js b/backend/app/controllers/playlist.controller.js
index ace7ba7..c85186a 100644
--- a/backend/app/controllers/playlist.controller.js
+++ b/backend/app/controllers/playlist.controller.js
@@ -238,26 +238,29 @@ export async function getSeeLater(req, res) {
const client = await getClient();
const query = `
SELECT
- JSON_AGG(
- json_build_object(
- 'video_id', videos.id,
- 'title', videos.title,
- 'thumbnail', videos.thumbnail,
- 'video_decscription', videos.description,
- 'channel', videos.channel,
- 'visibility', videos.visibility,
- 'file', videos.file,
- 'format', videos.format,
- 'release_date', videos.release_date,
- 'channel_id', channels.id,
- 'owner', channels.owner,
- 'views', COALESCE(video_views.view_count, 0),
- 'creator', json_build_object(
- 'name', channels.name,
- 'profilePicture', users.picture,
- 'description', channels.description
+ COALESCE(
+ JSON_AGG(
+ json_build_object(
+ 'video_id', videos.id,
+ 'title', videos.title,
+ 'thumbnail', videos.thumbnail,
+ 'video_decscription', videos.description,
+ 'channel', videos.channel,
+ 'visibility', videos.visibility,
+ 'file', videos.file,
+ 'format', videos.format,
+ 'release_date', videos.release_date,
+ 'channel_id', channels.id,
+ 'owner', channels.owner,
+ 'views', COALESCE(video_views.view_count, 0),
+ 'creator', json_build_object(
+ 'name', channels.name,
+ 'profilePicture', users.picture,
+ 'description', channels.description
+ )
)
- )
+ ) FILTER (WHERE videos.id IS NOT NULL),
+ '[]'::json
) AS videos
FROM
public.playlists
@@ -285,14 +288,14 @@ export async function getSeeLater(req, res) {
try {
const result = await client.query(query, [userId]);
if (result.rows.length === 0) {
- logger.write("No 'See Later' playlist found for user with id " + userId, 404);
+ logger.write("No 'See Later' playlist found for user with id " + userId, 200);
client.release();
- res.status(404).json({ error: "'See Later' playlist not found" });
+ res.status(200).json([]);
return;
}
logger.write("'See Later' playlist retrieved for user with id " + userId, 200);
client.release();
- res.status(200).json(result.rows[0].videos);
+ res.status(200).json(result.rows[0].videos || []);
} catch (error) {
logger.write("Error retrieving 'See Later' playlist: " + error.message, 500);
client.release();
diff --git a/backend/logs/access.log b/backend/logs/access.log
index 552e604..fd02723 100644
--- a/backend/logs/access.log
+++ b/backend/logs/access.log
@@ -11461,3 +11461,26 @@
[2025-08-31 10:29:58.869] [undefined] GET(/:id/stats): try to get stats
[2025-08-31 10:29:58.875] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-31 10:29:58.885] [undefined] GET(/:id/stats): Successfully get stats with status 200
+[2025-08-31 10:30:58.389] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-03 17:34:12.979] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-03 17:34:15.647] [undefined] GET(/:id): failed due to invalid values with status 400
+[2025-09-03 17:34:15.660] [undefined] GET(/:id/similar): failed due to invalid values with status 400
+[2025-09-03 17:34:15.671] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-03 17:34:15.736] [undefined] GET(/:id/views): failed due to invalid values with status 400
+[2025-09-03 17:34:24.176] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-03 17:34:26.470] [undefined] GET(/:id): failed due to invalid values with status 400
+[2025-09-03 17:34:26.478] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-03 17:34:26.485] [undefined] GET(/:id/similar): failed due to invalid values with status 400
+[2025-09-03 17:34:26.494] [undefined] GET(/:id/views): failed due to invalid values with status 400
+[2025-09-03 17:34:26.941] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-03 17:34:29.468] [undefined] GET(/:id/history): try to retrieve history of user 1
+[2025-09-03 17:34:29.523] [undefined] GET(/:id/history): successfully retrieved history of user 1 with status 200
+[2025-09-03 17:34:29.535] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-09-03 17:34:29.541] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-09-03 17:34:29.550] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-03 17:34:30.404] [undefined] GET(/:id): Playlist retrieved with id 1 with status 200
+[2025-09-03 17:34:31.607] [undefined] DELETE(/:id/video/:videoId): Video deleted from playlist with id 1 with status 200
+[2025-09-03 17:34:31.690] [undefined] GET(/:id): Playlist retrieved with id 1 with status 200
+[2025-09-03 17:34:32.741] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-03 17:34:41.091] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-03 17:35:57.790] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
From 529a590cce2fb2675b99ca23d52d3f46e4452a8d Mon Sep 17 00:00:00 2001
From: astria
Date: Wed, 3 Sep 2025 19:53:05 +0200
Subject: [PATCH 4/8] Fix docker issues
---
backend/Dockerfile | 18 +++-------
backend/logs/access.log | 3 ++
docker-compose.yaml | 33 +++++++----------
frontend/Dockerfile | 14 ++++++--
frontend/default.conf | 68 +++++++++++++++++++++++++++++++++++
frontend/nginx-selfsigned.crt | 23 ++++++++++++
frontend/nginx-selfsigned.key | 28 +++++++++++++++
frontend/package.json | 3 +-
8 files changed, 152 insertions(+), 38 deletions(-)
create mode 100644 frontend/default.conf
create mode 100644 frontend/nginx-selfsigned.crt
create mode 100644 frontend/nginx-selfsigned.key
diff --git a/backend/Dockerfile b/backend/Dockerfile
index 1470f39..ea47ba6 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -1,22 +1,14 @@
-FROM node:20-alpine
-# Set the working directory
+FROM node:22-alpine
+
WORKDIR /app
-# Copy package.json and package-lock.json
+
COPY package*.json ./
-# Install dependencies
RUN npm install --production
-# Copy the rest of the application code
-COPY . .
-# Expose the port the app runs on
-EXPOSE 8000
-# Install netcat for health checks
-RUN apk add --no-cache netcat-openbsd
+COPY . .
-# Install the cli tools
-RUN chmod +x ./freetube.sh
-RUN cp ./freetube.sh /usr/local/bin/freetube
+EXPOSE 8000
# Start the application
CMD ["npm", "start"]
\ No newline at end of file
diff --git a/backend/logs/access.log b/backend/logs/access.log
index fd02723..4264c87 100644
--- a/backend/logs/access.log
+++ b/backend/logs/access.log
@@ -11484,3 +11484,6 @@
[2025-09-03 17:34:32.741] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
[2025-09-03 17:34:41.091] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
[2025-09-03 17:35:57.790] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-03 17:44:19.296] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-03 17:44:20.911] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-03 17:50:33.774] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 9daba49..d75b89e 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -24,7 +24,8 @@ services:
- ./backend/logs:/var/log/freetube
- ./backend:/app
depends_on:
- - db
+ db:
+ condition: service_healthy
db:
image: postgres:latest
@@ -36,34 +37,24 @@ services:
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- db_data:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ start_period: 30s
frontend:
- image: nginx:latest
+ build:
+ context: ./frontend
+ dockerfile: Dockerfile
+ container_name: resit_frontend
ports:
- "80:80"
- "443:443"
- volumes:
- - ./frontend/dist:/usr/share/nginx/html
- - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
- - ./nginx/nginx-selfsigned.crt:/etc/nginx/ssl/nginx-selfsigned.crt
- - ./nginx/nginx-selfsigned.key:/etc/nginx/ssl/nginx-selfsigned.key
depends_on:
- resit_backend
-
- mailpit:
- image: axllent/mailpit:latest
- ports:
- - "8025:8025" # Web UI
- - "1025:1025" # SMTP
- volumes:
- - mailpit-data:/data
- environment:
- # set where to store the database
- MP_DATABASE: /data/mailpit.db
- restart: unless-stopped
volumes:
db_data:
- driver: local
- mailpit-data:
driver: local
\ No newline at end of file
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
index 5b114a4..e0a2a74 100644
--- a/frontend/Dockerfile
+++ b/frontend/Dockerfile
@@ -1,9 +1,17 @@
-FROM node:21-alpine3.20
+# Build stage
+FROM node:22-alpine3.20 as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
-EXPOSE 5173
-CMD ["npm", "run", "dev"]
+RUN npm run build
+# Production stage
+FROM nginx:alpine
+RUN mkdir -p /etc/nginx/ssl
+COPY --from=build-stage /app/dist /usr/share/nginx/html
+COPY default.conf /etc/nginx/conf.d/default.conf
+COPY nginx-selfsigned.crt nginx-selfsigned.key /etc/nginx/ssl/
+EXPOSE 80 443
+CMD ["nginx", "-g", "daemon off;"]
diff --git a/frontend/default.conf b/frontend/default.conf
new file mode 100644
index 0000000..314181e
--- /dev/null
+++ b/frontend/default.conf
@@ -0,0 +1,68 @@
+server {
+ server_name localhost;
+ listen 80;
+
+ return 301 https://$host$request_uri;
+}
+
+server {
+ server_name localhost;
+ listen 443 ssl;
+
+ root /usr/share/nginx/html;
+ index index.html index.htm;
+
+ # Allow large file uploads for videos (up to 500MB)
+ client_max_body_size 500M;
+
+ ssl_certificate /etc/nginx/ssl/nginx-selfsigned.crt;
+ ssl_certificate_key /etc/nginx/ssl/nginx-selfsigned.key;
+
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ # API routes - proxy to backend (MUST come before static file rules)
+ location /api/ {
+ # Handle preflight OPTIONS requests
+ if ($request_method = 'OPTIONS') {
+ add_header 'Access-Control-Allow-Origin' '$http_origin' always;
+ add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
+ add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always;
+ add_header 'Access-Control-Allow-Credentials' 'true' always;
+ add_header 'Access-Control-Max-Age' 1728000 always;
+ add_header 'Content-Type' 'text/plain; charset=utf-8' always;
+ add_header 'Content-Length' 0 always;
+ return 204;
+ }
+
+ proxy_pass http://resit_backend:8000;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header Origin $http_origin;
+ proxy_buffering off;
+
+ # CORS headers for actual requests
+ add_header 'Access-Control-Allow-Origin' '$http_origin' always;
+ add_header 'Access-Control-Allow-Credentials' 'true' always;
+
+ # Also set timeout for large uploads
+ proxy_read_timeout 300s;
+ proxy_send_timeout 300s;
+ }
+
+ # Static assets - NO CACHING for development
+ location ~* ^/(?!api/).*\.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
+ add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
+ add_header Pragma "no-cache";
+ add_header Expires "0";
+ try_files $uri =404;
+ }
+
+ # Handle React Router - all other routes should serve index.html
+ location / {
+ add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
+ try_files $uri $uri/ /index.html;
+ }
+}
\ No newline at end of file
diff --git a/frontend/nginx-selfsigned.crt b/frontend/nginx-selfsigned.crt
new file mode 100644
index 0000000..29fac8a
--- /dev/null
+++ b/frontend/nginx-selfsigned.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID5zCCAs+gAwIBAgIUXzNzqa/12lyIcoxXf+v371J3fWkwDQYJKoZIhvcNAQEL
+BQAwgYIxCzAJBgNVBAYTAkZSMREwDwYDVQQIDAhOb3JtYW5keTENMAsGA1UEBwwE
+Q2FlbjERMA8GA1UECgwIRnJhbWluZm8xFTATBgNVBAMMDFNhY2hhIEdVRVJJTjEn
+MCUGCSqGSIb3DQEJARYYc2FjaGEuZ3VlcmluQHN1cGluZm8uY29tMB4XDTI1MDcy
+MTEzMzgwMVoXDTI2MDcyMTEzMzgwMVowgYIxCzAJBgNVBAYTAkZSMREwDwYDVQQI
+DAhOb3JtYW5keTENMAsGA1UEBwwEQ2FlbjERMA8GA1UECgwIRnJhbWluZm8xFTAT
+BgNVBAMMDFNhY2hhIEdVRVJJTjEnMCUGCSqGSIb3DQEJARYYc2FjaGEuZ3Vlcmlu
+QHN1cGluZm8uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvLg7
+nR0UqRZ7UadhI8jrUjRMV1SZj+ljxEnV6tDOVMsvafsym1MhDZHb+cyv8769yqPv
+CKtIOQKhMH0PkSqau8szNlF1Tg/1UzT+Mkd4zvLvGE5+aW/oDMg7E2LMJZuCyO4X
+9SzWDVA5+b1QFIw6vvb3mCkUOtVDkOFreBBwryZKcWJ0b8o1hT60oB2wr18P14j0
+0C2/TmHMtim0o4r3gKGvpatqt1fXJo0UlYOwTvfMrYhu2VHqsQ2qP7ocazXEWt5u
+Alf1vNPkAenF0ZV/2UiaL41Q8GMoV1enDP7k7/qfgXvta/hOeYnLtmv5Qpi4XiWz
+xKjSukTUD2sRtSX+YQIDAQABo1MwUTAdBgNVHQ4EFgQUVj9KtmjLFy4xWzkNI9Kq
+NAxNsfUwHwYDVR0jBBgwFoAUVj9KtmjLFy4xWzkNI9KqNAxNsfUwDwYDVR0TAQH/
+BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAGpUPMoF/ASIqOOfX5anDtaPvnslj
+DuEVbU7Uoyc4EuSD343DPV7iMUKoFvVLPxJJqMLhSo3aEGJyqOF6q3fvq/vX2VE7
+9MhwS1t2DBGb5foWRosnT1EuqFU1/S0RJ/Y+GNcoY1PrUES4+r7zqqJJjwKOzneV
+ktUVCdKl0C1gtw6W4Ajxse3fm9DNLxnZZXbyNqn+KbI8QdO0xSEl+gyiycvPu/NT
++EesdlFoYjO7gdA8dXkmu+Z7R61MYhE9Zvyop5KVMqgU8/Ym04UUWjWQYWWLMyuu
+bxngE4XNEI5fhg+0e/I25xJJ9wVV/ZNAF4+XOylHz/CmU8V/SPKuGXBGHg==
+-----END CERTIFICATE-----
diff --git a/frontend/nginx-selfsigned.key b/frontend/nginx-selfsigned.key
new file mode 100644
index 0000000..0ac5345
--- /dev/null
+++ b/frontend/nginx-selfsigned.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC8uDudHRSpFntR
+p2EjyOtSNExXVJmP6WPESdXq0M5Uyy9p+zKbUyENkdv5zK/zvr3Ko+8Iq0g5AqEw
+fQ+RKpq7yzM2UXVOD/VTNP4yR3jO8u8YTn5pb+gMyDsTYswlm4LI7hf1LNYNUDn5
+vVAUjDq+9veYKRQ61UOQ4Wt4EHCvJkpxYnRvyjWFPrSgHbCvXw/XiPTQLb9OYcy2
+KbSjiveAoa+lq2q3V9cmjRSVg7BO98ytiG7ZUeqxDao/uhxrNcRa3m4CV/W80+QB
+6cXRlX/ZSJovjVDwYyhXV6cM/uTv+p+Be+1r+E55icu2a/lCmLheJbPEqNK6RNQP
+axG1Jf5hAgMBAAECggEAAj+hmDRx6jafAAf67sqi3ZgEGEmBkXNeeLGBTPc/qhxd
+ip6krTELnz8TE26RG5LYXzslasUNrn42nIImvBT5ZkcjcosKpWfEqQEAjc1PQovC
+9eyKnKfw4TpUvvmiveT4T98vCYEOOqHE0/WTdlOoaBY/f+sZKQYu+1NMtAjFcg2r
+vVqwsZb5vGyh7CKmIHZnz3UP8P+7G5digiNRne18pGnE2oTnSoQ3/QIqUWBs69DS
+k5ew+CSyTLiUFFnMnE4adwyg6wAud5fBlzowF6UF2agToX7pxEaGxGvpBGG034kk
+1UXaB/d5YwcsBeH+x5cNMLKZy4zqjoxEEW31Q466NQKBgQDtKk1R/slpTpRqvtBT
+NC7InvjcCBXkXttylQHJRN9glqhmflEOe8iMW1/qRwBPlQgK1wq/sXySanVv2+gO
+JGq8XNRLbHyG3YRyshdnJHP1HoWQE0uedD/rfqgkNaW5S1IvHrD7Q7tOvCrF+KbS
+612pmIgNVzn+inafDXPhMZc4pQKBgQDLtQGAu2eK58ewndyL8+7+VHZSTEtKpt+h
+G/U/ccv+6NGqdxI5YUkrJ7k6vV81VeRMvmN9uUS/i8znORFQmm6noRVkhXytwW5B
+HXq2co4WRvv9b/XqcqS0GSYVPJ1u4YNH6lvtDZ4UWPyBzYl700GdHrGa+erT44yL
+tnibHx9GDQKBgFW1J+Qt85O+9hvtgVPQU+fkq4K42VCCh0PNXavi2+cICyufEqPt
+T/iJPQxpRE9+SD3CoPvNpHs1ReN60U3rEzenRIFNX2NNwoPAoHyBy/YVZac/keBd
+mov8Zb9QM+fWtIiaytLDE3nMvph017T5ogucN+66SxcV6vBn6CzFwySRAoGAcUf2
+Tv1ohkGAtgIDrLx5cmvL5NZSpHAKOpDOoHqLA/W66v4OX2RviRUtF7JJ6OIb9GWH
+9Fl8Fr0KtKbyrw1CbevRdrYY8JN52bIoFJ+9zjupVHXXnookd5boq7SqpAe6ttpo
+RnplJ1GZEiIXy4lemp6AC/vhD/YhqWxOw4zaGl0CgYBslhqVt5F0EHf94p7NrCuY
+hNHKHaNaULYP0VXKefQamt/ssDuktqb6DNSIvx2rbbB5+33nTlLTya67gimY1lKt
+WeNB33/yBkCjfSP/J5UDD9mE/oPLt3vAOkOUgMCfp2IpC2Wez1QGqLHS260zpotP
+VpgalHuSWtn8D4nO2pk1hg==
+-----END PRIVATE KEY-----
diff --git a/frontend/package.json b/frontend/package.json
index adc5c94..2af0127 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -5,7 +5,8 @@
"type": "module",
"scripts": {
"dev": "vite --host",
- "build": "vite build --watch",
+ "build": "vite build",
+ "build:watch": "vite build --watch",
"lint": "eslint .",
"preview": "vite preview"
},
From 8cbc6f0e4339ea93e274cde083e9657e359b7ea6 Mon Sep 17 00:00:00 2001
From: astria
Date: Thu, 4 Sep 2025 23:26:39 +0200
Subject: [PATCH 5/8] Added fullscreen mode
---
backend/logs/access.log | 267 ++++++++++++++++++++
developpement.yaml | 51 ++--
docker-compose.yaml | 2 +
frontend/Docker.Development | 7 +
frontend/src/assets/svg/exit_fullscreen.svg | 1 +
frontend/src/assets/svg/fullscreen.svg | 1 +
frontend/src/pages/Video.jsx | 75 +++++-
7 files changed, 378 insertions(+), 26 deletions(-)
create mode 100644 frontend/Docker.Development
create mode 100644 frontend/src/assets/svg/exit_fullscreen.svg
create mode 100644 frontend/src/assets/svg/fullscreen.svg
diff --git a/backend/logs/access.log b/backend/logs/access.log
index 4264c87..647a6f5 100644
--- a/backend/logs/access.log
+++ b/backend/logs/access.log
@@ -11487,3 +11487,270 @@
[2025-09-03 17:44:19.296] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
[2025-09-03 17:44:20.911] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
[2025-09-03 17:50:33.774] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-03 20:04:12.031] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-03 20:04:13.537] [undefined] GET(/:id/history): try to retrieve history of user 1
+[2025-09-03 20:04:13.544] [undefined] GET(/:id/history): failed to retrieve history of user 1 because it doesn't exist with status 404
+[2025-09-03 20:04:13.556] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-09-03 20:04:13.561] [undefined] GET(/:id/channel): failed to retrieve channel of user 1 because it doesn't exist with status 404
+[2025-09-03 20:04:13.566] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-03 20:04:18.757] [undefined] POST(/): try to create new channel with owner 1 and name c2lamerde
+[2025-09-03 20:04:18.762] [undefined] POST(/): Successfully created new channel with name c2lamerde with status 200
+[2025-09-03 20:04:18.857] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-09-03 20:04:18.862] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-09-03 20:04:20.055] [undefined] GET(/:id): try to get channel with id 1
+[2025-09-03 20:04:20.060] [undefined] GET(/:id/stats): try to get stats
+[2025-09-03 20:04:20.065] [undefined] GET(/:id/stats): Successfully get stats with status 200
+[2025-09-03 20:04:20.070] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
+[2025-09-03 20:04:20.845] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-09-03 20:04:20.849] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-09-03 20:04:33.523] [undefined] POST(/): try to upload video with status undefined
+[2025-09-03 20:04:33.528] [undefined] POST(/): successfully uploaded video with status 200
+[2025-09-03 20:04:33.621] [undefined] POST(/thumbnail): try to add thumbnail to video 1
+[2025-09-03 20:04:33.627] [undefined] POST(/thumbnail): successfully uploaded thumbnail with status 200
+[2025-09-03 20:04:33.638] [undefined] PUT(/:id/tags): try to add tags to video 1
+[2025-09-03 20:04:33.646] [undefined] PUT(/:id/tags): successfully added tags to video 1 with status 200
+[2025-09-03 20:04:33.671] [undefined] GET(/:id): try to get channel with id 1
+[2025-09-03 20:04:33.675] [undefined] GET(/:id/stats): try to get stats
+[2025-09-03 20:04:33.679] [undefined] GET(/:id/stats): Successfully get stats with status 200
+[2025-09-03 20:04:33.685] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
+[2025-09-03 20:04:35.555] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-03 20:04:36.856] [undefined] GET(/:id): try to get video 1
+[2025-09-03 20:04:36.860] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-03 20:04:36.867] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-03 20:04:36.877] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-03 20:04:36.882] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-03 20:04:36.893] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-03 20:04:36.900] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:32:34.492] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-04 20:32:36.797] [undefined] GET(/:id/channel): try to retrieve channel of user 1
+[2025-09-04 20:32:36.803] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
+[2025-09-04 20:32:36.815] [undefined] GET(/:id/history): try to retrieve history of user 1
+[2025-09-04 20:32:36.822] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:32:36.826] [undefined] GET(/:id/history): successfully retrieved history of user 1 with status 200
+[2025-09-04 20:32:47.165] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-04 20:34:30.396] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-04 20:34:31.179] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-04 20:35:34.522] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-04 20:36:03.193] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-04 20:37:37.442] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-04 20:37:42.936] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-04 20:42:20.620] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-04 20:42:31.482] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-04 20:43:51.613] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
+[2025-09-04 20:44:03.089] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:44:03.095] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:44:03.102] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:44:03.112] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:44:03.119] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:44:03.131] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:44:03.136] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:44:42.468] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:44:42.523] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:44:42.534] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:44:42.544] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:44:42.553] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:44:42.569] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:44:42.573] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:45:08.656] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:45:08.660] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:45:08.667] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:45:08.677] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:45:08.682] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:45:08.711] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:45:08.718] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:45:27.395] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:45:27.403] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:45:27.413] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:45:27.418] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:45:27.424] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:45:27.455] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:45:27.465] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:45:40.775] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:45:40.780] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:45:40.787] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:45:40.799] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:45:40.805] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:45:40.887] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:45:40.894] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:48:09.425] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:48:09.433] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:48:09.442] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:48:09.454] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:48:09.461] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:48:09.487] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:48:09.495] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:48:14.450] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:48:14.455] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:48:14.461] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:48:14.479] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:48:14.485] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:48:14.516] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:48:14.524] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:48:23.210] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:48:23.215] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:48:23.221] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:48:23.232] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:48:23.237] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:48:23.268] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:48:23.277] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:48:28.466] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:48:28.471] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:48:28.478] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:48:28.491] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:48:28.498] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:48:28.562] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:48:28.567] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:48:55.091] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:48:55.099] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:48:55.109] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:48:55.116] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:48:55.122] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:48:55.142] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:48:55.150] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:49:01.822] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:49:01.827] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:49:01.834] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:49:01.844] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:49:01.850] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:49:01.906] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:49:01.912] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:49:37.215] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:49:37.223] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:49:37.230] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:49:37.241] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:49:37.248] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:49:37.271] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:49:37.277] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:50:00.804] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:50:00.808] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:50:00.815] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:50:00.826] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:50:00.832] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:50:00.888] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:50:00.894] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:50:16.435] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:50:16.445] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:50:16.451] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:50:16.462] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:50:16.468] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:50:16.539] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:50:16.545] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:51:09.495] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:51:09.502] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:51:09.509] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:51:09.519] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:51:09.526] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:51:09.581] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:51:09.588] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:51:20.516] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:51:20.520] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:51:20.527] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:51:20.539] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:51:20.545] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:51:20.597] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:51:20.604] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:51:38.559] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:51:38.563] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:51:38.570] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:51:38.583] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:51:38.589] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:51:38.660] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:51:38.666] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:51:59.262] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:51:59.269] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:51:59.278] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:51:59.284] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:51:59.290] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:51:59.312] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:51:59.320] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:52:08.947] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:52:08.951] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:52:08.957] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:52:08.968] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:52:08.974] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:52:09.029] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:52:09.033] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:53:15.575] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:53:15.583] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:53:15.590] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:53:15.596] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:53:15.602] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:53:15.694] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:53:15.699] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:53:40.778] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:53:40.782] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:53:40.789] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:53:40.799] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:53:40.805] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:53:40.859] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:53:40.866] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:53:53.650] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:53:53.658] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:53:53.666] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:53:53.675] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:53:53.681] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:53:53.748] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:53:53.754] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:57:38.645] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:57:38.652] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:57:38.659] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:57:38.666] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:57:38.673] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:57:38.707] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:57:38.716] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:57:47.609] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:57:47.614] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:57:47.621] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:57:47.635] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:57:47.641] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:57:47.693] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:57:47.699] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:57:54.157] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:57:54.162] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:57:54.168] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:57:54.181] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:57:54.187] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:57:54.260] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:57:54.266] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:58:40.327] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:58:40.335] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:58:40.342] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:58:40.353] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:58:40.359] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:58:40.380] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:58:40.389] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:59:06.564] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:59:06.568] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:59:06.574] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:59:06.583] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:59:06.588] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:59:06.609] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:59:06.618] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 20:59:50.463] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 20:59:50.474] [undefined] GET(/:id): try to get video 1
+[2025-09-04 20:59:50.481] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 20:59:50.495] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 20:59:50.501] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 20:59:50.530] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 20:59:50.537] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 21:01:19.527] [undefined] GET(/:id): try to get video 1
+[2025-09-04 21:01:19.535] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 21:01:19.541] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 21:01:19.547] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 21:01:19.554] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 21:01:19.571] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 21:01:19.579] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 21:01:28.790] [undefined] GET(/:id): try to get video 1
+[2025-09-04 21:01:28.846] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 21:01:28.853] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 21:01:28.882] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 21:01:28.888] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 21:01:28.935] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 21:01:28.941] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-04 21:01:30.079] [undefined] GET(/:id): try to get video 1
+[2025-09-04 21:01:30.084] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
+[2025-09-04 21:01:30.091] [undefined] GET(/:id): successfully get video 1 with status 200
+[2025-09-04 21:01:30.110] [undefined] GET(/:id/similar): try to get similar videos for video 1
+[2025-09-04 21:01:30.115] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
+[2025-09-04 21:01:30.138] [undefined] GET(/:id/views): try to add views for video 1
+[2025-09-04 21:01:30.145] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
diff --git a/developpement.yaml b/developpement.yaml
index 5b12e0b..dd7c7b5 100644
--- a/developpement.yaml
+++ b/developpement.yaml
@@ -1,32 +1,34 @@
services:
- backend:
+ resit_backend:
build:
context: ./backend
dockerfile: Dockerfile
network: host
container_name: resit_backend
ports:
- - "${BACKEND_PORT}:${BACKEND_PORT}"
+ - "8000:8000"
environment:
- DB_USER: ${POSTGRES_USER}
- DB_NAME: ${POSTGRES_DB}
- DB_HOST: ${POSTGRES_HOST}
- DB_PASSWORD: ${POSTGRES_PASSWORD}
+ POSTGRES_USER: ${POSTGRES_USER}
+ POSTGRES_DB: ${POSTGRES_DB}
+ POSTGRES_HOST: db
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
JWT_SECRET: ${JWT_SECRET}
LOG_FILE: ${LOG_FILE}
PORT: ${BACKEND_PORT}
+ GMAIL_USER: ${GMAIL_USER}
+ GMAIL_PASSWORD: ${GMAIL_PASSWORD}
+ GITHUB_ID: ${GITHUB_ID}
+ GITHUB_SECRET: ${GITHUB_SECRET}
volumes:
- ./backend/logs:/var/log/freetube
- - ./backend/app/uploads:/app/app/uploads
- - ./backend/app/utils/wait-for-it.sh:/wait-for-it.sh
+ - ./backend:/app
depends_on:
- - db
- command: ["/wait-for-it.sh", "${POSTGRES_HOST}:5432", "--", "npm", "start"]
+ db:
+ condition: service_healthy
db:
image: postgres:latest
- container_name: resit_db
ports:
- "5432:5432"
environment:
@@ -35,20 +37,29 @@ services:
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- db_data:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ start_period: 30s
frontend:
- build:
- context: ./frontend
- dockerfile: Dockerfile
- network: host
+ image: nginx:alpine
+ container_name: resit_frontend
ports:
- - "5173:5173"
+ - "80:80"
+ - "443:443"
volumes:
- - ./frontend/:/app
- - /app/node_modules
+ - ./frontend/dist:/usr/share/nginx/html
+ - ./frontend/nginx-selfsigned.crt:/etc/nginx/ssl/nginx-selfsigned.crt
+ - ./frontend/nginx-selfsigned.key:/etc/nginx/ssl/nginx-selfsigned.key
+ - ./frontend/default.conf:/etc/nginx/conf.d/default.conf
+ environment:
+ - VITE_API_BASE_URL=https://localhost/api
depends_on:
- - backend
+ - resit_backend
volumes:
db_data:
- driver: local
+ driver: local
\ No newline at end of file
diff --git a/docker-compose.yaml b/docker-compose.yaml
index d75b89e..d0246dd 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -52,6 +52,8 @@ services:
ports:
- "80:80"
- "443:443"
+ environment:
+ - VITE_API_BASE_URL=https://localhost/api
depends_on:
- resit_backend
diff --git a/frontend/Docker.Development b/frontend/Docker.Development
new file mode 100644
index 0000000..2bc8951
--- /dev/null
+++ b/frontend/Docker.Development
@@ -0,0 +1,7 @@
+# Build stage
+FROM node:22-alpine3.20 as build-stage
+
+WORKDIR /app
+COPY package*.json ./
+RUN npm install
+COPY . .
diff --git a/frontend/src/assets/svg/exit_fullscreen.svg b/frontend/src/assets/svg/exit_fullscreen.svg
new file mode 100644
index 0000000..d6f4973
--- /dev/null
+++ b/frontend/src/assets/svg/exit_fullscreen.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/svg/fullscreen.svg b/frontend/src/assets/svg/fullscreen.svg
new file mode 100644
index 0000000..a316690
--- /dev/null
+++ b/frontend/src/assets/svg/fullscreen.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/pages/Video.jsx b/frontend/src/pages/Video.jsx
index 780d617..462295a 100644
--- a/frontend/src/pages/Video.jsx
+++ b/frontend/src/pages/Video.jsx
@@ -18,6 +18,7 @@ export default function Video() {
const { user, isAuthenticated } = useAuth();
const videoRef = useRef(null);
const controllerRef = useRef(null);
+ const hideControlsTimeoutRef = useRef(null);
const navigation = useNavigate();
const [searchParams] = useSearchParams();
const playlistId = searchParams.get("playlistId");
@@ -35,6 +36,7 @@ export default function Video() {
const [playlists, setPlaylists] = useState([]);
const [isAddToPlaylistOpen, setIsAddToPlaylistOpen] = useState(false);
const [currentPlaylist, setCurrentPlaylist] = useState(null);
+ const [isFullscreen, setIsFullscreen] = useState(false);
const [isCommentVisible, setIsCommentVisible] = useState(window.innerWidth >= 1024); // Show comments by default on large screens
const fetchVideo = useCallback(async () => {
@@ -127,6 +129,19 @@ export default function Video() {
fetchNextVideo();
}, [currentPlaylist]);
+ // Handle fullscreen state changes
+ useEffect(() => {
+ if (!isFullscreen) {
+ // Clear timeout when exiting fullscreen
+ if (hideControlsTimeoutRef.current) {
+ clearTimeout(hideControlsTimeoutRef.current);
+ hideControlsTimeoutRef.current = null;
+ }
+ // Reset controls visibility for normal mode
+ setShowControls(false);
+ }
+ }, [isFullscreen]);
+
const handlePlayPause = () => {
if (videoRef.current) {
if (videoRef.current.paused) {
@@ -199,11 +214,31 @@ export default function Video() {
}
const handleMouseEnter = () => {
- setShowControls(true);
+ if (!isFullscreen) {
+ setShowControls(true);
+ }
};
const handleMouseLeave = () => {
- setShowControls(false);
+ if (!isFullscreen) {
+ setShowControls(false);
+ }
+ };
+
+ const handleMouseMove = () => {
+ if (isFullscreen) {
+ setShowControls(true);
+
+ // Clear existing timeout
+ if (hideControlsTimeoutRef.current) {
+ clearTimeout(hideControlsTimeoutRef.current);
+ }
+
+ // Hide controls after 3 seconds of no mouse movement
+ hideControlsTimeoutRef.current = setTimeout(() => {
+ setShowControls(false);
+ }, 3000);
+ }
};
const handleSubscribe = async () => {
@@ -318,6 +353,7 @@ export default function Video() {
className="relative w-full aspect-video mx-auto rounded-lg overflow-hidden"
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
+ onMouseMove={handleMouseMove}
>
@@ -492,7 +492,7 @@ export async function getSimilarVideos(req, res) {
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
+ WHERE t.name = ANY($1) AND v.id != $2 AND v.visibility = 'public'
GROUP BY v.id, c.name, c.id
LIMIT 10;
`;
diff --git a/backend/logs/access.log b/backend/logs/access.log
index 647a6f5..c5bf8cf 100644
--- a/backend/logs/access.log
+++ b/backend/logs/access.log
@@ -11754,3 +11754,248 @@
[2025-09-04 21:01:30.115] [undefined] GET(/:id/similar): successfully get similar videos for video 1 with status 200
[2025-09-04 21:01:30.138] [undefined] GET(/:id/views): try to add views for video 1
[2025-09-04 21:01:30.145] [undefined] GET(/:id/views): successfully added views for video 1 with status 200
+[2025-09-05 09:09:15.576] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:09:24.015] [undefined] GET(/:id): try to get video 8
+[2025-09-05 09:09:24.019] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:09:24.030] [undefined] GET(/:id): successfully get video 8 with status 200
+[2025-09-05 09:09:24.040] [undefined] GET(/:id/similar): try to get similar videos for video 8
+[2025-09-05 09:09:24.045] [undefined] GET(/:id/similar): successfully get similar videos for video 8 with status 200
+[2025-09-05 09:09:24.066] [undefined] GET(/:id/views): try to add views for video 8
+[2025-09-05 09:09:24.072] [undefined] GET(/:id/views): successfully added views for video 8 with status 200
+[2025-09-05 09:09:35.618] [undefined] GET(/:id/channel): try to retrieve channel of user 4
+[2025-09-05 09:09:35.623] [undefined] GET(/:id/history): try to retrieve history of user 4
+[2025-09-05 09:09:35.629] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
+[2025-09-05 09:09:35.636] [undefined] GET(/:id/history): successfully retrieved history of user 4 with status 200
+[2025-09-05 09:09:35.640] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:09:37.238] [undefined] GET(/:id): try to get channel with id 2
+[2025-09-05 09:09:37.243] [undefined] GET(/:id/stats): try to get stats
+[2025-09-05 09:09:37.248] [undefined] GET(/:id/stats): Successfully get stats with status 200
+[2025-09-05 09:09:37.254] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
+[2025-09-05 09:09:38.422] [undefined] GET(/:id/channel): try to retrieve channel of user 4
+[2025-09-05 09:09:38.426] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
+[2025-09-05 09:10:03.997] [undefined] POST(/): try to upload video with status undefined
+[2025-09-05 09:10:04.013] [undefined] POST(/): successfully uploaded video with status 200
+[2025-09-05 09:10:04.026] [undefined] POST(/thumbnail): try to add thumbnail to video 11
+[2025-09-05 09:10:04.032] [undefined] POST(/thumbnail): successfully uploaded thumbnail with status 200
+[2025-09-05 09:10:04.051] [undefined] PUT(/:id/tags): try to add tags to video 11
+[2025-09-05 09:10:04.058] [undefined] PUT(/:id/tags): successfully added tags to video 11 with status 200
+[2025-09-05 09:10:04.079] [undefined] GET(/:id): try to get channel with id 2
+[2025-09-05 09:10:04.085] [undefined] GET(/:id/stats): try to get stats
+[2025-09-05 09:10:04.091] [undefined] GET(/:id/stats): Successfully get stats with status 200
+[2025-09-05 09:10:04.101] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
+[2025-09-05 09:10:09.459] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:10:11.821] [undefined] GET(/:id): try to get video 8
+[2025-09-05 09:10:11.825] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:10:11.836] [undefined] GET(/:id): successfully get video 8 with status 200
+[2025-09-05 09:10:11.846] [undefined] GET(/:id/similar): try to get similar videos for video 8
+[2025-09-05 09:10:11.852] [undefined] GET(/:id/similar): successfully get similar videos for video 8 with status 200
+[2025-09-05 09:10:11.873] [undefined] GET(/:id/views): try to add views for video 8
+[2025-09-05 09:10:11.881] [undefined] GET(/:id/views): successfully added views for video 8 with status 200
+[2025-09-05 09:10:23.198] [undefined] GET(/:id/history): try to retrieve history of user 4
+[2025-09-05 09:10:23.206] [undefined] GET(/:id/channel): try to retrieve channel of user 4
+[2025-09-05 09:10:23.216] [undefined] GET(/:id/history): successfully retrieved history of user 4 with status 200
+[2025-09-05 09:10:23.221] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
+[2025-09-05 09:10:23.226] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:10:24.469] [undefined] GET(/:id): try to get channel with id 2
+[2025-09-05 09:10:24.474] [undefined] GET(/:id/stats): try to get stats
+[2025-09-05 09:10:24.478] [undefined] GET(/:id/stats): Successfully get stats with status 200
+[2025-09-05 09:10:24.483] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
+[2025-09-05 09:10:28.356] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:10:34.421] [undefined] GET(/:id/channel): try to retrieve channel of user 4
+[2025-09-05 09:10:34.426] [undefined] GET(/:id/history): try to retrieve history of user 4
+[2025-09-05 09:10:34.430] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
+[2025-09-05 09:10:34.436] [undefined] GET(/:id/history): successfully retrieved history of user 4 with status 200
+[2025-09-05 09:10:34.441] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:10:35.603] [undefined] GET(/:id): try to get channel with id 2
+[2025-09-05 09:10:35.608] [undefined] GET(/:id/stats): try to get stats
+[2025-09-05 09:10:35.612] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
+[2025-09-05 09:10:35.619] [undefined] GET(/:id/stats): Successfully get stats with status 200
+[2025-09-05 09:10:36.921] [undefined] GET(/:id/channel): try to retrieve channel of user 4
+[2025-09-05 09:10:36.925] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
+[2025-09-05 09:10:59.327] [undefined] POST(/): try to upload video with status undefined
+[2025-09-05 09:10:59.332] [undefined] POST(/): successfully uploaded video with status 200
+[2025-09-05 09:10:59.377] [undefined] POST(/thumbnail): try to add thumbnail to video 12
+[2025-09-05 09:10:59.382] [undefined] POST(/thumbnail): successfully uploaded thumbnail with status 200
+[2025-09-05 09:10:59.398] [undefined] PUT(/:id/tags): try to add tags to video 12
+[2025-09-05 09:10:59.402] [undefined] PUT(/:id/tags): Tag prive already exists for video 12 with status 200
+[2025-09-05 09:10:59.413] [undefined] PUT(/:id/tags): successfully added tags to video 12 with status 200
+[2025-09-05 09:10:59.431] [undefined] GET(/:id): try to get channel with id 2
+[2025-09-05 09:10:59.436] [undefined] GET(/:id/stats): try to get stats
+[2025-09-05 09:10:59.440] [undefined] GET(/:id/stats): Successfully get stats with status 200
+[2025-09-05 09:10:59.451] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
+[2025-09-05 09:11:04.346] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:11:07.011] [undefined] GET(/:id): try to get video 12
+[2025-09-05 09:11:07.015] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:11:07.021] [undefined] GET(/:id): successfully get video 12 with status 200
+[2025-09-05 09:11:07.030] [undefined] GET(/:id/similar): try to get similar videos for video 12
+[2025-09-05 09:11:07.035] [undefined] GET(/:id/similar): successfully get similar videos for video 12 with status 200
+[2025-09-05 09:11:07.050] [undefined] GET(/:id/views): try to add views for video 12
+[2025-09-05 09:11:07.059] [undefined] GET(/:id/views): successfully added views for video 12 with status 200
+[2025-09-05 09:12:29.703] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:12:29.711] [undefined] GET(/:id): try to get video 12
+[2025-09-05 09:12:29.726] [undefined] GET(/:id): successfully get video 12 with status 200
+[2025-09-05 09:12:29.737] [undefined] GET(/:id/similar): try to get similar videos for video 12
+[2025-09-05 09:12:29.744] [undefined] GET(/:id/similar): successfully get similar videos for video 12 with status 200
+[2025-09-05 09:12:29.760] [undefined] GET(/:id/views): try to add views for video 12
+[2025-09-05 09:12:29.766] [undefined] GET(/:id/views): successfully added views for video 12 with status 200
+[2025-09-05 09:13:57.318] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:15:07.924] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:15:28.583] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:15:56.114] [undefined] GET(/:id): try to get video 12
+[2025-09-05 09:15:56.117] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:15:56.129] [undefined] GET(/:id): successfully get video 12 with status 200
+[2025-09-05 09:15:56.141] [undefined] GET(/:id/similar): try to get similar videos for video 12
+[2025-09-05 09:15:56.146] [undefined] GET(/:id/similar): successfully get similar videos for video 12 with status 200
+[2025-09-05 09:15:56.160] [undefined] GET(/:id/views): try to add views for video 12
+[2025-09-05 09:15:56.164] [undefined] GET(/:id/views): successfully added views for video 12 with status 200
+[2025-09-05 09:16:01.720] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:18:55.271] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:18:57.236] [undefined] GET(/:id/channel): try to retrieve channel of user 4
+[2025-09-05 09:18:57.242] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
+[2025-09-05 09:18:57.258] [undefined] GET(/:id/history): try to retrieve history of user 4
+[2025-09-05 09:18:57.262] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:18:57.267] [undefined] GET(/:id/history): successfully retrieved history of user 4 with status 200
+[2025-09-05 09:19:19.417] [undefined] GET(/:id/channel): try to retrieve channel of user 4
+[2025-09-05 09:19:19.425] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
+[2025-09-05 09:19:19.445] [undefined] GET(/:id/history): try to retrieve history of user 4
+[2025-09-05 09:19:19.449] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:19:19.459] [undefined] GET(/:id/history): successfully retrieved history of user 4 with status 200
+[2025-09-05 09:19:21.373] [undefined] GET(/:id): try to get channel with id 2
+[2025-09-05 09:19:21.378] [undefined] GET(/:id/stats): try to get stats
+[2025-09-05 09:19:21.382] [undefined] GET(/:id/stats): Successfully get stats with status 200
+[2025-09-05 09:19:21.388] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
+[2025-09-05 09:19:22.607] [undefined] GET(/:id/channel): try to retrieve channel of user 4
+[2025-09-05 09:19:22.611] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
+[2025-09-05 09:19:31.231] [undefined] GET(/search): try to search user by username A
+[2025-09-05 09:19:31.237] [undefined] GET(/search): successfully found user with username A with status 200
+[2025-09-05 09:19:31.507] [undefined] GET(/search): try to search user by username As
+[2025-09-05 09:19:31.513] [undefined] GET(/search): successfully found user with username As with status 200
+[2025-09-05 09:19:37.369] [undefined] GET(/search): try to search user by username A
+[2025-09-05 09:19:37.373] [undefined] GET(/search): successfully found user with username A with status 200
+[2025-09-05 09:19:37.603] [undefined] GET(/search): try to search user by username As
+[2025-09-05 09:19:37.608] [undefined] GET(/search): successfully found user with username As with status 200
+[2025-09-05 09:19:37.809] [undefined] GET(/search): try to search user by username Ast
+[2025-09-05 09:19:37.816] [undefined] GET(/search): successfully found user with username Ast with status 200
+[2025-09-05 09:19:37.889] [undefined] GET(/search): try to search user by username Astr
+[2025-09-05 09:19:37.892] [undefined] GET(/search): successfully found user with username Astr with status 200
+[2025-09-05 09:19:49.328] [undefined] POST(/): try to upload video with status undefined
+[2025-09-05 09:19:49.350] [undefined] POST(/): successfully uploaded video with status 200
+[2025-09-05 09:19:49.397] [undefined] POST(/thumbnail): try to add thumbnail to video 13
+[2025-09-05 09:19:49.401] [undefined] POST(/thumbnail): successfully uploaded thumbnail with status 200
+[2025-09-05 09:19:49.416] [undefined] PUT(/:id/tags): try to add tags to video 13
+[2025-09-05 09:19:49.422] [undefined] PUT(/:id/tags): successfully added tags to video 13 with status 200
+[2025-09-05 09:19:49.443] [undefined] GET(/:id): try to get channel with id 2
+[2025-09-05 09:19:49.448] [undefined] GET(/:id/stats): try to get stats
+[2025-09-05 09:19:49.453] [undefined] GET(/:id/stats): Successfully get stats with status 200
+[2025-09-05 09:19:49.467] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
+[2025-09-05 09:21:02.547] [undefined] GET(/:id/channel): try to retrieve channel of user 4
+[2025-09-05 09:21:02.553] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
+[2025-09-05 09:21:10.923] [undefined] GET(/search): try to search user by username a
+[2025-09-05 09:21:10.928] [undefined] GET(/search): successfully found user with username a with status 200
+[2025-09-05 09:21:11.146] [undefined] GET(/search): try to search user by username as
+[2025-09-05 09:21:11.150] [undefined] GET(/search): successfully found user with username as with status 200
+[2025-09-05 09:21:11.335] [undefined] GET(/search): try to search user by username ast
+[2025-09-05 09:21:11.344] [undefined] GET(/search): successfully found user with username ast with status 200
+[2025-09-05 09:21:11.382] [undefined] GET(/search): try to search user by username astr
+[2025-09-05 09:21:11.388] [undefined] GET(/search): successfully found user with username astr with status 200
+[2025-09-05 09:21:11.564] [undefined] GET(/search): try to search user by username astri
+[2025-09-05 09:21:11.568] [undefined] GET(/search): successfully found user with username astri with status 200
+[2025-09-05 09:21:15.516] [undefined] GET(/search): try to search user by username a
+[2025-09-05 09:21:15.523] [undefined] GET(/search): successfully found user with username a with status 200
+[2025-09-05 09:21:15.737] [undefined] GET(/search): try to search user by username as
+[2025-09-05 09:21:15.741] [undefined] GET(/search): successfully found user with username as with status 200
+[2025-09-05 09:21:15.918] [undefined] GET(/search): try to search user by username ast
+[2025-09-05 09:21:15.924] [undefined] GET(/search): successfully found user with username ast with status 200
+[2025-09-05 09:21:15.972] [undefined] GET(/search): try to search user by username astr
+[2025-09-05 09:21:15.980] [undefined] GET(/search): successfully found user with username astr with status 200
+[2025-09-05 09:21:27.039] [undefined] POST(/): try to upload video with status undefined
+[2025-09-05 09:21:27.051] [undefined] POST(/): successfully uploaded video with status 200
+[2025-09-05 09:21:27.068] [undefined] POST(/thumbnail): try to add thumbnail to video 14
+[2025-09-05 09:21:27.073] [undefined] POST(/thumbnail): successfully uploaded thumbnail with status 200
+[2025-09-05 09:21:27.093] [undefined] PUT(/:id/tags): try to add tags to video 14
+[2025-09-05 09:21:27.101] [undefined] PUT(/:id/tags): successfully added tags to video 14 with status 200
+[2025-09-05 09:21:27.122] [undefined] GET(/:id): try to get channel with id 2
+[2025-09-05 09:21:27.130] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
+[2025-09-05 09:21:27.139] [undefined] GET(/:id/stats): try to get stats
+[2025-09-05 09:21:27.143] [undefined] GET(/:id/stats): Successfully get stats with status 200
+[2025-09-05 09:33:45.020] [undefined] GET(/:id/likes/day): try to get likes per day
+[2025-09-05 09:33:45.025] [undefined] GET(/:id): try to get video 12
+[2025-09-05 09:33:45.035] [undefined] GET(/:id): successfully get video 12 with status 200
+[2025-09-05 09:33:45.042] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
+[2025-09-05 09:34:02.855] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:36:29.635] [undefined] GET(/:id/subscriptions): try to retrieve all subscriptions of user 4
+[2025-09-05 09:36:29.640] [undefined] GET(/:id/subscriptions): successfully retrieved all subscriptions of user 4 with status 200
+[2025-09-05 09:36:29.649] [undefined] GET(/:id/subscriptions/videos): try to retrieve all subscriptions of user 4
+[2025-09-05 09:36:29.655] [undefined] GET(/:id/subscriptions/videos): successfully retrieved all subscriptions of user 4 with status 200
+[2025-09-05 09:36:32.965] [undefined] GET(/:id): try to get channel with id 5
+[2025-09-05 09:36:32.976] [undefined] GET(/:id): Successfully get channel with id 5 with status 200
+[2025-09-05 09:36:32.989] [undefined] GET(/:id/channel/subscribed): check if user 4 is subscribed to channel 5
+[2025-09-05 09:36:32.994] [undefined] GET(/:id/channel/subscribed): user 4 is subscribed to channel 5 with status 200
+[2025-09-05 09:37:01.587] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:37:47.320] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:38:00.125] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:38:02.317] [undefined] GET(/:id/history): try to retrieve history of user 4
+[2025-09-05 09:38:02.324] [undefined] GET(/:id/history): successfully retrieved history of user 4 with status 200
+[2025-09-05 09:38:02.344] [undefined] GET(/:id/channel): try to retrieve channel of user 4
+[2025-09-05 09:38:02.350] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
+[2025-09-05 09:38:02.355] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:38:03.268] [undefined] GET(/:id): Playlist retrieved with id 4 with status 200
+[2025-09-05 09:38:04.837] [undefined] DELETE(/:id/video/:videoId): Video deleted from playlist with id 4 with status 200
+[2025-09-05 09:38:04.945] [undefined] GET(/:id): Playlist retrieved with id 4 with status 200
+[2025-09-05 09:38:06.399] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:38:22.999] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:40:19.073] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:40:19.081] [undefined] GET(/:id): try to get video 8
+[2025-09-05 09:40:19.087] [undefined] GET(/:id): successfully get video 8 with status 200
+[2025-09-05 09:40:19.098] [undefined] GET(/:id/similar): try to get similar videos for video 8
+[2025-09-05 09:40:19.109] [undefined] GET(/:id/similar): successfully get similar videos for video 8 with status 200
+[2025-09-05 09:40:19.166] [undefined] GET(/:id/views): try to add views for video 8
+[2025-09-05 09:40:19.172] [undefined] GET(/:id/views): successfully added views for video 8 with status 200
+[2025-09-05 09:40:20.697] [undefined] GET(/:id): try to get video 8
+[2025-09-05 09:40:20.700] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:40:20.711] [undefined] GET(/:id): successfully get video 8 with status 200
+[2025-09-05 09:40:20.721] [undefined] GET(/:id/similar): try to get similar videos for video 8
+[2025-09-05 09:40:20.726] [undefined] GET(/:id/similar): successfully get similar videos for video 8 with status 200
+[2025-09-05 09:40:20.784] [undefined] GET(/:id/views): try to add views for video 8
+[2025-09-05 09:40:20.788] [undefined] GET(/:id/views): successfully added views for video 8 with status 200
+[2025-09-05 09:40:32.075] [undefined] GET(/:id): try to get video 8
+[2025-09-05 09:40:32.079] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:40:32.089] [undefined] GET(/:id): successfully get video 8 with status 200
+[2025-09-05 09:40:32.102] [undefined] GET(/:id/similar): try to get similar videos for video 8
+[2025-09-05 09:40:32.108] [undefined] GET(/:id/similar): successfully get similar videos for video 8 with status 200
+[2025-09-05 09:40:32.162] [undefined] GET(/:id/views): try to add views for video 8
+[2025-09-05 09:40:32.167] [undefined] GET(/:id/views): successfully added views for video 8 with status 200
+[2025-09-05 09:40:33.008] [undefined] GET(/:id): try to get video 8
+[2025-09-05 09:40:33.013] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
+[2025-09-05 09:40:33.023] [undefined] GET(/:id): successfully get video 8 with status 200
+[2025-09-05 09:40:33.050] [undefined] GET(/:id/similar): try to get similar videos for video 8
+[2025-09-05 09:40:33.059] [undefined] GET(/:id/similar): successfully get similar videos for video 8 with status 200
+[2025-09-05 09:40:33.162] [undefined] GET(/:id/views): try to add views for video 8
+[2025-09-05 09:40:33.166] [undefined] GET(/:id/views): successfully added views for video 8 with status 200
+[2025-09-05 09:41:02.165] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
+[2025-09-05 09:50:00.863] [undefined] GET(/:id): try to get channel with id 6
+[2025-09-05 09:50:00.876] [undefined] GET(/:id): Successfully get channel with id 6 with status 200
+[2025-09-05 09:50:08.677] [undefined] GET(/:id): try to get channel with id 2
+[2025-09-05 09:50:08.689] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
+[2025-09-05 09:50:14.446] [undefined] GET(/:id): try to get channel with id 5
+[2025-09-05 09:50:14.458] [undefined] GET(/:id): Successfully get channel with id 5 with status 200
+[2025-09-05 09:50:16.410] [undefined] GET(/:id): try to get video 8
+[2025-09-05 09:50:16.421] [undefined] GET(/:id): successfully get video 8 with status 200
+[2025-09-05 09:50:16.430] [undefined] GET(/:id/similar): try to get similar videos for video 8
+[2025-09-05 09:50:16.435] [undefined] GET(/:id/similar): successfully get similar videos for video 8 with status 200
+[2025-09-05 09:59:02.737] [undefined] GET(/:id): try to get video 12
+[2025-09-05 09:59:02.743] [undefined] GET(/:id): successfully get video 12 with status 200
+[2025-09-05 09:59:02.756] [undefined] GET(/:id/similar): try to get similar videos for video 12
+[2025-09-05 09:59:02.761] [undefined] GET(/:id/similar): successfully get similar videos for video 12 with status 200
+[2025-09-05 10:02:49.939] [undefined] GET(/:id): try to get video 12
+[2025-09-05 10:02:49.952] [undefined] GET(/:id): successfully get video 12 with status 200
+[2025-09-05 10:02:49.963] [undefined] GET(/:id/similar): try to get similar videos for video 12
+[2025-09-05 10:02:49.969] [undefined] GET(/:id/similar): successfully get similar videos for video 12 with status 200
+[2025-09-05 10:04:14.469] [undefined] GET(/:id): try to get video 12
+[2025-09-05 10:04:14.479] [undefined] GET(/:id): successfully get video 12 with status 200
+[2025-09-05 10:04:14.491] [undefined] GET(/:id/similar): try to get similar videos for video 12
+[2025-09-05 10:04:14.498] [undefined] GET(/:id/similar): successfully get similar videos for video 12 with status 200
+[2025-09-05 10:06:26.495] [undefined] GET(/:id): try to get channel with id 6
+[2025-09-05 10:06:26.509] [undefined] GET(/:id): Successfully get channel with id 6 with status 200
+[2025-09-05 10:06:37.217] [undefined] GET(/:id): try to get channel with id 5
+[2025-09-05 10:06:37.227] [undefined] GET(/:id): Successfully get channel with id 5 with status 200
diff --git a/developpement.yaml b/developpement.yaml
index dd7c7b5..35ed232 100644
--- a/developpement.yaml
+++ b/developpement.yaml
@@ -20,6 +20,7 @@ services:
GMAIL_PASSWORD: ${GMAIL_PASSWORD}
GITHUB_ID: ${GITHUB_ID}
GITHUB_SECRET: ${GITHUB_SECRET}
+ FRONTEND_URL: ${FRONTEND_URL}
volumes:
- ./backend/logs:/var/log/freetube
- ./backend:/app
diff --git a/docker-compose.yaml b/docker-compose.yaml
index d0246dd..ab63c0f 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -20,6 +20,7 @@ services:
GMAIL_PASSWORD: ${GMAIL_PASSWORD}
GITHUB_ID: ${GITHUB_ID}
GITHUB_SECRET: ${GITHUB_SECRET}
+ FRONTEND_URL: ${FRONTEND_URL}
volumes:
- ./backend/logs:/var/log/freetube
- ./backend:/app
diff --git a/frontend/src/components/Recommendations.jsx b/frontend/src/components/Recommendations.jsx
index f7ce8d1..d59b791 100644
--- a/frontend/src/components/Recommendations.jsx
+++ b/frontend/src/components/Recommendations.jsx
@@ -7,9 +7,11 @@ export default function Recommendations({videos}) {