mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2025-09-08 06:58:43 +00:00
updated gear icon on profile page and removed "make private" option until i can get it working correctly
This commit is contained in:
@@ -105,7 +105,7 @@
|
|||||||
class="mt-1 block w-full rounded-md border-gray-700 bg-gray-800 text-gray-100 focus:border-blue-500 focus:ring-blue-500"
|
class="mt-1 block w-full rounded-md border-gray-700 bg-gray-800 text-gray-100 focus:border-blue-500 focus:ring-blue-500"
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<!--
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -116,7 +116,7 @@
|
|||||||
>Private Listing (Encrypt Magnet)</span
|
>Private Listing (Encrypt Magnet)</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
class="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
||||||
|
@@ -2,8 +2,31 @@
|
|||||||
|
|
||||||
> ⚠️ **Note:** If you find a new bug thats not listed here. Please submit a [Bug Report](https://bitvid.network/?modal=bug).
|
> ⚠️ **Note:** If you find a new bug thats not listed here. Please submit a [Bug Report](https://bitvid.network/?modal=bug).
|
||||||
|
|
||||||
|
- Speed up loading in subscriptions. Save to local cache?
|
||||||
- Fix "Dev Mode" publishing "Live Mode" notes—add a flag for dev mode posts.
|
- Fix "Dev Mode" publishing "Live Mode" notes—add a flag for dev mode posts.
|
||||||
- Fix issue with video post set to private.
|
- Fix issue with video post set to private.
|
||||||
|
- Disable "private video" until I can make it work better.
|
||||||
|
- Make "private video" work better using nip-04 encryption for magnet field.
|
||||||
|
- Fix slow back button issues on Firefox.
|
||||||
|
- Add Amber login support for mobile.
|
||||||
|
- Add settings (three dots) button for all videos, not the same as gear menu. Only show delete and edit gear for logged-in users videos.
|
||||||
|
- Add support for "Playlist" lists and other custom lists (named whatever) and also "Watch Later" list and "Watch History".
|
||||||
|
- Add an "add to playlist" button to the edit button.
|
||||||
|
- Add "add to watch later" option to edit button.
|
||||||
|
- Add block button to settings button.
|
||||||
|
- Add report button to settings button.
|
||||||
|
- Fix autoplay broken on iPhone chrome.
|
||||||
|
- Fix playback broken on Safari on iPhone.
|
||||||
|
- Update note spec v3 transition to include new fields that have been added like "has previous" or "videoRootID" or enentID if null.
|
||||||
|
- Change "explore" view to "kids" view and add flag to all notes to see if they are for kids.
|
||||||
|
- Add "seed" lists.
|
||||||
|
- Make "edit" video a form modal rather than a browser pop-up.
|
||||||
|
- Add "upload thumbnail" as option to add/edit video form. (use https://apidocs.imgur.com/)
|
||||||
|
- Fix issue where page refreshes when pulling up a video in the video modal.
|
||||||
|
- Fix sidebar media query settings on medium-sized screens. (tablet/laptops)
|
||||||
|
- Fix various "text wrap" issues causing scroll left and right on profile and modal pages.
|
||||||
|
- Add zaps to profile and video modal pages.
|
||||||
|
- Add comments to video modal pages.
|
||||||
|
|
||||||
## Feature Additions
|
## Feature Additions
|
||||||
|
|
||||||
|
94
js/app.js
94
js/app.js
@@ -349,7 +349,7 @@ class bitvidApp {
|
|||||||
this.showError("Could not generate link.");
|
this.showError("Could not generate link.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add click handlers for avatar and name => channel profile
|
// Add click handlers for avatar and name => channel profile
|
||||||
if (this.creatorAvatar) {
|
if (this.creatorAvatar) {
|
||||||
@@ -708,31 +708,33 @@ class bitvidApp {
|
|||||||
async batchFetchProfiles(authorSet) {
|
async batchFetchProfiles(authorSet) {
|
||||||
const pubkeys = Array.from(authorSet);
|
const pubkeys = Array.from(authorSet);
|
||||||
if (!pubkeys.length) return;
|
if (!pubkeys.length) return;
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
kinds: [0],
|
kinds: [0],
|
||||||
authors: pubkeys,
|
authors: pubkeys,
|
||||||
limit: pubkeys.length,
|
limit: pubkeys.length,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Query each relay
|
// Query each relay
|
||||||
const results = await Promise.all(
|
const results = await Promise.all(
|
||||||
nostrClient.relays.map(relayUrl =>
|
nostrClient.relays.map((relayUrl) =>
|
||||||
nostrClient.pool.list([relayUrl], [filter])
|
nostrClient.pool.list([relayUrl], [filter])
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const allProfileEvents = results.flat();
|
const allProfileEvents = results.flat();
|
||||||
|
|
||||||
// Keep only the newest per author
|
// Keep only the newest per author
|
||||||
const newestEvents = new Map();
|
const newestEvents = new Map();
|
||||||
for (const evt of allProfileEvents) {
|
for (const evt of allProfileEvents) {
|
||||||
if (!newestEvents.has(evt.pubkey) ||
|
if (
|
||||||
evt.created_at > newestEvents.get(evt.pubkey).created_at) {
|
!newestEvents.has(evt.pubkey) ||
|
||||||
|
evt.created_at > newestEvents.get(evt.pubkey).created_at
|
||||||
|
) {
|
||||||
newestEvents.set(evt.pubkey, evt);
|
newestEvents.set(evt.pubkey, evt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the cache & DOM
|
// Update the cache & DOM
|
||||||
for (const [pubkey, evt] of newestEvents.entries()) {
|
for (const [pubkey, evt] of newestEvents.entries()) {
|
||||||
try {
|
try {
|
||||||
@@ -751,7 +753,7 @@ class bitvidApp {
|
|||||||
console.error("Batch profile fetch error:", err);
|
console.error("Batch profile fetch error:", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProfileInDOM(pubkey, profile) {
|
updateProfileInDOM(pubkey, profile) {
|
||||||
// For any .author-pic[data-pubkey=...]
|
// For any .author-pic[data-pubkey=...]
|
||||||
const picEls = document.querySelectorAll(
|
const picEls = document.querySelectorAll(
|
||||||
@@ -791,7 +793,7 @@ class bitvidApp {
|
|||||||
thumbnail: thumbEl?.value.trim() || "",
|
thumbnail: thumbEl?.value.trim() || "",
|
||||||
description: descEl?.value.trim() || "",
|
description: descEl?.value.trim() || "",
|
||||||
mode: isDevMode ? "dev" : "live",
|
mode: isDevMode ? "dev" : "live",
|
||||||
isPrivate: privEl?.checked || false,
|
// isPrivate: privEl?.checked || false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!formData.title || !formData.magnet) {
|
if (!formData.title || !formData.magnet) {
|
||||||
@@ -1023,10 +1025,10 @@ class bitvidApp {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.videoSubscription) {
|
if (this.videoSubscription) {
|
||||||
|
console.log(
|
||||||
console.log("[loadVideos] subscription remains open to get live updates.");
|
"[loadVideos] subscription remains open to get live updates."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Already subscribed: just show what's cached
|
// Already subscribed: just show what's cached
|
||||||
const allCached = nostrClient.getActiveVideos();
|
const allCached = nostrClient.getActiveVideos();
|
||||||
@@ -1055,12 +1057,12 @@ class bitvidApp {
|
|||||||
async loadOlderVideos(lastTimestamp) {
|
async loadOlderVideos(lastTimestamp) {
|
||||||
// 1) Use nostrClient to fetch older slices
|
// 1) Use nostrClient to fetch older slices
|
||||||
const olderVideos = await nostrClient.fetchOlderVideos(lastTimestamp);
|
const olderVideos = await nostrClient.fetchOlderVideos(lastTimestamp);
|
||||||
|
|
||||||
if (!olderVideos || olderVideos.length === 0) {
|
if (!olderVideos || olderVideos.length === 0) {
|
||||||
this.showSuccess("No more older videos found.");
|
this.showSuccess("No more older videos found.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Merge them into the client’s allEvents / activeMap
|
// 2) Merge them into the client’s allEvents / activeMap
|
||||||
for (const v of olderVideos) {
|
for (const v of olderVideos) {
|
||||||
nostrClient.allEvents.set(v.id, v);
|
nostrClient.allEvents.set(v.id, v);
|
||||||
@@ -1069,11 +1071,11 @@ class bitvidApp {
|
|||||||
// You can call getActiveKey(v) if you want to match your code’s approach.
|
// You can call getActiveKey(v) if you want to match your code’s approach.
|
||||||
// Then re-check if this one is newer than what’s stored, etc.
|
// Then re-check if this one is newer than what’s stored, etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Re-render
|
// 3) Re-render
|
||||||
const all = nostrClient.getActiveVideos();
|
const all = nostrClient.getActiveVideos();
|
||||||
this.renderVideoList(all);
|
this.renderVideoList(all);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if there's at least one strictly older version
|
* Returns true if there's at least one strictly older version
|
||||||
@@ -1094,7 +1096,7 @@ class bitvidApp {
|
|||||||
|
|
||||||
async renderVideoList(videos) {
|
async renderVideoList(videos) {
|
||||||
if (!this.videoList) return;
|
if (!this.videoList) return;
|
||||||
|
|
||||||
// 1) If no videos
|
// 1) If no videos
|
||||||
if (!videos || videos.length === 0) {
|
if (!videos || videos.length === 0) {
|
||||||
this.videoList.innerHTML = `
|
this.videoList.innerHTML = `
|
||||||
@@ -1103,38 +1105,40 @@ class bitvidApp {
|
|||||||
</p>`;
|
</p>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Sort newest first
|
// 2) Sort newest first
|
||||||
videos.sort((a, b) => b.created_at - a.created_at);
|
videos.sort((a, b) => b.created_at - a.created_at);
|
||||||
|
|
||||||
const fullAllEventsArray = Array.from(nostrClient.allEvents.values());
|
const fullAllEventsArray = Array.from(nostrClient.allEvents.values());
|
||||||
const fragment = document.createDocumentFragment();
|
const fragment = document.createDocumentFragment();
|
||||||
const authorSet = new Set();
|
const authorSet = new Set();
|
||||||
|
|
||||||
// 3) Build each card
|
// 3) Build each card
|
||||||
videos.forEach((video, index) => {
|
videos.forEach((video, index) => {
|
||||||
if (!video.id || !video.title) {
|
if (!video.id || !video.title) {
|
||||||
console.error("Video missing ID/title:", video);
|
console.error("Video missing ID/title:", video);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
authorSet.add(video.pubkey);
|
authorSet.add(video.pubkey);
|
||||||
|
|
||||||
const nevent = window.NostrTools.nip19.neventEncode({ id: video.id });
|
const nevent = window.NostrTools.nip19.neventEncode({ id: video.id });
|
||||||
const shareUrl = `${window.location.pathname}?v=${encodeURIComponent(nevent)}`;
|
const shareUrl = `${window.location.pathname}?v=${encodeURIComponent(
|
||||||
|
nevent
|
||||||
|
)}`;
|
||||||
const canEdit = video.pubkey === this.pubkey;
|
const canEdit = video.pubkey === this.pubkey;
|
||||||
const highlightClass =
|
const highlightClass =
|
||||||
video.isPrivate && canEdit
|
video.isPrivate && canEdit
|
||||||
? "border-2 border-yellow-500"
|
? "border-2 border-yellow-500"
|
||||||
: "border-none";
|
: "border-none";
|
||||||
const timeAgo = this.formatTimeAgo(video.created_at);
|
const timeAgo = this.formatTimeAgo(video.created_at);
|
||||||
|
|
||||||
// Check if there's an older version
|
// Check if there's an older version
|
||||||
let hasOlder = false;
|
let hasOlder = false;
|
||||||
if (canEdit && video.videoRootId) {
|
if (canEdit && video.videoRootId) {
|
||||||
hasOlder = this.hasOlderVersion(video, fullAllEventsArray);
|
hasOlder = this.hasOlderVersion(video, fullAllEventsArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
const revertButton = hasOlder
|
const revertButton = hasOlder
|
||||||
? `
|
? `
|
||||||
<button
|
<button
|
||||||
@@ -1145,7 +1149,7 @@ class bitvidApp {
|
|||||||
</button>
|
</button>
|
||||||
`
|
`
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const gearMenu = canEdit
|
const gearMenu = canEdit
|
||||||
? `
|
? `
|
||||||
<div class="relative inline-block ml-3 overflow-visible">
|
<div class="relative inline-block ml-3 overflow-visible">
|
||||||
@@ -1183,7 +1187,7 @@ class bitvidApp {
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const cardHtml = `
|
const cardHtml = `
|
||||||
<div class="video-card bg-gray-900 rounded-lg overflow-hidden shadow-lg hover:shadow-2xl transition-all duration-300 ${highlightClass}">
|
<div class="video-card bg-gray-900 rounded-lg overflow-hidden shadow-lg hover:shadow-2xl transition-all duration-300 ${highlightClass}">
|
||||||
<!-- The clickable link to play video -->
|
<!-- The clickable link to play video -->
|
||||||
@@ -1236,23 +1240,25 @@ class bitvidApp {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const template = document.createElement("template");
|
const template = document.createElement("template");
|
||||||
template.innerHTML = cardHtml.trim();
|
template.innerHTML = cardHtml.trim();
|
||||||
const cardEl = template.content.firstElementChild;
|
const cardEl = template.content.firstElementChild;
|
||||||
fragment.appendChild(cardEl);
|
fragment.appendChild(cardEl);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clear old content, add new
|
// Clear old content, add new
|
||||||
this.videoList.innerHTML = "";
|
this.videoList.innerHTML = "";
|
||||||
this.videoList.appendChild(fragment);
|
this.videoList.appendChild(fragment);
|
||||||
|
|
||||||
// Lazy-load images
|
// Lazy-load images
|
||||||
const lazyEls = this.videoList.querySelectorAll("[data-lazy]");
|
const lazyEls = this.videoList.querySelectorAll("[data-lazy]");
|
||||||
lazyEls.forEach((el) => this.mediaLoader.observe(el));
|
lazyEls.forEach((el) => this.mediaLoader.observe(el));
|
||||||
|
|
||||||
// GEAR MENU / button event listeners...
|
// GEAR MENU / button event listeners...
|
||||||
const gearButtons = this.videoList.querySelectorAll("[data-settings-dropdown]");
|
const gearButtons = this.videoList.querySelectorAll(
|
||||||
|
"[data-settings-dropdown]"
|
||||||
|
);
|
||||||
gearButtons.forEach((button) => {
|
gearButtons.forEach((button) => {
|
||||||
button.addEventListener("click", () => {
|
button.addEventListener("click", () => {
|
||||||
const index = button.getAttribute("data-settings-dropdown");
|
const index = button.getAttribute("data-settings-dropdown");
|
||||||
@@ -1262,7 +1268,7 @@ class bitvidApp {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Edit button
|
// Edit button
|
||||||
const editButtons = this.videoList.querySelectorAll("[data-edit-index]");
|
const editButtons = this.videoList.querySelectorAll("[data-edit-index]");
|
||||||
editButtons.forEach((button) => {
|
editButtons.forEach((button) => {
|
||||||
@@ -1275,7 +1281,9 @@ class bitvidApp {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Revert button
|
// Revert button
|
||||||
const revertButtons = this.videoList.querySelectorAll("[data-revert-index]");
|
const revertButtons = this.videoList.querySelectorAll(
|
||||||
|
"[data-revert-index]"
|
||||||
|
);
|
||||||
revertButtons.forEach((button) => {
|
revertButtons.forEach((button) => {
|
||||||
button.addEventListener("click", () => {
|
button.addEventListener("click", () => {
|
||||||
const index = button.getAttribute("data-revert-index");
|
const index = button.getAttribute("data-revert-index");
|
||||||
@@ -1286,7 +1294,9 @@ class bitvidApp {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Delete All button
|
// Delete All button
|
||||||
const deleteAllButtons = this.videoList.querySelectorAll("[data-delete-all-index]");
|
const deleteAllButtons = this.videoList.querySelectorAll(
|
||||||
|
"[data-delete-all-index]"
|
||||||
|
);
|
||||||
deleteAllButtons.forEach((button) => {
|
deleteAllButtons.forEach((button) => {
|
||||||
button.addEventListener("click", () => {
|
button.addEventListener("click", () => {
|
||||||
const index = button.getAttribute("data-delete-all-index");
|
const index = button.getAttribute("data-delete-all-index");
|
||||||
@@ -1295,10 +1305,10 @@ class bitvidApp {
|
|||||||
this.handleFullDeleteVideo(index);
|
this.handleFullDeleteVideo(index);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2) After building cards, do one batch profile fetch
|
// 2) After building cards, do one batch profile fetch
|
||||||
this.batchFetchProfiles(authorSet);
|
this.batchFetchProfiles(authorSet);
|
||||||
|
|
||||||
// === NEW: attach click listeners to .author-pic and .author-name
|
// === NEW: attach click listeners to .author-pic and .author-name
|
||||||
const authorPics = this.videoList.querySelectorAll(".author-pic");
|
const authorPics = this.videoList.querySelectorAll(".author-pic");
|
||||||
authorPics.forEach((pic) => {
|
authorPics.forEach((pic) => {
|
||||||
@@ -1310,7 +1320,7 @@ class bitvidApp {
|
|||||||
this.goToProfile(pubkey);
|
this.goToProfile(pubkey);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const authorNames = this.videoList.querySelectorAll(".author-name");
|
const authorNames = this.videoList.querySelectorAll(".author-name");
|
||||||
authorNames.forEach((nameEl) => {
|
authorNames.forEach((nameEl) => {
|
||||||
nameEl.style.cursor = "pointer";
|
nameEl.style.cursor = "pointer";
|
||||||
@@ -1322,7 +1332,7 @@ class bitvidApp {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the modal to reflect current torrent stats.
|
* Updates the modal to reflect current torrent stats.
|
||||||
* We remove the unused torrent.status references,
|
* We remove the unused torrent.status references,
|
||||||
@@ -1416,7 +1426,7 @@ class bitvidApp {
|
|||||||
"New Description? (blank=keep existing)",
|
"New Description? (blank=keep existing)",
|
||||||
video.description
|
video.description
|
||||||
);
|
);
|
||||||
const wantPrivate = confirm("Make this video private? OK=Yes, Cancel=No");
|
// const wantPrivate = confirm("Make this video private? OK=Yes, Cancel=No");
|
||||||
|
|
||||||
// 4) Build final updated fields (or fallback to existing)
|
// 4) Build final updated fields (or fallback to existing)
|
||||||
const title =
|
const title =
|
||||||
@@ -1431,7 +1441,7 @@ class bitvidApp {
|
|||||||
// 5) Create an object with the new data
|
// 5) Create an object with the new data
|
||||||
const updatedData = {
|
const updatedData = {
|
||||||
version: video.version || 2,
|
version: video.version || 2,
|
||||||
isPrivate: wantPrivate,
|
// isPrivate: wantPrivate,
|
||||||
title,
|
title,
|
||||||
magnet,
|
magnet,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
|
@@ -276,15 +276,16 @@ async function loadUserVideos(pubkey) {
|
|||||||
<div class="relative inline-block ml-3 overflow-visible">
|
<div class="relative inline-block ml-3 overflow-visible">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="inline-flex items-center p-2 rounded-full text-gray-400
|
class="inline-flex items-center justify-center
|
||||||
hover:text-gray-200 hover:bg-gray-800 focus:outline-none focus:ring-2
|
w-10 h-10 p-2
|
||||||
focus:ring-blue-500"
|
rounded-full text-gray-400 hover:text-gray-200 hover:bg-gray-800
|
||||||
|
focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
data-settings-dropdown="${index}"
|
data-settings-dropdown="${index}"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src="assets/svg/video-settings-gear.svg"
|
src="assets/svg/video-settings-gear.svg"
|
||||||
alt="Settings"
|
alt="Settings"
|
||||||
class="w-5 h-5"
|
class="w-5 h-5 object-contain"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
|
Reference in New Issue
Block a user