Knut Melvær
Knut is a principal developer marketing manager at Sanity.io
Schemas for running a podcast backend on Sanity.io
// podcast.js
import languages from './languages';
export default {
name: 'podcast',
title: 'Podcast',
description: 'Create and configure a podcast',
type: 'document',
fields: [
{
name: 'title',
type: 'string',
required: true,
description:
'Remember that if your title is too long, it may be truncated in various podcatchers-'
},
{
name: 'subtitle',
type: 'string',
description: 'That catchy tagline.'
},
{
name: 'slug',
title: 'Podcast slug',
type: 'slug',
description: 'For when you need to refer to your podcast in a url.',
options: {
source: 'title',
slugify: input =>
input
.toLowerCase()
.replace(/\s+/g, '-')
.slice(0, 200)
}
},
{
name: 'description',
type: 'text',
required: true,
description:
'What is this podcast about and why should people subscribe to it?'
},
{
name: 'coverArt',
title: 'Cover art',
type: 'image',
required: true,
description:
'The image should be either jpg or png. Preferably 3000 x 3000, minimum 1400 x 1400 pixels.'
},
{
name: 'copyright',
type: 'string',
description: 'Who owns the rights to this podcast?'
},
{
name: 'language',
type: 'string',
description: 'What language is this podcast in?',
options: {
list: languages
}
},
{
name: 'explicit',
type: 'boolean',
description:
'Do you need to warn parents about the content in this podcast? (You can set this for individual episodes to)'
},
{
name: 'itunes',
title: 'iTunes settings',
type: 'itunes',
description: 'iTunes has extra stuff',
}
],
preview: {
select: {
title: 'title',
subtitle: 'subtitle',
description: 'description',
media: 'coverArt'
}
}
};
// iTunes Categories
const categories = [
{ value: "Arts", title: "Arts" },
{ value: "Arts > Design", title: "Arts > Design" },
{ value: "Arts > Fashion & Beauty", title: "Arts > Fashion & Beauty" },
{ value: "Arts > Food", title: "Arts > Food" },
{ value: "Arts > Literature", title: "Arts > Literature" },
{ value: "Arts > Performing Arts", title: "Arts > Performing Arts" },
{ value: "Arts > Visual Arts", title: "Arts > Visual Arts" },
{ value: "Business", title: "Business" },
{ value: "Business > Business News", title: "Business > Business News" },
{ value: "Business > Careers", title: "Business > Careers" },
{ value: "Business > Investing", title: "Business > Investing" },
{ value: "Business > Management & Marketing", title: "Business > Management & Marketing" },
{ value: "Business > Shopping", title: "Business > Shopping" },
{ value: "Comedy", title: "Comedy" },
{ value: "Education", title: "Education" },
{ value: "Education > Education", title: "Education > Education" },
{ value: "Education > Education Technology", title: "Education > Education Technology" },
{ value: "Education > Higher Education", title: "Education > Higher Education" },
{ value: "Education > K-12", title: "Education > K-12" },
{ value: "Education > Language Courses", title: "Education > Language Courses" },
{ value: "Education > Training", title: "Education > Training" },
{ value: "Games & Hobbies", title: "Games & Hobbies" },
{ value: "Games & Hobbies > Automotive", title: "Games & Hobbies > Automotive" },
{ value: "Games & Hobbies > Aviation", title: "Games & Hobbies > Aviation" },
{ value: "Games & Hobbies > Hobbies", title: "Games & Hobbies > Hobbies" },
{ value: "Games & Hobbies > Other Games", title: "Games & Hobbies > Other Games" },
{ value: "Games & Hobbies > Video Games", title: "Games & Hobbies > Video Games" },
{ value: "Government & Organizations", title: "Government & Organizations" },
{ value: "Government & Organizations > Local", title: "Government & Organizations > Local" },
{ value: "Government & Organizations > National", title: "Government & Organizations > National" },
{ value: "Government & Organizations > Non-Profit", title: "Government & Organizations > Non-Profit" },
{ value: "Government & Organizations > Regional", title: "Government & Organizations > Regional" },
{ value: "Health", title: "Health" },
{ value: "Health > Alternative Health", title: "Health > Alternative Health" },
{ value: "Health > Fitness & Nutrition", title: "Health > Fitness & Nutrition" },
{ value: "Health > Self-Help", title: "Health > Self-Help" },
{ value: "Health > Sexuality", title: "Health > Sexuality" },
{ value: "Kids & Family", title: "Kids & Family" },
{ value: "Music", title: "Music" },
{ value: "News & Politics", title: "News & Politics" },
{ value: "Religion & Spirituality", title: "Religion & Spirituality" },
{ value: "Religion & Spirituality > Buddhism", title: "Religion & Spirituality > Buddhism" },
{ value: "Religion & Spirituality > Christianity", title: "Religion & Spirituality > Christianity" },
{ value: "Religion & Spirituality > Hinduism", title: "Religion & Spirituality > Hinduism" },
{ value: "Religion & Spirituality > Islam", title: "Religion & Spirituality > Islam" },
{ value: "Religion & Spirituality > Judaism", title: "Religion & Spirituality > Judaism" },
{ value: "Religion & Spirituality > Other", title: "Religion & Spirituality > Other" },
{ value: "Religion & Spirituality > Spirituality", title: "Religion & Spirituality > Spirituality" },
{ value: "Science & Medicine", title: "Science & Medicine" },
{ value: "Science & Medicine > Medicine", title: "Science & Medicine > Medicine" },
{ value: "Science & Medicine > Natural Sciences", title: "Science & Medicine > Natural Sciences" },
{ value: "Science & Medicine > Social Sciences", title: "Science & Medicine > Social Sciences" },
{ value: "Society & Culture", title: "Society & Culture" },
{ value: "Society & Culture > History", title: "Society & Culture > History" },
{ value: "Society & Culture > Personal Journals", title: "Society & Culture > Personal Journals" },
{ value: "Society & Culture > Philosophy", title: "Society & Culture > Philosophy" },
{ value: "Society & Culture > Places & Travel", title: "Society & Culture > Places & Travel" },
{ value: "Sports & Recreation", title: "Sports & Recreation" },
{ value: "Sports & Recreation > Amateur", title: "Sports & Recreation > Amateur" },
{ value: "Sports & Recreation > College & High School", title: "Sports & Recreation > College & High School" },
{ value: "Sports & Recreation > Outdoor", title: "Sports & Recreation > Outdoor" },
{ value: "Sports & Recreation > Professional", title: "Sports & Recreation > Professional" },
{ value: "Technology", title: "Technology" },
{ value: "Technology > Gadgets", title: "Technology > Gadgets" },
{ value: "Technology > Tech News", title: "Technology > Tech News" },
{ value: "Technology > Podcasting", title: "Technology > Podcasting" },
{ value: "Technology > Software How-To", title: "Technology > Software How-To" },
{ value: "TV & Film", title: "TV & Film" },
];
export default {
name: 'categories',
title: 'Categories',
type: 'object',
description:
'Each podcast can belong to 3 separate categories, and will be ranked separately in each.',
fieldsets: [
{
title: 'Optional categories',
name: 'categories',
options: {
collapsable: true
}
}
],
fields: ['first', 'secondary', 'tertiary'].map((category, index) => ({
name: `${category}Category`,
type: 'string',
description: 'Where should this podcast be organized in iTunes?',
options: {
list: categories
},
fieldset: index ? 'categories' : null
}))
}
export default {
name: 'episode',
title: 'Episode',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
required: true,
description: 'Remember that long titles can be truncated in podcast apps',
type: 'string'
},
{
name: 'podcast',
description: 'Choose podcast(s) to publish this episode in',
type: 'array',
of: [{ type: 'reference', weak: true, to: [{ type: 'podcast' }] }]
},
{
name: 'schedule',
type: 'schedule',
title: 'Publish schedule',
},
{
name: 'file',
title: 'Podcast media file',
description:
'Most podcatchers support .mp3, but other audio-formats may work as well',
type: 'file'
},
{
name: 'fileUrl',
title: 'External location for podcast media file',
description: 'For when you host your podcast media file elsewhere',
type: 'url'
},
{
name: 'duration',
title: 'Duration',
description: 'HH:MM:SS',
type: 'string'
},
{
name: 'subtitle',
type: 'string',
title: 'Subtitle',
},
{
name: 'explicit',
title: 'Explicit content',
type: 'boolean'
},
{
name: 'summary',
title: 'Summary',
description: 'An episode summary is a string containing one or more descriptive sentences summarizing your episode for potential listeners. You can specify up to 4000 characters.',
type: 'text'
},
{
name: 'description',
title: 'Description',
description: `An episode description is a string containing one or more sentences describing your episode to potential listeners. You can specify up to 4000 characters.`,
type: 'text',
validation: Rule => Rule.max(4000)
},
{
name: 'content',
title: 'Content',
description: 'An episode note. Where encoded is a string containing information about your episode.',
type: 'array',
of: [{
type: 'block'
}]
},
{
name: 'linkList',
title: 'Link list',
description: 'A more structured way to add links for show notes. Will be compiled at the end of the episode content field in a podcast RSS feed',
type: 'array',
of: [
{
type: 'linkListItem'
}
]
},
{
name: 'slug',
title: 'Episode slug',
type: 'slug',
description: 'When you need to refer to your podcast episode in a url',
options: {
source: 'title',
slugify: input =>
input
.toLowerCase()
.replace(/\s+/g, '-')
.slice(0, 200)
}
},
{
name: 'tags',
title: 'Tags',
type: 'array',
options: {
layout: 'tags'
},
of: [
{
type: 'string'
}
]
},
{
name: 'itunes',
title: 'iTunes Settings',
type: 'itunesEpisodeSettings',
},
{
name: 'coverArt',
title: 'Cover art',
type: 'image'
},
{
name: 'sponsors',
type: 'array',
title: 'Sponsors',
of: [
{ type: 'sponsorRead' }
]
},
],
orderings: [
{
title: 'Publish Date, New',
name: 'publishDateDesc',
by: [
{field: 'schedule.publish', direction: 'desc'}
]
},
{
title: 'Publish Date, Old',
name: 'publishDateAsc',
by: [
{field: 'schedule.publish', direction: 'asc'}
]
}
],
preview: {
select: {
title: 'title',
subtitle: 'podcast.0.title',
description: 'summary',
media: 'coverArt',
schedule: 'schedule'
},
prepare({title, subtitle, description, media, schedule}) {
return {
title,
esubtitle: `${new Date(schedule.publish).toDateString()} – ${subtitle}`,
description,
media,
}
}
}
};
export default {
name: 'host',
title: 'Host',
type: 'document',
fields: [
{
name: 'name',
title: 'Name',
type: 'string',
},
{
name: 'email',
type: 'email',
},
{
name: 'description',
title: 'Description',
description: 'Describe your host in the most interesting way',
type: 'array',
of: [
{
type: 'block'
}
]
},
{
name: 'image',
type: 'image'
}
]
}
export default {
name: 'itunes',
title: 'iTunes settings',
type: 'object',
description: 'iTunes has extra stuff',
fields: [
{
name: 'author',
type: 'string',
title: 'Author',
description: 'Podcast author, typically the host(s)'
},
{
name: 'owner',
type: 'owner',
title: 'Owner',
},
{
name: 'url',
type: 'url',
description:
'Helpful for when you want to show this podcast in other contexts than iTunes'
},
{
name: 'type',
type: 'string',
description:
'Is this a ongoing (episodic) podcast, or is it structured in seasons?',
options: {
list: [
{
value: 'episodic',
title: 'Episodic'
},
{
value: 'serial',
title: 'Serial'
}
]
}
},
{
name: 'categories',
title: 'Categories',
type: 'categories'
}
]
}
export default {
name: 'itunesEpisodeSettings',
title: 'iTunes Settings',
type: 'object',
fields: [
{
name: 'type',
title: 'Episode type',
type: 'string',
options: {
list: [
{ value: 'full', title: 'Full' },
{ value: 'trailer', title: 'Trailer' },
{ value: 'bonus', title: 'Bonus' }
]
}
},
{
name: 'season',
title: 'Season',
type: 'number'
}
]
}
export default [
{ value: "af", title: "af" },
{ value: "ar", title: "ar" },
{ value: "az", title: "az" },
{ value: "bg", title: "bg" },
{ value: "bn", title: "bn" },
{ value: "bs", title: "bs" },
{ value: "ca", title: "ca" },
{ value: "cs", title: "cs" },
{ value: "cy", title: "cy" },
{ value: "da", title: "da" },
{ value: "de", title: "de" },
{ value: "de-at", title: "de-at" },
{ value: "de-ch", title: "de-ch" },
{ value: "el", title: "el" },
{ value: "en", title: "en" },
{ value: "en-au", title: "en-au" },
{ value: "en-ca", title: "en-ca" },
{ value: "en-gb", title: "en-gb" },
{ value: "en-ie", title: "en-ie" },
{ value: "en-in", title: "en-in" },
{ value: "en-nz", title: "en-nz" },
{ value: "en-us", title: "en-us" },
{ value: "en-za", title: "en-za" },
{ value: "eo", title: "eo" },
{ value: "es", title: "es" },
{ value: "es-419", title: "es-419" },
{ value: "es-ar", title: "es-ar" },
{ value: "es-cl", title: "es-cl" },
{ value: "es-co", title: "es-co" },
{ value: "es-cr", title: "es-cr" },
{ value: "es-ec", title: "es-ec" },
{ value: "es-mx", title: "es-mx" },
{ value: "es-pa", title: "es-pa" },
{ value: "es-pe", title: "es-pe" },
{ value: "es-us", title: "es-us" },
{ value: "es-ve", title: "es-ve" },
{ value: "et", title: "et" },
{ value: "eu", title: "eu" },
{ value: "fa", title: "fa" },
{ value: "fi", title: "fi" },
{ value: "fr", title: "fr" },
{ value: "fr-ca", title: "fr-ca" },
{ value: "fr-ch", title: "fr-ch" },
{ value: "gl", title: "gl" },
{ value: "he", title: "he" },
{ value: "hi", title: "hi" },
{ value: "hi-in", title: "hi-in" },
{ value: "hr", title: "hr" },
{ value: "hu", title: "hu" },
{ value: "id", title: "id" },
{ value: "is", title: "is" },
{ value: "it", title: "it" },
{ value: "it-ch", title: "it-ch" },
{ value: "ja", title: "ja" },
{ value: "km", title: "km" },
{ value: "kn", title: "kn" },
{ value: "ko", title: "ko" },
{ value: "lo", title: "lo" },
{ value: "lt", title: "lt" },
{ value: "lv", title: "lv" },
{ value: "mk", title: "mk" },
{ value: "mn", title: "mn" },
{ value: "mr-in", title: "mr-in" },
{ value: "ms", title: "ms" },
{ value: "nb", title: "nb" },
{ value: "ne", title: "ne" },
{ value: "nl", title: "nl" },
{ value: "nn", title: "nn" },
{ value: "or", title: "or" },
{ value: "pl", title: "pl" },
{ value: "pt", title: "pt" },
{ value: "pt-br", title: "pt-br" },
{ value: "rm", title: "rm" },
{ value: "ro", title: "ro" },
{ value: "ru", title: "ru" },
{ value: "sk", title: "sk" },
{ value: "sl", title: "sl" },
{ value: "sr", title: "sr" },
{ value: "sv", title: "sv" },
{ value: "sw", title: "sw" },
{ value: "ta", title: "ta" },
{ value: "th", title: "th" },
{ value: "tl", title: "tl" },
{ value: "tr", title: "tr" },
{ value: "tt", title: "tt" },
{ value: "uk", title: "uk" },
{ value: "ug", title: "ug" },
{ value: "ur", title: "ur" },
{ value: "uz", title: "uz" },
{ value: "vi", title: "vi" },
{ value: "wo", title: "wo" },
{ value: "zh-cn", title: "zh-cn" },
{ value: "zh-hk", title: "zh-hk" },
{ value: "zh-tw", title: "zh-tw" },
{ value: "zh-yue", title: "zh-yue" },
]
export default {
name: "linkListItem",
type: 'object',
fields: [
{
name: 'title',
type: 'string'
},
{
name: 'URL',
type: 'url'
},
{
name: 'excerpt',
type: 'text'
},
{
name: 'timestamp',
type: 'string',
}
]
}
export default {
name: 'owner',
type: 'object',
description:
'The name and email of the person or organization that iTunes should list in their different views',
fields: [
{
name: 'email',
type: 'email'
},
{
name: 'name',
type: 'string'
}
]
}
export default {
name: 'schedule',
type: 'object',
title: 'Publish schedule',
fields: [
{
name: 'publish',
type: 'datetime',
title: 'Date of publication',
description: 'When should this episode be available?',
options: {
inputUtc: false,
dateFormat: 'YYYY-MM-DD',
timeFormat: 'HH:mm',
inputDate: true,
inputTime: true,
timeStep: 15,
calendarTodayLabel: 'Today',
placeholderDate: '2017-04-18',
placeholderTime: '11:29'
}
},
{
name: 'unpublish',
type: 'datetime',
title: 'When should this episode be unaccessible?',
description:
'In case you want to unpublish an episode on a said date.',
options: {
inputUtc: false,
dateFormat: 'YYYY-MM-DD',
timeFormat: 'HH:mm',
inputDate: true,
inputTime: true,
timeStep: 15,
calendarTodayLabel: 'Today',
placeholderDate: '2017-04-18',
placeholderTime: '11:29'
}
}
]
}
export default {
name: 'social',
title: 'Social network presence',
type: 'object',
fields: [
{
name: 'twitter',
type: 'string',
},
{
name: 'facebook',
type: 'string',
},
{
name: 'googleplus',
type: 'string',
},
{
name: 'instagram',
type: 'string',
},
{
name: 'linkedin',
type: 'string',
},
{
name: 'youtube',
type: 'string',
},
]
}
export default {
name: 'sponsor',
type: 'document',
title: 'Sponsor',
fields: [
{
name: 'name',
type: 'string',
title: 'Name of sponsor'
},
{
name: 'url',
type: 'url',
title: 'URL',
},
{
name: 'description',
type: 'array',
title: 'Description',
of: [{ type: 'block' }]
},
{
name: 'logo',
type: 'image',
title: 'Logo',
},
]
}
export default {
name: 'sponsorRead',
type: 'object',
title: 'Sponsor read',
fields: [
{
name: 'sponsor',
type: 'reference',
to: [
{
type: 'sponsor'
}
]
},
{
name: 'copy',
type: 'array',
title: 'copy',
of: [{ type: 'block'}]
},
]
}
These schemas add the following document types to your Sanity dataset: Podcast, Episode, Host, Sponsor. You can create as many podcasts as you want, and attach episodes to them. This plugin supports cross-posting episodes to multiple podcasts, as well as scheduling and connecting specific sponsor reads to episodes.
Knut is a principal developer marketing manager at Sanity.io
This can be used for blogs or articles where you want to possibly display next and previous article buttons
Go to Get current post, previous post, and next postHow to automatically generate linked headings with a custom serializer
Go to Anchored Headings for Portable TextMigration script to convert plain text to block content across your content lake
Go to Migrate plain text field to Portable TextSimple content type for a question and answer pattern
Go to Frequently asked questions