mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2025-09-10 07:58:47 +00:00
added fallback thumbnail image
this is in case the videos thumbnail image cant be loaded in.
This commit is contained in:
BIN
src/assets/jpg/video-thumbnail-fallback.jpg
Normal file
BIN
src/assets/jpg/video-thumbnail-fallback.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 93 KiB |
@@ -1,5 +1,11 @@
|
|||||||
// js/app.js
|
// js/app.js
|
||||||
|
|
||||||
|
// <ai_context>
|
||||||
|
// DO NOT REMOVE OR EDIT. This context is for internal build tooling.
|
||||||
|
// File: js/app.js
|
||||||
|
// Project: bitvid
|
||||||
|
// </ai_context>
|
||||||
|
|
||||||
import { nostrClient } from "./nostr.js";
|
import { nostrClient } from "./nostr.js";
|
||||||
import { torrentClient } from "./webtorrent.js";
|
import { torrentClient } from "./webtorrent.js";
|
||||||
import { isDevMode } from "./config.js";
|
import { isDevMode } from "./config.js";
|
||||||
@@ -553,18 +559,14 @@ class bitvidApp {
|
|||||||
// Sort by creation date
|
// Sort by creation date
|
||||||
videoArray.sort((a, b) => b.created_at - a.created_at);
|
videoArray.sort((a, b) => b.created_at - a.created_at);
|
||||||
|
|
||||||
// Prepare to fetch user profiles
|
|
||||||
const userProfiles = new Map();
|
const userProfiles = new Map();
|
||||||
const uniquePubkeys = [...new Set(videoArray.map((v) => v.pubkey))];
|
const uniquePubkeys = [...new Set(videoArray.map((v) => v.pubkey))];
|
||||||
|
|
||||||
|
// Fetch user profiles
|
||||||
for (const pubkey of uniquePubkeys) {
|
for (const pubkey of uniquePubkeys) {
|
||||||
try {
|
try {
|
||||||
const userEvents = await nostrClient.pool.list(nostrClient.relays, [
|
const userEvents = await nostrClient.pool.list(nostrClient.relays, [
|
||||||
{
|
{ kinds: [0], authors: [pubkey], limit: 1 },
|
||||||
kinds: [0],
|
|
||||||
authors: [pubkey],
|
|
||||||
limit: 1,
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (userEvents[0]?.content) {
|
if (userEvents[0]?.content) {
|
||||||
@@ -588,7 +590,7 @@ class bitvidApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build HTML for each video
|
// Build video cards
|
||||||
const renderedVideos = videoArray
|
const renderedVideos = videoArray
|
||||||
.map((video, index) => {
|
.map((video, index) => {
|
||||||
try {
|
try {
|
||||||
@@ -597,30 +599,24 @@ class bitvidApp {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, create a ?v=... link for middle-click / ctrl+click
|
// Create share URL
|
||||||
const nevent = window.NostrTools.nip19.neventEncode({
|
const nevent = window.NostrTools.nip19.neventEncode({ id: video.id });
|
||||||
id: video.id,
|
const shareUrl = `${window.location.pathname}?v=${encodeURIComponent(nevent)}`;
|
||||||
});
|
|
||||||
const shareUrl = `${
|
|
||||||
window.location.pathname
|
|
||||||
}?v=${encodeURIComponent(nevent)}`;
|
|
||||||
|
|
||||||
|
// Get profile info
|
||||||
const profile = userProfiles.get(video.pubkey) || {
|
const profile = userProfiles.get(video.pubkey) || {
|
||||||
name: "Unknown",
|
name: "Unknown",
|
||||||
picture: `https://robohash.org/${video.pubkey}`,
|
picture: `https://robohash.org/${video.pubkey}`,
|
||||||
};
|
};
|
||||||
const timeAgo = this.formatTimeAgo(video.created_at);
|
const timeAgo = this.formatTimeAgo(video.created_at);
|
||||||
|
|
||||||
// If user is the owner
|
// Determine edit capability
|
||||||
const canEdit = video.pubkey === this.pubkey;
|
const canEdit = video.pubkey === this.pubkey;
|
||||||
|
const highlightClass = video.isPrivate && canEdit
|
||||||
// If it's private + user owns it => highlight with a special border
|
|
||||||
const highlightClass =
|
|
||||||
video.isPrivate && canEdit
|
|
||||||
? "border-2 border-yellow-500"
|
? "border-2 border-yellow-500"
|
||||||
: "border-none"; // normal case
|
: "border-none";
|
||||||
|
|
||||||
// Gear menu if canEdit
|
// If user can edit, show gear menu
|
||||||
const gearMenu = canEdit
|
const gearMenu = canEdit
|
||||||
? `
|
? `
|
||||||
<div class="relative inline-block ml-3 overflow-visible">
|
<div class="relative inline-block ml-3 overflow-visible">
|
||||||
@@ -635,7 +631,6 @@ class bitvidApp {
|
|||||||
class="w-5 h-5"
|
class="w-5 h-5"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<!-- The dropdown appears above the gear (bottom-full) -->
|
|
||||||
<div
|
<div
|
||||||
id="settingsDropdown-${index}"
|
id="settingsDropdown-${index}"
|
||||||
class="hidden absolute right-0 bottom-full mb-2 w-32 rounded-md shadow-lg bg-gray-800 ring-1 ring-black ring-opacity-5 z-50"
|
class="hidden absolute right-0 bottom-full mb-2 w-32 rounded-md shadow-lg bg-gray-800 ring-1 ring-black ring-opacity-5 z-50"
|
||||||
@@ -659,13 +654,10 @@ class bitvidApp {
|
|||||||
`
|
`
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
// Instead of a <div onclick="..."> for the thumbnail, we use <a>
|
// Main video card
|
||||||
// This allows middle-click or ctrl+click to open shareUrl in a new tab,
|
|
||||||
// while left-click is prevented => opens modal
|
|
||||||
return `
|
return `
|
||||||
<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}">
|
||||||
|
|
||||||
<!-- VIDEO THUMBNAIL via <a> -->
|
|
||||||
<a
|
<a
|
||||||
href="${shareUrl}"
|
href="${shareUrl}"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -677,40 +669,32 @@ class bitvidApp {
|
|||||||
app.playVideo('${encodeURIComponent(video.magnet)}');
|
app.playVideo('${encodeURIComponent(video.magnet)}');
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
${
|
<img
|
||||||
video.thumbnail
|
src="assets/jpg/video-thumbnail-fallback.jpg"
|
||||||
? `<img
|
data-real-src="${this.escapeHTML(video.thumbnail)}"
|
||||||
src="${this.escapeHTML(video.thumbnail)}"
|
|
||||||
alt="${this.escapeHTML(video.title)}"
|
alt="${this.escapeHTML(video.title)}"
|
||||||
class="w-full h-full object-cover"
|
class="w-full h-full object-cover"
|
||||||
>`
|
onload="
|
||||||
: `<div class="flex items-center justify-center h-full bg-gray-800">
|
const realSrc = this.getAttribute('data-real-src');
|
||||||
<svg class="w-16 h-16 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
if (realSrc) {
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
const testImg = new Image();
|
||||||
d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
|
testImg.onload = () => { this.src = realSrc; };
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
testImg.src = realSrc;
|
||||||
d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
</div>`
|
|
||||||
}
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
<div class="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-20 transition-opacity duration-300"></div>
|
<div class="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-20 transition-opacity duration-300"></div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- CARD INFO -->
|
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<!-- TITLE -->
|
|
||||||
<h3
|
<h3
|
||||||
class="text-lg font-bold text-white line-clamp-2 hover:text-blue-400 cursor-pointer mb-3"
|
class="text-lg font-bold text-white line-clamp-2 hover:text-blue-400 cursor-pointer mb-3"
|
||||||
onclick="app.playVideo('${encodeURIComponent(
|
onclick="app.playVideo('${encodeURIComponent(video.magnet)}')"
|
||||||
video.magnet
|
|
||||||
)}')"
|
|
||||||
>
|
>
|
||||||
${this.escapeHTML(video.title)}
|
${this.escapeHTML(video.title)}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<!-- CREATOR info + gear icon -->
|
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<!-- Left: Avatar & user/time -->
|
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<div class="w-8 h-8 rounded-full bg-gray-700 overflow-hidden">
|
<div class="w-8 h-8 rounded-full bg-gray-700 overflow-hidden">
|
||||||
<img
|
<img
|
||||||
@@ -728,7 +712,6 @@ class bitvidApp {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Right: gearMenu if user owns the video -->
|
|
||||||
${gearMenu}
|
${gearMenu}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user