feat(ui): improve podcast display in playlist and podcast views

- Show podcast-aware album link in playlist (navigates to podcast channel page)
- Show '-' instead of '[Unknown Artist]' for podcast episodes with no artist
- Use best-resolution image URL in podcast list view
- Add srcSet/sizes for responsive cover images in podcast grid and show views
This commit is contained in:
Jiho Andrew Lee 2026-04-28 16:34:27 +09:00
commit 3ce6141887
4 changed files with 31 additions and 3 deletions

View file

@ -57,7 +57,10 @@ AlbumOrChannelLinkField.defaultProps = { addLabel: true, sortBy: 'album' }
const PodcastAwareArtistField = (props) => {
const record = props.record
if (record?.genre === 'Podcast' && !record?.artist) {
const isPodcast = record?.genre === 'Podcast'
const hasNoRealArtist =
!record?.artist || record?.artist === '[Unknown Artist]'
if (isPodcast && hasNoRealArtist) {
return <span>-</span>
}
return <ArtistLinkField {...props} />

View file

@ -42,6 +42,11 @@ const useStyles = makeStyles((theme) => ({
},
}))
const buildSrcSet = (images) => {
if (!images || images.length === 0) return undefined
return images.map((img) => `${img.url} ${img.width}w`).join(', ')
}
const getColsForWidth = (width) => {
if (width === 'xs') return 2
if (width === 'sm') return 3
@ -67,7 +72,13 @@ const PodcastGridView = ({ width, ...props }) => {
<div className={classes.tileContainer}>
<Link className={classes.link} to={linkToRecord(basePath, id, 'show')}>
{record.imageUrl ? (
<img src={record.imageUrl} alt={record.title} className={classes.cover} />
<img
src={record.imageUrl}
srcSet={buildSrcSet(record.images)}
sizes="(max-width: 600px) 50vw, (max-width: 960px) 33vw, (max-width: 1280px) 25vw, 20vw"
alt={record.title}
className={classes.cover}
/>
) : (
<div className={classes.placeholder}>
<MicIcon className={classes.placeholderIcon} style={{ fontSize: 48, color: '#888' }} />

View file

@ -42,11 +42,18 @@ const PodcastFilter = (props) => (
</Filter>
)
const bestImageUrl = (record, targetWidth) => {
if (!record.images || record.images.length === 0) return record.imageUrl
const sorted = [...record.images].sort((a, b) => a.width - b.width)
const best = sorted.find((img) => img.width >= targetWidth) || sorted[sorted.length - 1]
return best ? best.url : record.imageUrl
}
const CoverArtField = ({ record }) => {
if (!record) return null
if (record.imageUrl) {
return (
<Avatar src={record.imageUrl} variant="rounded" style={{ width: 55, height: 55 }} alt={record.title} />
<Avatar src={bestImageUrl(record, 55)} variant="rounded" style={{ width: 55, height: 55 }} alt={record.title} />
)
}
return (

View file

@ -88,6 +88,11 @@ const useStyles = makeStyles((theme) => ({
tableWrapper: { marginTop: theme.spacing(2), overflowX: 'auto' },
}))
const buildSrcSet = (images) => {
if (!images || images.length === 0) return undefined
return images.map((img) => `${img.url} ${img.width}w`).join(', ')
}
const formatDuration = (seconds) => {
if (!seconds) return ''
const h = Math.floor(seconds / 3600)
@ -153,6 +158,8 @@ const PodcastShow = (props) => {
{record.imageUrl ? (
<img
src={record.imageUrl}
srcSet={buildSrcSet(record.images)}
sizes="192px"
alt={record.title}
style={{ width: '100%', height: '100%', objectFit: 'cover', borderRadius: 4 }}
/>