mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
4b1dd3c29f
Findings 5-8 of the dedup audit: - F5 byte formatters: appUpdaterHelpers.fmtBytes + ZipDownloadOverlay .formatMB route through the existing formatBytes; a new formatMb (always-MB) backs playlistDetailHelpers.formatSize, AlbumHeader and the 4 inline DeviceSyncPreSyncModal expressions. SongInfoModal.format Size is intentionally left — it uses decimal (1e6) divisors, not 1024. - F6 sanitizeHtml: extracted to utils/sanitizeHtml.ts; AlbumHeader, ComposerDetail and the (now-empty, deleted) artistDetailHelpers use it directly. nowPlayingHelpers keeps its own export but now delegates to the shared sanitiser and only adds its trailing-link strip on top. - F7 album duration: BecauseYouLikeRail's formatAlbumDuration drops in favour of the shared formatHumanHoursMinutes. Behaviour note: total minutes now floor instead of round (<=1 min display difference, matches every other caller). - F8 clock time: extracted to utils/format/formatClockTime.ts; PlaybackDelayModal + QueueHeader use it (toLocaleTimeString and Intl.DateTimeFormat produced identical output). Behaviour preserved except the two explicitly noted divergences (F7 round->floor; F5 appUpdater/Zip now show GB above 1 GB instead of a large MB number).
40 lines
1.3 KiB
TypeScript
40 lines
1.3 KiB
TypeScript
import type { SubsonicSong } from '../../api/subsonicTypes';
|
|
import { formatHumanHoursMinutes } from '../format/formatHumanDuration';
|
|
import { formatMb } from '../format/formatBytes';
|
|
|
|
export function sanitizeFilename(name: string): string {
|
|
return name
|
|
.replace(/[/\\?%*:|"<>]/g, '-')
|
|
.replace(/\.{2,}/g, '.')
|
|
.replace(/^[\s.]+|[\s.]+$/g, '')
|
|
.substring(0, 200) || 'download';
|
|
}
|
|
|
|
export function formatSize(bytes?: number): string {
|
|
return bytes ? formatMb(bytes) : '';
|
|
}
|
|
|
|
export function totalDurationLabel(songs: SubsonicSong[]): string {
|
|
const total = songs.reduce((acc, s) => acc + (s.duration ?? 0), 0);
|
|
return formatHumanHoursMinutes(total);
|
|
}
|
|
|
|
export const SMART_PREFIX = 'psy-smart-';
|
|
|
|
export function isSmartPlaylistName(name: string): boolean {
|
|
return (name ?? '').toLowerCase().startsWith(SMART_PREFIX);
|
|
}
|
|
|
|
export function displayPlaylistName(name: string): string {
|
|
const n = name ?? '';
|
|
if (isSmartPlaylistName(n)) return n.slice(SMART_PREFIX.length);
|
|
return n;
|
|
}
|
|
|
|
export function codecLabel(song: SubsonicSong, showBitrate: boolean): string {
|
|
const parts: string[] = [];
|
|
if (song.suffix) parts.push(song.suffix.toUpperCase());
|
|
if (showBitrate && song.bitRate) parts.push(`${song.bitRate} kbps`);
|
|
return parts.join(' · ');
|
|
}
|