mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
refactor(dedup): consolidate byte / sanitize / clock / album-duration helpers (Phase L, part 2) (#692)
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).
This commit is contained in:
committed by
GitHub
parent
0153435787
commit
4b1dd3c29f
@@ -13,31 +13,8 @@ import { copyEntityShareLink } from '../utils/share/copyEntityShareLink';
|
||||
import { showToast } from '../utils/ui/toast';
|
||||
import { isAlbumRecentlyAdded } from '../utils/albumRecency';
|
||||
import { formatLongDuration } from '../utils/format/formatDuration';
|
||||
|
||||
function formatSize(bytes?: number): string {
|
||||
if (!bytes) return '';
|
||||
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
||||
}
|
||||
|
||||
function sanitizeHtml(html: string): string {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, 'text/html');
|
||||
doc.querySelectorAll('script, style, iframe, object, embed, form, input, button, select, base, meta, link').forEach(el => el.remove());
|
||||
doc.querySelectorAll('*').forEach(el => {
|
||||
Array.from(el.attributes).forEach(attr => {
|
||||
const name = attr.name.toLowerCase();
|
||||
const val = attr.value.toLowerCase().trim();
|
||||
if (
|
||||
name.startsWith('on') ||
|
||||
(name === 'href' && (val.startsWith('javascript:') || val.startsWith('data:'))) ||
|
||||
(name === 'src' && (val.startsWith('javascript:') || val.startsWith('data:')))
|
||||
) {
|
||||
el.removeAttribute(attr.name);
|
||||
}
|
||||
});
|
||||
});
|
||||
return doc.body.innerHTML;
|
||||
}
|
||||
import { formatMb } from '../utils/format/formatBytes';
|
||||
import { sanitizeHtml } from '../utils/sanitizeHtml';
|
||||
|
||||
function BioModal({ bio, onClose }: { bio: string; onClose: () => void }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -372,7 +349,7 @@ export default function AlbumHeader({
|
||||
</div>
|
||||
) : (
|
||||
<button className="btn btn-ghost" id="album-download-btn" onClick={onDownload}>
|
||||
<Download size={16} /> {t('albumDetail.download')}{totalSize > 0 ? ` · ${formatSize(totalSize)}` : ''}
|
||||
<Download size={16} /> {t('albumDetail.download')}{totalSize > 0 ? ` · ${formatMb(totalSize)}` : ''}
|
||||
</button>
|
||||
)}
|
||||
{offlineStatus === 'downloading' && offlineProgress ? (
|
||||
|
||||
Reference in New Issue
Block a user