// js/components/VideoList.js import { nostrClient } from "../nostr.js"; import { formatTimeAgo } from "../utils/timeUtils.js"; import { escapeHTML } from "../utils/htmlUtils.js"; export class VideoList { constructor() { this.videoList = document.getElementById("videoList"); this.pubkey = null; // We'll need this for private video filtering } setPubkey(pubkey) { this.pubkey = pubkey; } async loadVideos() { console.log("Starting loadVideos..."); try { const videos = await nostrClient.fetchVideos(); console.log("Raw videos from nostrClient:", videos); if (!videos) { console.log("No videos received"); throw new Error("No videos received from relays"); } // Convert to array if not already const videosArray = Array.isArray(videos) ? videos : [videos]; // Filter private videos const displayedVideos = videosArray.filter((video) => { if (!video.isPrivate) { return true; } return this.pubkey && video.pubkey === this.pubkey; }); if (displayedVideos.length === 0) { console.log("No valid videos found after filtering."); this.renderEmptyState( "No public videos available yet. Be the first to upload one!" ); return; } console.log("Processing filtered videos:", displayedVideos); await this.renderVideoList(displayedVideos); console.log(`Rendered ${displayedVideos.length} videos successfully`); } catch (error) { console.log("Failed to fetch videos:", error); this.renderEmptyState( "No videos available at the moment. Please try again later." ); } } renderEmptyState(message) { if (this.videoList) { this.videoList.innerHTML = `
${escapeHTML(message)}
`; } } async renderVideoList(videos) { try { console.log("RENDER VIDEO LIST - Start", { videosReceived: videos, videosCount: videos ? videos.length : "N/A", videosType: typeof videos, }); if (!videos || videos.length === 0) { this.renderEmptyState("No videos found."); return; } // Sort by creation date const videoArray = [...videos].sort( (a, b) => b.created_at - a.created_at ); // Fetch user profiles const userProfiles = await this.fetchUserProfiles(videoArray); // Build HTML for each video const renderedVideos = videoArray .map((video, index) => this.renderVideoCard(video, index, userProfiles)) .filter(Boolean); if (renderedVideos.length === 0) { this.renderEmptyState("No valid videos to display."); return; } this.videoList.innerHTML = renderedVideos.join(""); console.log("Videos rendered successfully"); } catch (error) { console.error("Rendering error:", error); this.renderEmptyState("Error loading videos."); } } async fetchUserProfiles(videos) { const userProfiles = new Map(); const uniquePubkeys = [...new Set(videos.map((v) => v.pubkey))]; for (const pubkey of uniquePubkeys) { try { const profile = await nostrClient.fetchUserProfile(pubkey); userProfiles.set(pubkey, profile); } catch (error) { console.error(`Profile fetch error for ${pubkey}:`, error); userProfiles.set(pubkey, { name: "Unknown", picture: `https://robohash.org/${pubkey}`, }); } } return userProfiles; } renderVideoCard(video, index, userProfiles) { try { if (!this.validateVideo(video, index)) { console.error(`Invalid video: ${video.title}`); return ""; } const profile = userProfiles.get(video.pubkey) || { name: "Unknown", picture: `https://robohash.org/${video.pubkey}`, }; const canEdit = video.pubkey === this.pubkey; const highlightClass = video.isPrivate && canEdit ? "border-2 border-yellow-500" : "border-none"; return `${escapeHTML(profile.name)}