mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2025-09-09 23:48:44 +00:00
fixed html header issue and forced 16:9 thumbnail aspect
This commit is contained in:
@@ -472,3 +472,22 @@ footer a:hover {
|
|||||||
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create a container that preserves a 16:9 aspect ratio via padding-top. */
|
||||||
|
/* Force 16:9 ratio using padding-top technique */
|
||||||
|
.ratio-16-9 {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 56.25%; /* 16:9 => 9/16 = 0.5625 => 56.25% */
|
||||||
|
background-color: #1e293b; /* fallback background if image doesn't load */
|
||||||
|
}
|
||||||
|
|
||||||
|
.ratio-16-9 > img {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
107
src/js/app.js
107
src/js/app.js
@@ -549,26 +549,23 @@ class bitvidApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const videoArray = Array.isArray(videos) ? videos : [videos];
|
const videoArray = Array.isArray(videos) ? videos : [videos];
|
||||||
|
|
||||||
if (videoArray.length === 0) {
|
if (videoArray.length === 0) {
|
||||||
console.error("VIDEO ARRAY IS EMPTY");
|
console.error("VIDEO ARRAY IS EMPTY");
|
||||||
this.videoList.innerHTML = `<p class="text-center text-gray-500">No videos available.</p>`;
|
this.videoList.innerHTML = `<p class="text-center text-gray-500">No videos available.</p>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by creation date
|
// Sort newest first
|
||||||
videoArray.sort((a, b) => b.created_at - a.created_at);
|
videoArray.sort((a, b) => b.created_at - a.created_at);
|
||||||
|
|
||||||
|
// 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) {
|
||||||
const profile = JSON.parse(userEvents[0].content);
|
const profile = JSON.parse(userEvents[0].content);
|
||||||
userProfiles.set(pubkey, {
|
userProfiles.set(pubkey, {
|
||||||
@@ -590,7 +587,7 @@ class bitvidApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build video cards
|
// Build each video card
|
||||||
const renderedVideos = videoArray
|
const renderedVideos = videoArray
|
||||||
.map((video, index) => {
|
.map((video, index) => {
|
||||||
try {
|
try {
|
||||||
@@ -599,24 +596,24 @@ class bitvidApp {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create share URL
|
// Create a share URL
|
||||||
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)}`;
|
||||||
|
|
||||||
// Get profile info
|
// Gather 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);
|
||||||
|
|
||||||
// Determine edit capability
|
// Check if user can edit
|
||||||
const canEdit = video.pubkey === this.pubkey;
|
const canEdit = video.pubkey === this.pubkey;
|
||||||
const highlightClass = video.isPrivate && canEdit
|
const highlightClass = video.isPrivate && canEdit
|
||||||
? "border-2 border-yellow-500"
|
? "border-2 border-yellow-500"
|
||||||
: "border-none";
|
: "border-none";
|
||||||
|
|
||||||
// If user can edit, show gear menu
|
// Gear menu if canEdit
|
||||||
const gearMenu = canEdit
|
const gearMenu = canEdit
|
||||||
? `
|
? `
|
||||||
<div class="relative inline-block ml-3 overflow-visible">
|
<div class="relative inline-block ml-3 overflow-visible">
|
||||||
@@ -654,78 +651,78 @@ class bitvidApp {
|
|||||||
`
|
`
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
// Main video card
|
// Build the card HTML
|
||||||
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}">
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="${shareUrl}"
|
href="${shareUrl}"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="aspect-w-16 aspect-h-9 bg-gray-800 cursor-pointer relative group block"
|
class="block cursor-pointer relative group"
|
||||||
style="display: block;"
|
onclick="if (event.button === 0 && !event.ctrlKey && !event.metaKey) {
|
||||||
onclick="if (event.button === 0 && !event.ctrlKey && !event.metaKey) {
|
event.preventDefault();
|
||||||
event.preventDefault();
|
app.playVideo('${encodeURIComponent(video.magnet)}');
|
||||||
app.playVideo('${encodeURIComponent(video.magnet)}');
|
}"
|
||||||
}"
|
>
|
||||||
>
|
<!-- Force 16:9 ratio with custom CSS -->
|
||||||
|
<div class="ratio-16-9">
|
||||||
<img
|
<img
|
||||||
src="assets/jpg/video-thumbnail-fallback.jpg"
|
src="assets/jpg/video-thumbnail-fallback.jpg"
|
||||||
data-real-src="${this.escapeHTML(video.thumbnail)}"
|
data-real-src="${this.escapeHTML(video.thumbnail)}"
|
||||||
alt="${this.escapeHTML(video.title)}"
|
alt="${this.escapeHTML(video.title)}"
|
||||||
class="w-full h-full object-cover"
|
|
||||||
onload="
|
onload="
|
||||||
const realSrc = this.getAttribute('data-real-src');
|
const realSrc = this.getAttribute('data-real-src');
|
||||||
if (realSrc) {
|
if (realSrc) {
|
||||||
|
const that = this;
|
||||||
const testImg = new Image();
|
const testImg = new Image();
|
||||||
testImg.onload = () => { this.src = realSrc; };
|
testImg.onload = function() {
|
||||||
|
that.src = realSrc;
|
||||||
|
};
|
||||||
testImg.src = realSrc;
|
testImg.src = realSrc;
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<div class="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-20 transition-opacity duration-300"></div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<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(video.magnet)}')"
|
onclick="app.playVideo('${encodeURIComponent(video.magnet)}')"
|
||||||
>
|
>
|
||||||
${this.escapeHTML(video.title)}
|
${this.escapeHTML(video.title)}
|
||||||
</h3>
|
</h3>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center justify-between">
|
<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
|
src="${this.escapeHTML(profile.picture)}"
|
||||||
src="${this.escapeHTML(profile.picture)}"
|
alt="${profile.name}"
|
||||||
alt="${profile.name}"
|
class="w-full h-full object-cover"
|
||||||
class="w-full h-full object-cover"
|
>
|
||||||
>
|
</div>
|
||||||
</div>
|
<div class="min-w-0">
|
||||||
<div class="min-w-0">
|
<p class="text-sm text-gray-400 hover:text-gray-300 cursor-pointer">
|
||||||
<p class="text-sm text-gray-400 hover:text-gray-300 cursor-pointer">
|
${this.escapeHTML(profile.name)}
|
||||||
${this.escapeHTML(profile.name)}
|
</p>
|
||||||
</p>
|
<div class="flex items-center text-xs text-gray-500 mt-1">
|
||||||
<div class="flex items-center text-xs text-gray-500 mt-1">
|
<span>${timeAgo}</span>
|
||||||
<span>${timeAgo}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${gearMenu}
|
|
||||||
</div>
|
</div>
|
||||||
|
${gearMenu}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error(`Error processing video ${index}:`, error);
|
console.error(`Error processing video ${index}:`, err);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.filter((html) => html.length > 0);
|
.filter((html) => html.length > 0);
|
||||||
|
|
||||||
console.log("Rendered videos:", renderedVideos.length);
|
|
||||||
|
|
||||||
if (renderedVideos.length === 0) {
|
if (renderedVideos.length === 0) {
|
||||||
this.videoList.innerHTML = `<p class="text-center text-gray-500">No valid videos to display.</p>`;
|
this.videoList.innerHTML = `<p class="text-center text-gray-500">No valid videos to display.</p>`;
|
||||||
return;
|
return;
|
||||||
|
Reference in New Issue
Block a user