Adding "Explicit" ID3 tag for iTunes
davidjm777 - August 5, 2009 - 15:20
| Project: | FileField Podcaster |
| Version: | 6.x-0.7 |
| Component: | Miscellaneous |
| Category: | support request |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | active |
Jump to:
Description
Is anyone else having trouble figuring out how to get the iTunes "Explicit" ID3 information into the file? There is some talk about "converting the file in iTunes" then setting the ID3 explicit. But I cannot figure it out! I see everything else BUT explicit.
I have everything else working now, but I am stuck here. Anyone figured it out already?

#1
I'm also having this problem.
#2
subscribe.
#3
No, the Explicit or Clean tags are in the RSS feed, not on the mp3 files themselves. ("Clean") The tag exists on both the Channel level and on the individual Items, so it would need to be supported for each.
I might be willing to throw a patch together, but it doesn't look like this module is still being maintained.
#4
I will definitely bug test if you're up to it gruber76. There really isn't another module such as this so if need be I'm sure someone could ask to takeover maintainership.
#5
I got an email about the comment I left on the ffpc documentation page: http://drupal.org/node/313322 about customising the output of this module.
The output is defined within the module, rather than in template files, so changes to the output require changing (hacking) the module. While I can see that this is not best practice, the output of the template file (ffpc-view-podcast-feed.tpl.php) mostly just prints a variable - $channel. $channel is built inside the ffpc.module file from an array ($args) which does not have scope outside the function that creates it. It seems that there is really no way of customising the output to the extent that is required without really essentially re-doing all the work that is done by the module. An alternative approach would be give up on the module altogether and build an rss feed the way you want it, with all the heavy lifting done in template files - since one perfectly good methodology for creating a podcast feed has already been established by ffpc, it seems a duplication of effort to look for a different solution.
My fix to this issue, then, was to say 'I want a module very like ffpc, but with a different set of itunes tags outputted'. My solution was to clone ffpc, but to change all the ffpc output for output that suited me. I called my new module (which is just to create a talks podcast for my church) ffpcstpauls. Alternatively, you could just hack the ffpc module - only it would then be hard to tell what was original and what was your modifications.
As a rough and ready solution to getting the itunes feed you want this is quite easy (it took me an afternoon to read all the itunes specifications, decide what I wanted my feed to look like, figure out how ffpc delivered the feed it did, and then go through the code so that it delivered what we wanted instead). A better fix would be to provide an administration interface for ffpc, so that the options that you want are available there - or to make a module that was somehow more dependent on .tpl.php files which could easily be themed. Either of those would have taken several days (and then could have been buggy etc...).
So... let me go through the module files, and explain how to use them as the template for a module that will produce a specific feed in the format you want. The module has 6 files - the .info file which is needed to see and load your module in the module administration page, a .tpl.php file - which is the template file for the feed, a .module file, which builds the feed from the various rows and adds the feed meta data, a .views.inc file which defines the classes and template used to build the rows and style the feed.
Creating a custom ffpc module
Decide on a name for your module - I chose ffpcstpauls - when I refer to this, use your own name instead
Make a copy of the ffpc.info file and name it ffpcstpauls.info. Change the name and description (Name - St Paul's FileField Podcast; Description: A clone of ffpc, with the iTunes tags customised for St Paul's iTunes feed) to suit your feed.
;$Id$name = "St Pauls FieldField Podcast"
description = "Richard Morgan hack of the FFPC module to customise a podcast for St Pauls"
package = Views
core = 6.x
dependencies[] = content
dependencies[] = views
dependencies[] = filefield
dependencies[] = filefield_meta
dependencies[] = getid3
Make a copy of the ffpc.views.inc file and name it ffpcstpauls.views.inc. This file defines the call to the theme file ('theme' => 'ffpcstpauls_view_podcast_feed') and the handlers for styling in general, and more specifically the row formats ('handler' => 'ffpcstpauls_plugin_style_podcast' and 'handler' => 'ffpcstpauls_plugin_row_podcast' respectively). You must ensure that you rename these three references (which will be defined in the next four files) with the names that you use in your files (following the principle of replacing the 'ffpc' part of the name with your new name.
Here is my ffpcstpauls.views.inc file:
<?php
/*
* Richard Morgan hack of the ffpc (filefield podcast) module - we want more itunes: tags (image, site summary) and to customise our description fields
*
* Much of the output here is based on the Apple Podcast standard. Details
* can be found here:
* http://www.apple.com/itunes/store/podcaststechspecs.html
*
* Note: We need a custom style plugin because the default RSS plugin does
* not permit additional elements to be added to the feed.
*/
function ffpcstpauls_views_plugins() {
return array(
'module' => 'ffpcstpauls',
'style' => array(
'podcast' => array(
'title' => t('St Pauls Podcast Feed'),
'help' => t('Generates Customised Podcast for St Pauls.'),
'handler' => 'ffpcstpauls_plugin_style_podcast',
'theme' => 'ffpcstpauls_view_podcast_feed',
'uses row plugin' => TRUE,
'uses options' => TRUE,
'type' => 'feed',
'parent' => 'rss',
),
),
'row' => array(
'podcast' => array(
'title' => t('St Pauls Talk'),
'help' => t('Display the node as a Podcast Episode.'),
'handler' => 'ffpcstpauls_plugin_row_podcast',
'uses fields' => TRUE,
'type' => 'feed',
'parent' => 'node_rss',
'uses options' => TRUE,
),
),
);
}
The style plugin file is ffpc_plugin_style_podcast.inc copy it and rename it ffpcstpauls_plugin_style_podcast.inc. This file simply defines the overall style of the feed as an rss feed. It does that by 'extending' the view_plugin_style_rss class - but in fact it doesn't add anything to that class, so its really just copying its functionality to a different names class. All we need to do is make sure that we rename the class we are defining with our name.
<?php
/**
* Default style plugin to render a Podcast
*/
class ffpcstpauls_plugin_style_podcast extends views_plugin_style_rss {
}
The template file (ffpc-view-podcast-feed.tpl.php) is copied and named 'ffpcstpauls-view-podcast-feed.tpl.php'. In the original template, the xml:base property is pulled from the $link variable (you could put that back safely) and the two namespace definitions (xmlns:...) are produced by the variable $namespaces. I've explicitly defined them. You could leave this file alone (apart from the changing the file name); I was happy that I was writing this for a specific instance and wanted to be sure that I was writing the namespaces as the iTunes stuff asked.
<rss version="2.0" xml:base="http://www.stpaulssalisbury.org/podcast" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:media="http://search.yahoo.com/mrss/"><?php print $channel; ?>
</rss>
The heavy lifting happens in the next two files. In fact if you just wanted to hack the module as is you could leave the four previous files entirely alone, not bother creating a new module and just overwrite these two files.
The first file is ffpc_plugin_row_podcast.inc - copy it and rename it ffpcstpauls_plugin_row_podcast.inc - this defines the class which extends the regular rss item class (make sure you rename this in line 2) and this is what formats each item in the podcast - by picking the items you want to include and sending them through the drupal function format_rss_item(). You need to go through the iTunes spec and decide how you want your feed items to look - Apple give a really good description of how each item in the feed displays in iTunes - you can choose exactly what you want where. The heavy lifting is done by loading the node of that row of your view - you then need to pull all the data out of that item by directly describing the property of the node object (i.e. $item->body). This is exactly the same as any other (advanced) rows theming and there are lots of examples of this. You need to know what the properties of the object are - the easiest way to do this is to set up a test page where you load a node as (say) $item, and then print_r($item); to output the object on the screen - it's easier to see this clearly by viewing the source. There is lots of supplemental advice about how to do this, and it is an essential technique for theming anything in Drupal - so if you've got this far, I guess you can probably already do this. The id3 tags are included by GetID3 - all of that stuff is pretty self evident in the code below.
Anyway, sufficient to say that the following code relates to the specific way in which a 'sermon' node type is set up (via CCK) on our website - your application of this principle will be entirely different. So here is the code - read it, compare it to the original and go bake your own:
<?php
class ffpcstpauls_plugin_row_podcast extends views_plugin_row_node_rss {
function render($row) {
// stripped right down from ffpc equivalent. The itunes:subtitle is built from the speaker name, the passage they're speaking on, its date and event type. pubDate from the talk date
global $base_url;
// Load the specified node:
$item = node_load($row->nid);
// get the file item and return if there is no audio for this item yet
$file = $item->field_sermon_audio[0];
if (!is_array($file)) return;
$item->build_mode = NODE_BUILD_RSS;
$item->link = url("node/$row->nid", array('absolute' => TRUE));
// Prepare $item_summary and $item_description (displayed as itunes:summary - what you get when you click on the i button in itunes - if it's empty it defaults to the description tag)
$item_text = $item->body;
$stripped_item_text = strip_tags($item_text);
$item_summary = substr($stripped_item_text, 0, 4000);
$item_description = "Talks from St Paul's Salisbury";
// Prepare $item_date (displayed as pubDate - determines order in which posts are displayed, so we'll arbitrarily add 1000 to the date of the evening talks)
$date = $item->field_talk_date[0]['value'] . " GMT";
$item_date = ($item->field_event_type[0]['value'] == "6.30pm") ? date('r', (strtotime($date) + 1000)) : date('r', strtotime($date));
// Prepare $item_subtitle (displayed as itunes:subtitle)
if ($item->field_speaker[0]['nid']) {
$speaker_node = node_load($item->field_speaker[0]['nid']);
$speaker = $speaker_node->title;
}
if ($item->field_event_type[0]['value']) {
$event_type = $item->field_event_type[0]['value'];
}
if ($item->field_bible_ref[0]['value']) {
$bible_ref = $item->field_bible_ref[0]['value'];
}
if (!$speaker && !$bible_ref) {
$item_subtitle = "A Talk from St Paul's Salisbury";
} elseif (!$speaker) {
$item_subtitle = "A Talk on " . $bible_ref;
} elseif (!$bible_ref) {
$item_subtitle = "A Talk by " . $speaker;
} else {
$item_subtitle = $speaker . " on " . $bible_ref;
}
$item_subtitle .= " (";
if ($event_type) $item_subtitle .= $event_type . ", ";
$item_subtitle .= date('jS M y', strtotime($date)) . ")";
// load getid3 and put the results of its analyze method into the string $info
if (!getid3_load(TRUE)) {
return NULL;
}
$getid3 = new getID3;
$info = $getid3->analyze($file['filepath']);
$extra = array();
$extra[] = array(
'key' => 'enclosure',
'attributes' => array(
'url' => url( $file['filepath'], array('absolute'=>TRUE) ),
'length' => $file['filesize'],
'type' => $file['filemime'],
),
);
$extra[] = array(
'key' => 'itunes:duration',
'value' => $info['playtime_string'],
);
$extra[] = array(
'key' => 'itunes:author',
'value' => $info['tags']['id3v2']['artist'][0],
);
$extra[] = array(
'key' => 'itunes:subtitle',
'value' => $item_subtitle,
);
$extra[] = array(
'key' => 'itunes:summary',
'value' => $item_summary,
);
$extra[] = array(
'key' => 'pubDate',
'value' => $item_date,
);
$extra[] = array(
'key' => 'guid',
'value' => url( $file['filepath'], array('absolute'=>TRUE) ),
);
/*
* The following function takes title, link, description and then
* all additional XML elements. For the title we'll use the node
* title. Link serves no real purpose in a podcast. Description
* is overridden by the extra "subtitle" tag but we'll keep it for
* completeness with RSS.
*/
return format_rss_item($item->title, $item->link, $item_description, $extra );
}
}
The final file is the module file itself (ffpc.module - copied and re-named as ffpcstpauls.module). Make sure that both functions (mine are named: ffpcstpauls_views_api() and template_preprocess_ffpcstpauls_view_podcast_feed()) are renamed with your module name replacing the original ffpc name. The first function allows views to call all the .inc files in this module folder, and works with views 2 - all the files for your module must be in the same folder - as in the original ffpc, otherwise you will also need to specify a path within this function. The preprocess function is responsible for building the whole feed channel - with the function format_rss_channel(), and includes all the channel information (which is where the 'explicit' tag is, and a link to an image for the channel). Here you simply hard code your own channel information - again the Apple website has very good information about categories etc...
<?php
/**
* This is modelled on the ffpc module - we're explicitly setting tags here not in the view though - for itunes feed specs see: http://www.apple.com/itunes/podcasts/specs.html
* This allows us to set the link to the homepage - not the podcast feed, set the podcast description beyond 255 characters, have an image for the podcast, an author attribute and the explicit and category tags that an itunes feed ought to have.
* The format_rss_channel() function takes care of converting special characters into the correct xml entities etc...
*
* This file defines the tags in the 'channel' - the item tags are defined in ffpc-stpauls_plugin_row_podcast.inc
*/
/**
* Implementation of hook_views_api().
* This is required for views to load all the .inc files in the module folder
*/
function ffpcstpauls_views_api() {
return array('api' => 2);
}
/**
* This pre-processes $vars - which is fed in by reference ('&$vars') - before it is available to the template (ffpcstpauls-view-podcast-feed.tpl.php)
* The function builds $vars['channel'] which means that $channel is available to the template to output
* It also sets $vars['link'] so that $link is available to the template (which we don't use)
* It also set the drupal header as an rss feed
*/
function template_preprocess_ffpcstpauls_view_podcast_feed(&$vars) {
// Title is used as the channel title
$title = "St Paul's Salisbury";
// Description is not used by itunes (but required for a valid feed?)
$description = "A feed of the audio sermons from St Paul's";
// itunes:summary is allowed to be 4,000 characters (rather than a max 255) and is used as the description of the feed
$summary = "Regular podcast of Sunday and Midweek talks from St Paul's Salisbury. St Paul's seeks to encounter God, to equip His people and extend His Kingdom. We pray that our talks will help you grow in your relationship with God and live out that faith in your daily life. This podcast is of talks given at the Sunday services (10.30am and 6.30pm) and also at 'Oasis' - our women's fellowship at 10am on a Thursday morning.";
// Author shows up on the channel page
$author = "St Paul's Church, Salisbury";
// copyright seems to show on Apple TV, but not on the itunes page (?)
$copyright = "Copyright St Paul's Church, Salisbury, 2009 to date, and the various speakers whose talks are podcast";
// explicit must be set - yes is for filth, clean is for family friendly, no is for ordinary content
$explicit = "no";
// Categories are defined on the Apple website - see http://www.apple.com/itunes/podcasts/specs.html
$category = "Religion & Spirituality";
$subcategory = "Christianity";
// owner details (name and email) are for administration only - i.e. for iTunes to get in touch
$name = "St Paul's Salisbury";
$email = variable_get('site_mail', ini_get('sendmail_from'));
// image must be created and ftp'ed into place
$image_url = "http://www.stpaulssalisbury.org/sites/default/files/podcast_image.gif";
// This is where we add additional elements to the podcast channel (other than title and description).
// We use the variables set above (except $title and description which are directly fed to format_rss_channel() )
$args = array(
'itunes:summary' => $summary,
'itunes:author' => $author,
'copyright' => $copyright,
'itunes:explicit' => $explicit,
'itunes:keywords' => 'sermon, sermons, church of england, anglican',
'itunes:owner' => array(
'itunes:name' => $name,
'itunes:email' => $email,
),
array(
'key' => 'itunes:image',
'attributes' => array(
'href' => $image_url,
),
),
array(
'key' => 'itunes:category',
'attributes' => array(
'text' => $category,
),
'value' => array(
array(
'key' => 'itunes:category',
'attributes' => array(
'text' => $subcategory,
),
),
),
),
);
$items = &$vars['rows'];
$vars['link'] = check_url(url('<front>', array('absolute' => true)));
$vars['channel'] = format_rss_channel($title, $vars['link'], $description, $items, 'en', $args);
drupal_set_header('Content-Type: application/rss+xml; charset=utf-8');
}
There we are - look at the Apple info on how an iTunes feed should be formatted - decide what information you want in summaries and descriptions etc... - make sure that your node has somewhere to enter that extra information, and then bake your own module exactly following the pattern used by ffpc.
Once you have your six files - you put them in a folder with your module name, upload it to sites/all/modules and then install it as you would any other module. To create your feed in Views you follow exactly the instructions as for ffpc.
There is some work involved - it's not difficult, especially if you are used to theming Drupal nodes by directly pulling the node properties.
Have fun - I hope this is helpful.
#6
This is super amazing Richard! Thanks so much. You don't know how much this helps.
#7
Glad to know it's helpful - hope you get the feed up and running soon...