diff --git a/data/users.json b/data/users.json index 0d3d075..6e4f265 100644 --- a/data/users.json +++ b/data/users.json @@ -6,12 +6,16 @@ "subscribers": [ "ma", "miles" + ], + "watchHistory": [ + 1757455619505 ] }, { "id": 1757455788998, "username": "ma", "password": "$2b$10$FX01zPi0FXvHcXtcsX6t0.w0QHxIkkByhlX8tdx4fboQpnXtn.9a2", - "subscribers": [] + "subscribers": [], + "watchHistory": [] } ] \ No newline at end of file diff --git a/data/videos.json b/data/videos.json index c721c36..44ab658 100644 --- a/data/videos.json +++ b/data/videos.json @@ -1,27 +1,12 @@ [ - { - "id": 1757455491733, - "title": "yapping-yapping-level-today.mp4", - "filename": "1757455491493.mp4", - "uploader": "miles", - "likes": [ - "miles" - ], - "comments": [ - { - "user": "miles", - "text": "hi" - } - ], - "thumbnail": "1757455491496.png" - }, { "id": 1757455619505, "title": "SysDVR_2025_08_31_16_54_21.mp4", "filename": "1757455619060.mp4", "uploader": "miles", "likes": [ - "ma" + "ma", + "miles" ], "comments": [ { @@ -33,7 +18,8 @@ "text": "hi" } ], - "thumbnail": "1757455619233.png" + "thumbnail": "1757455619233.png", + "_score": 0.2 }, { "id": 1757455624902, @@ -54,6 +40,7 @@ "text": "no" } ], - "thumbnail": "1757455624790.png" + "thumbnail": "1757455624790.png", + "_score": 0.4 } ] \ No newline at end of file diff --git a/public/admin.html b/public/admin.html new file mode 100644 index 0000000..63504cd --- /dev/null +++ b/public/admin.html @@ -0,0 +1,27 @@ + + + + Admin Panel - MiniTube + + + + +

Admin Panel

+
+

Delete User Account

+
+ + +
+

+
+
+

Delete Video

+
+ + +
+

+
+ + diff --git a/public/admin.js b/public/admin.js new file mode 100644 index 0000000..cee9e65 --- /dev/null +++ b/public/admin.js @@ -0,0 +1,27 @@ +// Admin Panel JS + +document.getElementById('deleteUserForm').addEventListener('submit', async (e) => { + e.preventDefault(); + const username = document.getElementById('deleteUsername').value.trim(); + if (!username) return; + const res = await fetch('/api/admin/delete-user', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ username }) + }); + const data = await res.json(); + document.getElementById('userDeleteMsg').textContent = data.success ? 'User deleted.' : (data.error || 'Error.'); +}); + +document.getElementById('deleteVideoForm').addEventListener('submit', async (e) => { + e.preventDefault(); + const id = document.getElementById('deleteVideoId').value.trim(); + if (!id) return; + const res = await fetch('/api/admin/delete-video', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ id }) + }); + const data = await res.json(); + document.getElementById('videoDeleteMsg').textContent = data.success ? 'Video deleted.' : (data.error || 'Error.'); +}); diff --git a/public/app.js b/public/app.js index 2b3f9b5..9c9e4da 100644 --- a/public/app.js +++ b/public/app.js @@ -1,3 +1,102 @@ +// -------------------- Recommended Videos (Personalized) -------------------- +async function loadRecommendedIndex() { + const list = document.getElementById('recommendedVideos'); + if (!list) return; + let videos = []; + let res; + try { + res = await fetch('/api/recommended'); + if (res.ok) { + videos = await res.json(); + } else { + res = await fetch('/api/videos'); + videos = await res.json(); + } + } catch { + res = await fetch('/api/videos'); + videos = await res.json(); + } + // Show top 6 + const top = videos.slice(0, 6); + list.innerHTML = ''; + for (const v of top) { + const li = document.createElement('li'); + li.style.display = 'flex'; + li.style.alignItems = 'center'; + li.style.marginBottom = '1em'; + li.innerHTML = ` + + +
+
${v.title}
+
by ${v.uploader}
+
${v.likes?.length || 0} likes
+
+
+ `; + list.appendChild(li); + } +} +// -------------------- Watch Later & History (localStorage) -------------------- +function getWatchLater() { + return JSON.parse(localStorage.getItem('watchLater') || '[]'); +} +function setWatchLater(arr) { + localStorage.setItem('watchLater', JSON.stringify(arr)); +} +function addToWatchLater(video) { + let arr = getWatchLater(); + if (!arr.find(v => v.id === video.id)) { + arr.unshift(video); + setWatchLater(arr.slice(0, 20)); + } + renderWatchLater(); +} +function removeFromWatchLater(id) { + let arr = getWatchLater().filter(v => v.id !== id); + setWatchLater(arr); + renderWatchLater(); +} +function renderWatchLater() { + const list = document.getElementById('watchLaterList'); + if (!list) return; + const arr = getWatchLater(); + list.innerHTML = ''; + arr.forEach(v => { + const li = document.createElement('li'); + li.innerHTML = `${v.title} `; + list.appendChild(li); + }); + list.querySelectorAll('.removeLater').forEach(btn => { + btn.onclick = e => removeFromWatchLater(btn.dataset.id); + }); +} + +function getWatchHistory() { + return JSON.parse(localStorage.getItem('watchHistory') || '[]'); +} +function setWatchHistory(arr) { + localStorage.setItem('watchHistory', JSON.stringify(arr)); +} +function addToWatchHistory(video) { + let arr = getWatchHistory(); + arr = arr.filter(v => v.id !== video.id); + arr.unshift(video); + setWatchHistory(arr.slice(0, 20)); + renderWatchHistory(); +} +function renderWatchHistory() { + const list = document.getElementById('watchHistoryList'); + if (!list) return; + const arr = getWatchHistory(); + list.innerHTML = ''; + arr.forEach(v => { + const li = document.createElement('li'); + li.innerHTML = `${v.title}`; + list.appendChild(li); + }); +} + // -------------------- Load Videos on Homepage -------------------- async function loadVideos() { try { @@ -13,9 +112,20 @@ async function loadVideos() { ${v.title} by ${v.uploader} + `; list.appendChild(li); }); + // Add event listeners for Watch Later + list.querySelectorAll('.addLater').forEach(btn => { + btn.onclick = async e => { + const id = btn.dataset.id; + const v = videos.find(v => v.id == id); + if (v) addToWatchLater(v); + }; + }); + renderWatchLater(); + renderWatchHistory(); } catch (err) { console.error("Error loading videos:", err); } @@ -93,6 +203,9 @@ document.addEventListener("DOMContentLoaded", () => { // Homepage video list loadVideos(); + // Recommended sidebar + loadRecommendedIndex(); + // Login form const loginForm = document.getElementById("loginForm"); if (loginForm) loginForm.addEventListener("submit", loginUser); @@ -108,4 +221,8 @@ document.addEventListener("DOMContentLoaded", () => { // Upload form const uploadForm = document.getElementById("uploadForm"); if (uploadForm) uploadForm.addEventListener("submit", uploadVideo); + + // Render watch later/history on all pages + renderWatchLater(); + renderWatchHistory(); }); diff --git a/public/index.html b/public/index.html index d719925..ff87742 100644 --- a/public/index.html +++ b/public/index.html @@ -6,12 +6,22 @@ -

MiniTube

- - -

-

- - +
+
+

MiniTube

+ +

+

+ +
+ +
diff --git a/public/upload.html b/public/upload.html index 64ca7f6..d4503ab 100644 --- a/public/upload.html +++ b/public/upload.html @@ -14,6 +14,39 @@ + + + + + + + + + + + + + + + + + +

Back to Home

+ diff --git a/public/watch.html b/public/watch.html index 554aa03..e1fa61a 100644 --- a/public/watch.html +++ b/public/watch.html @@ -5,34 +5,60 @@ -

- -

Uploader:

- - +
+
+

+ +

Uploader:

- -

+ + -

Change Thumbnail

-
- - -
+ +

-

Comments

- -
- - -
+ + +

Comments

+ +
+ + +
+
+ +