Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 36 additions & 6 deletions src/feeds/rss/references/rss-ns.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,24 @@
}
]
},
"images": {
"srcset": "https://example.com/images/episode-1000.jpg 1000w, https://example.com/images/episode-600.jpg 600w"
},
"images": [
{
"href": "https://example.com/images/episode-artwork.jpg",
"alt": "Episode 1 Artwork",
"aspectRatio": "1/1",
"width": 3000,
"purpose": "artwork"
},
{
"href": "https://example.com/images/episode-social.jpg",
"alt": "Episode 1 Social Preview",
"aspectRatio": "16/9",
"width": 1200,
"height": 630,
"type": "image/jpeg",
"purpose": "social"
}
],
"socialInteracts": [
{
"protocol": "twitter",
Expand Down Expand Up @@ -1254,9 +1269,24 @@
]
},
"medium": "podcast",
"images": {
"srcset": "https://example.com/images/cover-1000.jpg 1000w, https://example.com/images/cover-600.jpg 600w"
},
"images": [
{
"href": "https://example.com/images/cover-artwork.jpg",
"alt": "Podcast Cover Art",
"aspectRatio": "1/1",
"width": 3000,
"purpose": "artwork"
},
{
"href": "https://example.com/images/cover-social.jpg",
"alt": "Social Media Preview",
"aspectRatio": "16/9",
"width": 1200,
"height": 630,
"type": "image/jpeg",
"purpose": "social"
}
],
"liveItems": [
{
"persons": [
Expand Down
6 changes: 4 additions & 2 deletions src/feeds/rss/references/rss-ns.xml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@
<podcast:valueRecipient name="Producer" type="node" address="03ae9f91a0cb8ff43840e3c322c4c61f019d8c1c3cea15a25cfc425ac605e61a4a" split="10"/>
</podcast:value>
<podcast:medium>podcast</podcast:medium>
<podcast:images srcset="https://example.com/images/cover-1000.jpg 1000w, https://example.com/images/cover-600.jpg 600w"/>
<podcast:image href="https://example.com/images/cover-artwork.jpg" alt="Podcast Cover Art" aspect-ratio="1/1" width="3000" purpose="artwork"/>
<podcast:image href="https://example.com/images/cover-social.jpg" alt="Social Media Preview" aspect-ratio="16/9" width="1200" height="630" type="image/jpeg" purpose="social"/>
<podcast:liveItem status="live" start="2025-04-30T08:00:00.000Z" end="2025-04-30T09:00:00.000Z">
<podcast:person group="host">Jane Smith</podcast:person>
<podcast:contentLink href="https://example.com/live/chat">Live Chat</podcast:contentLink>
Expand Down Expand Up @@ -428,7 +429,8 @@
<podcast:valueRecipient name="Host" type="node" address="02d5c1bf8b940dc9cadca86d1b0a3c37fbe39cee83420ef254acd7d8e5edf5f16e" split="90"/>
<podcast:valueRecipient name="Guest" type="node" address="03ae9f91a0cb8ff43840e3c322c4c61f019d8c1c3cea15a25cfc425ac605e61a4a" split="10"/>
</podcast:value>
<podcast:images srcset="https://example.com/images/episode-1000.jpg 1000w, https://example.com/images/episode-600.jpg 600w"/>
<podcast:image href="https://example.com/images/episode-artwork.jpg" alt="Episode 1 Artwork" aspect-ratio="1/1" width="3000" purpose="artwork"/>
<podcast:image href="https://example.com/images/episode-social.jpg" alt="Episode 1 Social Preview" aspect-ratio="16/9" width="1200" height="630" type="image/jpeg" purpose="social"/>
<podcast:socialInteract uri="https://twitter.com/examplepodcast/status/123456789" protocol="twitter" accountId="@examplepodcast" accountUrl="https://twitter.com/examplepodcast"/>
<podcast:socialInteract uri="https://podcastindex.social/@dave/123456789" protocol="mastodon" accountId="@[email protected]" accountUrl="https://podcastindex.social/@examplepodcast"/>
<podcast:txt purpose="transcript">{"version": "1.0.0", "chapters": []}</podcast:txt>
Expand Down
15 changes: 13 additions & 2 deletions src/namespaces/podcast/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export namespace PodcastNs {
license?: License
alternateEnclosures?: Array<AlternateEnclosure>
values?: Array<Value>
images?: Images
images?: Array<Image>
socialInteracts?: Array<SocialInteract>
txts?: Array<Txt>
chat?: Chat
Expand Down Expand Up @@ -135,10 +135,21 @@ export namespace PodcastNs {
fee?: boolean
}

/** @internal Legacy type for parsing podcast:images with srcset attribute. */
export type Images = {
srcset?: string
}

export type Image = {
href: string
alt?: string
aspectRatio?: string
width?: number
height?: number
type?: string
purpose?: string
}

export type LiveItem<TDate extends DateLike> = BaseItem & {
status: string
start: TDate // Date: ISO 8601.
Expand Down Expand Up @@ -226,7 +237,7 @@ export namespace PodcastNs {
guid?: string
values?: Array<Value>
medium?: string
images?: Images
images?: Array<Image>
liveItems?: Array<LiveItem<TDate>>
blocks?: Array<Block>
txts?: Array<Txt>
Expand Down
69 changes: 50 additions & 19 deletions src/namespaces/podcast/generate/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
generateEpisode,
generateFeed,
generateFunding,
generateImages,
generateImage,
generateIntegrity,
generateItem,
generateLicense,
Expand Down Expand Up @@ -664,20 +664,43 @@ describe('generateValue', () => {
})
})

describe('generateImages', () => {
it('should generate images with srcset', () => {
describe('generateImage', () => {
it('should generate image with all properties', () => {
const value = {
srcset: 'https://example.com/image-400.jpg 400w, https://example.com/image-800.jpg 800w',
href: 'https://example.com/image.jpg',
alt: 'Example Image',
aspectRatio: '16/9',
width: 1200,
height: 630,
type: 'image/jpeg',
purpose: 'social',
}
const expected = {
'@srcset': 'https://example.com/image-400.jpg 400w, https://example.com/image-800.jpg 800w',
'@href': 'https://example.com/image.jpg',
'@alt': 'Example Image',
'@aspect-ratio': '16/9',
'@width': 1200,
'@height': 630,
'@type': 'image/jpeg',
'@purpose': 'social',
}

expect(generateImages(value)).toEqual(expected)
expect(generateImage(value)).toEqual(expected)
})

it('should generate image with only required href', () => {
const value = {
href: 'https://example.com/image.jpg',
}
const expected = {
'@href': 'https://example.com/image.jpg',
}

expect(generateImage(value)).toEqual(expected)
})

it('should handle non-object inputs', () => {
expect(generateImages(undefined)).toBeUndefined()
expect(generateImage(undefined)).toBeUndefined()
})
})

Expand Down Expand Up @@ -1068,9 +1091,11 @@ describe('generateBaseItem', () => {
type: 'lightning',
method: 'keysend',
},
images: {
srcset: 'https://example.com/image.jpg',
},
images: [
{
href: 'https://example.com/image.jpg',
},
],
socialInteracts: [
{
protocol: 'activitypub',
Expand Down Expand Up @@ -1126,9 +1151,11 @@ describe('generateBaseItem', () => {
'@type': 'lightning',
'@method': 'keysend',
},
'podcast:images': {
'@srcset': 'https://example.com/image.jpg',
},
'podcast:image': [
{
'@href': 'https://example.com/image.jpg',
},
],
'podcast:socialInteract': [
{
'@protocol': 'activitypub',
Expand Down Expand Up @@ -1309,9 +1336,11 @@ describe('generateFeed', () => {
method: 'keysend',
},
medium: 'podcast',
images: {
srcset: 'https://example.com/image.jpg',
},
images: [
{
href: 'https://example.com/image.jpg',
},
],
liveItems: [
{
status: 'live',
Expand Down Expand Up @@ -1384,9 +1413,11 @@ describe('generateFeed', () => {
'@method': 'keysend',
},
'podcast:medium': 'podcast',
'podcast:images': {
'@srcset': 'https://example.com/image.jpg',
},
'podcast:image': [
{
'@href': 'https://example.com/image.jpg',
},
],
'podcast:liveItem': [
{
'@status': 'live',
Expand Down
16 changes: 11 additions & 5 deletions src/namespaces/podcast/generate/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const generateBaseItem: GenerateUtil<PodcastNs.BaseItem> = (baseItem) =>
generateAlternateEnclosure,
),
'podcast:value': generateArrayOrSingular(baseItem.values, baseItem.value, generateValue),
'podcast:images': generateImages(baseItem.images),
'podcast:image': trimArray(baseItem.images, generateImage),
'podcast:socialInteract': trimArray(baseItem.socialInteracts, generateSocialInteract),
'podcast:txt': trimArray(baseItem.txts, generateTxt),
'podcast:chat': generateSingularOrArray(baseItem.chat, baseItem.chats, generateChat),
Expand Down Expand Up @@ -303,13 +303,19 @@ export const generateValue: GenerateUtil<PodcastNs.Value> = (value) => {
return trimObject(valueOut)
}

export const generateImages: GenerateUtil<PodcastNs.Images> = (images) => {
if (!isObject(images)) {
export const generateImage: GenerateUtil<PodcastNs.Image> = (image) => {
if (!isObject(image)) {
return
}

const value = {
'@srcset': generatePlainString(images.srcset),
'@href': generatePlainString(image.href),
'@alt': generatePlainString(image.alt),
'@aspect-ratio': generatePlainString(image.aspectRatio),
'@width': generateNumber(image.width),
'@height': generateNumber(image.height),
'@type': generatePlainString(image.type),
'@purpose': generatePlainString(image.purpose),
}

return trimObject(value)
Expand Down Expand Up @@ -492,7 +498,7 @@ export const generateFeed: GenerateUtil<PodcastNs.Feed<DateLike>> = (feed) => {
'podcast:guid': generateCdataString(feed.guid),
'podcast:value': generateArrayOrSingular(feed.values, feed.value, generateValue),
'podcast:medium': generateCdataString(feed.medium),
'podcast:images': generateImages(feed.images),
'podcast:image': trimArray(feed.images, generateImage),
'podcast:liveItem': trimArray(feed.liveItems, generateLiveItem),
'podcast:block': trimArray(feed.blocks, generateBlock),
'podcast:txt': trimArray(feed.txts, generateTxt),
Expand Down
Loading