Files
client/greyscale/src/utils.js
T
2026-04-17 16:52:51 -04:00

65 lines
2.0 KiB
JavaScript

export function formatDuration(seconds) {
if (!Number.isFinite(seconds) || seconds < 0) return '0:00';
const m = Math.floor(seconds / 60);
const s = Math.floor(seconds % 60);
return `${m}:${String(s).padStart(2, '0')}`;
}
export function formatDate(dateStr) {
if (!dateStr) return '';
const date = new Date(dateStr);
if (Number.isNaN(date.getTime())) return '';
return date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
}
export function formatYear(dateStr) {
if (!dateStr) return '';
const date = new Date(dateStr);
if (Number.isNaN(date.getTime())) return '';
return String(date.getFullYear());
}
export function escapeHtml(value) {
return String(value)
.replace(/&/g, '\u0026amp;')
.replace(/</g, '\u0026lt;')
.replace(/>/g, '\u0026gt;')
.replace(/"/g, '\u0026quot;')
.replace(/\u0027/g, '\u0026#39;');
}
export function getTrackArtists(track) {
if (!track || typeof track !== 'object') return 'Unknown artist';
if (track.artist?.name) return track.artist.name;
if (Array.isArray(track.artists) && track.artists.length > 0) {
return track.artists.map((a) => a?.name).filter(Boolean).join(', ') || 'Unknown artist';
}
if (typeof track.artist === 'string' && track.artist.trim()) return track.artist;
return 'Unknown artist';
}
export function getTrackTitle(track) {
return track?.title || 'Unknown title';
}
export function sanitizeForFilename(str) {
return String(str || '')
.replace(/[\\/:*?"<>|]/g, '_')
.replace(/\s+/g, ' ')
.trim();
}
export function buildTrackFilename(track, extension = 'flac') {
const artists = sanitizeForFilename(getTrackArtists(track));
const title = sanitizeForFilename(getTrackTitle(track));
return `${artists} - ${title}.${extension}`;
}
export function debounce(fn, wait = 250) {
let t = null;
return (...args) => {
if (t) clearTimeout(t);
t = setTimeout(() => fn(...args), wait);
};
}