diff --git a/src/assets/jpg/video-thumbnail-fallback.jpg b/src/assets/jpg/video-thumbnail-fallback.jpg new file mode 100644 index 0000000..ac4493d Binary files /dev/null and b/src/assets/jpg/video-thumbnail-fallback.jpg differ diff --git a/src/js/app.js b/src/js/app.js index 7d34789..acc34ff 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -1,5 +1,11 @@ // js/app.js +// +// DO NOT REMOVE OR EDIT. This context is for internal build tooling. +// File: js/app.js +// Project: bitvid +// + import { nostrClient } from "./nostr.js"; import { torrentClient } from "./webtorrent.js"; import { isDevMode } from "./config.js"; @@ -535,38 +541,34 @@ class bitvidApp { videosCount: videos ? videos.length : "N/A", videosType: typeof videos, }); - + if (!videos) { console.error("NO VIDEOS RECEIVED"); this.videoList.innerHTML = `

No videos found.

`; return; } - + const videoArray = Array.isArray(videos) ? videos : [videos]; - + if (videoArray.length === 0) { console.error("VIDEO ARRAY IS EMPTY"); this.videoList.innerHTML = `

No videos available.

`; return; } - + // Sort by creation date videoArray.sort((a, b) => b.created_at - a.created_at); - - // Prepare to fetch user profiles + const userProfiles = new Map(); const uniquePubkeys = [...new Set(videoArray.map((v) => v.pubkey))]; - + + // Fetch user profiles for (const pubkey of uniquePubkeys) { try { const userEvents = await nostrClient.pool.list(nostrClient.relays, [ - { - kinds: [0], - authors: [pubkey], - limit: 1, - }, + { kinds: [0], authors: [pubkey], limit: 1 }, ]); - + if (userEvents[0]?.content) { const profile = JSON.parse(userEvents[0].content); userProfiles.set(pubkey, { @@ -587,8 +589,8 @@ class bitvidApp { }); } } - - // Build HTML for each video + + // Build video cards const renderedVideos = videoArray .map((video, index) => { try { @@ -596,31 +598,25 @@ class bitvidApp { console.error(`Invalid video: ${video.title}`); return ""; } - - // First, create a ?v=... link for middle-click / ctrl+click - const nevent = window.NostrTools.nip19.neventEncode({ - id: video.id, - }); - const shareUrl = `${ - window.location.pathname - }?v=${encodeURIComponent(nevent)}`; - + + // Create share URL + const nevent = window.NostrTools.nip19.neventEncode({ id: video.id }); + const shareUrl = `${window.location.pathname}?v=${encodeURIComponent(nevent)}`; + + // Get profile info const profile = userProfiles.get(video.pubkey) || { name: "Unknown", picture: `https://robohash.org/${video.pubkey}`, }; const timeAgo = this.formatTimeAgo(video.created_at); - - // If user is the owner + + // Determine edit capability const canEdit = video.pubkey === this.pubkey; - - // If it's private + user owns it => highlight with a special border - const highlightClass = - video.isPrivate && canEdit - ? "border-2 border-yellow-500" - : "border-none"; // normal case - - // Gear menu if canEdit + const highlightClass = video.isPrivate && canEdit + ? "border-2 border-yellow-500" + : "border-none"; + + // If user can edit, show gear menu const gearMenu = canEdit ? `
@@ -629,14 +625,13 @@ class bitvidApp { class="inline-flex items-center p-2 rounded-full text-gray-400 hover:text-gray-200 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500" onclick="document.getElementById('settingsDropdown-${index}').classList.toggle('hidden')" > - Settings - - ` : ""; - - // Instead of a
for the thumbnail, we use - // This allows middle-click or ctrl+click to open shareUrl in a new tab, - // while left-click is prevented => opens modal + + // Main video card return `
- - ${ - video.thumbnail - ? `${this.escapeHTML(video.title)}` - : `
- - - - -
` - } + ${this.escapeHTML(video.title)}
-
- -

- ${this.escapeHTML(video.title)} -

+

+ ${this.escapeHTML(video.title)} +

- -
- -
-
- ${profile.name} -
-
-

- ${this.escapeHTML(profile.name)} -

-
- ${timeAgo} -
-
+
+
+
+ ${profile.name} +
+
+

+ ${this.escapeHTML(profile.name)} +

+
+ ${timeAgo}
- - ${gearMenu} +
+ ${gearMenu} +
`; @@ -740,14 +723,14 @@ class bitvidApp { } }) .filter((html) => html.length > 0); - + console.log("Rendered videos:", renderedVideos.length); - + if (renderedVideos.length === 0) { this.videoList.innerHTML = `

No valid videos to display.

`; return; } - + this.videoList.innerHTML = renderedVideos.join(""); console.log("Videos rendered successfully"); } catch (error) {