89 lines
2.4 KiB
JavaScript
89 lines
2.4 KiB
JavaScript
export function normalizeRelayUrl(url) {
|
|
if (!url) return '';
|
|
let normalized = url.trim().toLowerCase();
|
|
if (!normalized) return '';
|
|
|
|
if (!normalized.startsWith('ws://') && !normalized.startsWith('wss://')) {
|
|
normalized = 'wss://' + normalized;
|
|
}
|
|
|
|
while (normalized.endsWith('/')) {
|
|
normalized = normalized.slice(0, -1);
|
|
}
|
|
|
|
return normalized;
|
|
}
|
|
|
|
/**
|
|
* Extracts and normalizes photo data from NIP-360 (Place Photos) events.
|
|
* Sorts chronologically and guarantees the first landscape photo (or first portrait) is at index 0.
|
|
*
|
|
* @param {Array} events NIP-360 events
|
|
* @returns {Array} Array of photo objects
|
|
*/
|
|
export function parsePlacePhotos(events) {
|
|
if (!events || events.length === 0) return [];
|
|
|
|
// Sort by created_at ascending (oldest first)
|
|
const sortedEvents = [...events].sort((a, b) => a.created_at - b.created_at);
|
|
|
|
const allPhotos = [];
|
|
|
|
for (const event of sortedEvents) {
|
|
// Find all imeta tags
|
|
const imetas = event.tags.filter((t) => t[0] === 'imeta');
|
|
for (const imeta of imetas) {
|
|
let url = null;
|
|
let thumbUrl = null;
|
|
let blurhash = null;
|
|
let isLandscape = false;
|
|
let aspectRatio = 16 / 9; // default
|
|
|
|
for (const tag of imeta.slice(1)) {
|
|
if (tag.startsWith('url ')) {
|
|
url = tag.substring(4);
|
|
} else if (tag.startsWith('thumb ')) {
|
|
thumbUrl = tag.substring(6);
|
|
} else if (tag.startsWith('blurhash ')) {
|
|
blurhash = tag.substring(9);
|
|
} else if (tag.startsWith('dim ')) {
|
|
const dimStr = tag.substring(4);
|
|
const [width, height] = dimStr.split('x').map(Number);
|
|
if (width && height) {
|
|
aspectRatio = width / height;
|
|
if (width > height) {
|
|
isLandscape = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (url) {
|
|
allPhotos.push({
|
|
eventId: event.id,
|
|
pubkey: event.pubkey,
|
|
createdAt: event.created_at,
|
|
url,
|
|
thumbUrl,
|
|
blurhash,
|
|
isLandscape,
|
|
aspectRatio,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (allPhotos.length === 0) return [];
|
|
|
|
// Find the first landscape photo
|
|
const firstLandscapeIndex = allPhotos.findIndex((p) => p.isLandscape);
|
|
|
|
if (firstLandscapeIndex > 0) {
|
|
// Move the first landscape photo to the front
|
|
const [firstLandscape] = allPhotos.splice(firstLandscapeIndex, 1);
|
|
allPhotos.unshift(firstLandscape);
|
|
}
|
|
|
|
return allPhotos;
|
|
}
|