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}
>