Populate a WCF syndication podcast using MP3 ID3 metadata tags
In the last post, I showed how to create a podcast using WCF syndication. A podcast is an RSS feed containing a list of audio files to which users can subscribe. The podcast not only contains links to the audio files, but also metadata about each episode. A cool approach to building the feed is reading this metadata from the ID3 tags on the MP3 files used for the podcast.
One library to do this is TagLib-Sharp. Here is some sample code:
1: var taggedFile = TagLib.File.Create(f);
2: var fileInfo = new FileInfo(f);
3: var item = new iTunesPodcastItem()
4: {
5: title = taggedFile.Tag.Title,
6: size = fileInfo.Length,
7: url = feed.baseUrl + fileInfo.Name,
8: duration = taggedFile.Properties.Duration,
9: mediaType = feed.mediaType,
10: summary = taggedFile.Tag.Comment,
11: subTitle = taggedFile.Tag.FirstAlbumArtist,
12: id = fileInfo.Name
13: };
14: if (!string.IsNullOrEmpty(taggedFile.Tag.Album))
15: item.publishedDate = DateTimeOffset.Parse(taggedFile.Tag.Album);
This reads the ID3 tags into an object for later use in creating the syndication feed. When the MP3 is created, these tags are set...or they can be set after the fact using the Properties dialog in Windows Explorer. The only "hack" is that there isn't an easily accessible tag for
"subtitle" or "published date" so I used other tags in this example. Feel free to change this to meet your purposes. You could remove the subtitle & use the file modified data for example.
That takes care of the episodes, for the feed level settings we'll load those from an XML file:
1: <?xml version="1.0" encoding="utf-8" ?>
2: <iTunesPodcastFeed
3: baseUrl =""
4: title=""
5: subTitle=""
6: description=""
7: copyright=""
8: category=""
9: ownerName=""
10: ownerEmail=""
11: mediaType="audio/mp3"
12: mediaFiles="*.mp3"
13: imageUrl=""
14: link=""
15: />
Here is the full code put together.
- Read the feed XML file and deserialize it into an iTunesPodcastFeed class
- Loop over the files in a directory reading the ID3 tags from the audio files
1: public static iTunesPodcastFeed CreateFeedFromFiles(string podcastDirectory, string podcastFeedFile)
2: {
3: XmlSerializer serializer = new XmlSerializer(typeof(iTunesPodcastFeed));
4: iTunesPodcastFeed feed;
5: using (var fs = File.OpenRead(Path.Combine(podcastDirectory, podcastFeedFile)))
6: {
7: feed = (iTunesPodcastFeed)serializer.Deserialize(fs);
8: }
9: foreach (var f in Directory.GetFiles(podcastDirectory, feed.mediaFiles))
10: {
11: try
12: {
13: var taggedFile = TagLib.File.Create(f);
14: var fileInfo = new FileInfo(f);
15: var item = new iTunesPodcastItem()
16: {
17: title = taggedFile.Tag.Title,
18: size = fileInfo.Length,
19: url = feed.baseUrl + fileInfo.Name,
20: duration = taggedFile.Properties.Duration,
21: mediaType = feed.mediaType,
22: summary = taggedFile.Tag.Comment,
23: subTitle = taggedFile.Tag.FirstAlbumArtist,
24: id = fileInfo.Name
25: };
26: if (!string.IsNullOrEmpty(taggedFile.Tag.Album))
27: item.publishedDate = DateTimeOffset.Parse(taggedFile.Tag.Album);
28: feed.Items.Add(item);
29: }
30: catch
31: {
32: // ignore files that can't be accessed successfully
33: }
34: }
35: return feed;
36: }
Usually putting a "try...catch" like this is bad, but in this case I'm just skipping over files that are locked while they are being uploaded to the web site.
Here is the code from the last couple of posts.