Index: audio_itunes.admin.inc
===================================================================
RCS file: audio_itunes.admin.inc
diff -N audio_itunes.admin.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ audio_itunes.admin.inc	25 Nov 2008 14:03:39 -0000
@@ -0,0 +1,27 @@
+<?php
+// $Id: audio_itunes.module,v 1.9 2008/11/24 21:11:13 drewish Exp $
+
+/**
+ * Settings form.
+ */
+function audio_itunes_admin_settings() {
+  $types = array();
+  foreach (node_get_types() as $type) {
+    $types[$type->type] = $type->name;
+  }
+  $form['audio_itunes_types'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Node types'),
+    '#options' => $types,
+    '#default_value' => variable_get('audio_itunes_types', array('audio')),
+    '#description' => t('Associate iTunes feed item information with node types.'),
+  );
+  $form['#validate'][] = 'audio_itunes_admin_settings_validate';
+
+  return system_settings_form($form);
+}
+
+function audio_itunes_admin_settings_validate($form, &$form_state) {
+  // Retrieve selected types - Forms API sets the value of unselected checkboxes to 0.
+  $form_state['values']['audio_itunes_types'] = array_keys(array_filter($form_state['values']['audio_itunes_types']));
+}
\ No newline at end of file
Index: audio_itunes.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/audio/contrib/itunes/audio_itunes.install,v
retrieving revision 1.3
diff -u -p -r1.3 audio_itunes.install
--- audio_itunes.install	24 Nov 2008 21:11:13 -0000	1.3
+++ audio_itunes.install	25 Nov 2008 14:03:40 -0000
@@ -24,8 +24,14 @@ function audio_itunes_schema() {
     'fields' => array(
       'vid' => array(
         'type' => 'int',
-        'size' => 'medium',
-        'not null' => 'true',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'nid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
         'default' => 0,
       ),
       'summary' => array(
@@ -64,11 +70,33 @@ function audio_itunes_schema() {
 }
 
 /**
+ * Add a nid column to the to the {audio_itunes_item} table.
+ */
+function audio_itunes_update_6000() {
+  $ret = array();
+
+  // Create the nid field so we can easily associate all the records with a
+  // particular node.
+  $nid_field = array(
+    'type' => 'int',
+    'unsigned' => TRUE,
+    'not null' => TRUE,
+    'default' => 0,
+  );
+  db_add_field($ret, 'audio_itunes_item', 'nid', $nid_field);
+
+  // Assign nids from the node table.
+  $ret[] = update_sql("UPDATE {audio_itunes_item} a INNER JOIN {node} n ON a.vid = n.vid SET a.nid = n.nid");
+
+  return $ret;
+}
+
+/**
  * Update to remove the unused {audio_itunes_channel} table.
  */
 // FIXME: Commented out until I can figure out some way to pass the data out
 // to admins so they can copy/paste into their views.
-function _audio_itunes_update_6000() {
+function _audio_itunes_update_6001() {
   $ret = array();
 
   db_drop_table($ret, 'audio_itunes_channel');
Index: audio_itunes.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/audio/contrib/itunes/audio_itunes.module,v
retrieving revision 1.9
diff -u -p -r1.9 audio_itunes.module
--- audio_itunes.module	24 Nov 2008 21:11:13 -0000	1.9
+++ audio_itunes.module	25 Nov 2008 14:03:40 -0000
@@ -4,6 +4,23 @@
 define('AUDIO_ITUNES_EXPLICIT_YES', 1);
 define('AUDIO_ITUNES_EXPLICIT_CLEAN', 2);
 
+
+/**
+ * Implementation of hook_menu().
+ */
+function audio_itunes_menu() {
+  $items = array();
+  $items['admin/settings/audio_itunes'] = array(
+    'title' => 'Audio iTunes',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('audio_itunes_admin_settings'),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'audio_itunes.admin.inc',
+    'description' => 'Determine which node types can track iTunes information.'
+  );
+  return $items;
+}
+
 /**
  * Implementation of hook_views_api().
  */
@@ -14,47 +31,50 @@ function audio_itunes_views_api() {
 }
 
 /**
- * Implementation of hook_form_alter() so we can add our image fields to the
- * audio node form.
+ * Implementation of hook_form_alter().
+ *
+ * We add in extra iTunes specific information to the node edit forms.
  */
 function audio_itunes_form_alter(&$form, &$form_state, $form_id) {
-  // We only alter audio node edit forms
-  if ($form_id == 'audio_node_form') {
-    $node = $form['#node'];
-
-    $form['audio_itunes'] = array(
-      '#type' => 'fieldset', '#title' => t('iTunes feed information'),
-      '#collapsible' => TRUE,
-      '#description' => t('iTunes specific information.'),
-      '#weight' => 0,
-      '#tree' => TRUE,
-    );
-    $form['audio_itunes']['subtitle'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Subtitle'),
-      '#default_value' => $node->audio_itunes['subtitle'],
-      '#maxlength' => 255,
-      '#description' => t("The contents of this tag are shown in the Description column in iTunes. The subtitle displays best if it is only a few words long."),
-    );
-    $form['audio_itunes']['summary'] = array(
-      '#type' => 'textarea',
-      '#title' => t('Summary'),
-      '#default_value' => $node->audio_itunes['summary'],
-      '#maxlength' => 4000,
-      '#rows' => 5,
-      '#description' => t('The contents of this tag are shown in a separate window that appears when the "circled i" in the Description column is clicked. It also appears on the iTunes page for your podcast.'),
-    );
-    $form['audio_itunes']['explicit'] = array(
-      '#type' => 'select', '#title' => t('Explicit'),
-      '#options' => array(0 => 'Unspecified', AUDIO_ITUNES_EXPLICIT_YES => 'Yes', AUDIO_ITUNES_EXPLICIT_CLEAN => 'Clean'),
-      '#default_value' => $node->audio_itunes['explicit'],
-      '#description' => t('If select "yes", an "explicit" parental advisory graphic will appear next to your podcast artwork on the iTunes Music Store, and in the Name column in iTunes. If you select "clean", the parental advisory type is considered Clean, meaning that no explicit language or adult content is included anywhere in the episode, and a "clean" graphic will appear.'),
-    );
-    $form['audio_itunes']['block'] = array(
-      '#type' => 'checkbox', '#title' => t('Block'),
-      '#default_value' => $node->audio_itunes['block'],
-      '#description' => t('Check this to prevent this episode from appearing in the iTunes Podcast directory. For example, you may want a specific episode blocked from iTunes if its content might cause the feed to be removed from iTunes.'),
-    );
+  // We only alter the selected node edit forms
+  if (isset($form['#id']) && $form['#id'] == 'node-form') {
+    $types = variable_get('audio_itunes_types', array('audio'));
+    if (isset($form['#node']->type) && in_array($form['#node']->type, $types)) {
+      $node = $form['#node'];
+      $form['audio_itunes'] = array(
+        '#type' => 'fieldset', '#title' => t('iTunes feed information'),
+        '#collapsible' => TRUE,
+        '#description' => t('iTunes specific information.'),
+        '#weight' => 0,
+        '#tree' => TRUE,
+      );
+      $form['audio_itunes']['subtitle'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Subtitle'),
+        '#default_value' => isset($node->audio_itunes['subtitle']) ? $node->audio_itunes['subtitle'] : '',
+        '#maxlength' => 255,
+        '#description' => t("The contents of this tag are shown in the Description column in iTunes. The subtitle displays best if it is only a few words long."),
+      );
+      $form['audio_itunes']['summary'] = array(
+        '#type' => 'textarea',
+        '#title' => t('Summary'),
+        '#default_value' => isset($node->audio_itunes['summary']) ? $node->audio_itunes['summary'] : '',
+        '#maxlength' => 4000,
+        '#rows' => 5,
+        '#description' => t('The contents of this tag are shown in a separate window that appears when the "circled i" in the Description column is clicked. It also appears on the iTunes page for your podcast.'),
+      );
+      $form['audio_itunes']['explicit'] = array(
+        '#type' => 'select', '#title' => t('Explicit'),
+        '#options' => array(0 => 'Unspecified', AUDIO_ITUNES_EXPLICIT_YES => 'Yes', AUDIO_ITUNES_EXPLICIT_CLEAN => 'Clean'),
+        '#default_value' => isset($node->audio_itunes['explicit']) ? $node->audio_itunes['explicit'] : 0,
+        '#description' => t('If select "yes", an "explicit" parental advisory graphic will appear next to your podcast artwork on the iTunes Music Store, and in the Name column in iTunes. If you select "clean", the parental advisory type is considered Clean, meaning that no explicit language or adult content is included anywhere in the episode, and a "clean" graphic will appear.'),
+      );
+      $form['audio_itunes']['block'] = array(
+        '#type' => 'checkbox', '#title' => t('Block'),
+        '#default_value' => isset($node->audio_itunes['block']) ? $node->audio_itunes['block'] : 0,
+        '#description' => t('Check this to prevent this episode from appearing in the iTunes Podcast directory. For example, you may want a specific episode blocked from iTunes if its content might cause the feed to be removed from iTunes.'),
+      );
+    }
   }
 }
 
@@ -65,25 +85,27 @@ function audio_itunes_nodeapi(&$node, $o
   if ($node->type == 'audio') {
     switch ($op) {
       case 'load':
-        $result = db_query("SELECT * FROM {audio_itunes_item} WHERE vid=%d", $node->vid);
+        $result = db_query("SELECT * FROM {audio_itunes_item} WHERE vid = %d", $node->vid);
         if ($result) {
           return array('audio_itunes' => db_fetch_array($result));
         }
         break;
 
-      case 'insert':
-        db_query("INSERT INTO {audio_itunes_item} (vid, summary, subtitle, explicit, block) VALUES (%d, '%s', '%s', %d, %d)",
-          $node->vid, $node->audio_itunes['summary'], $node->audio_itunes['subtitle'], $node->audio_itunes['explicit'], $node->audio_itunes['block']);
-        break;
-
       case 'update':
-        // delete and insert rather than updating in case the node doesn't have an existing record
+        // Delete and insert rather than updating in case the node doesn't have
+        // an existing record.
         db_query("DELETE FROM {audio_itunes_item} WHERE vid = %d", $node->vid);
-        db_query("INSERT INTO {audio_itunes_item} (vid, summary, subtitle, explicit, block) VALUES (%d, '%s', '%s', %d, %d)",
-          $node->vid, $node->audio_itunes['summary'], $node->audio_itunes['subtitle'], $node->audio_itunes['explicit'], $node->audio_itunes['block']);
+        // INTENTIONALLY NO BREAK HERE.
+      case 'insert':
+        $record = array_merge($node->audio_itunes, array('nid' => $node->nid, 'vid' => $node->vid));
+        drupal_write_record('audio_itunes_item', $record);
         break;
 
       case 'delete':
+        db_query("DELETE FROM {audio_itunes_item} WHERE nid = %d", $node->nid);
+        break;
+
+      case 'delete revision':
         db_query("DELETE FROM {audio_itunes_item} WHERE vid = %d", $node->vid);
         break;
 
@@ -110,7 +132,7 @@ function audio_itunes_nodeapi(&$node, $o
           'key' => 'itunes:explicit',
           'value' => audio_itunes_explicit($node->audio_itunes['explicit']),
         );
-        // FIXME: first 12 freetaging terms should go into the keywords...
+        // TODO: first 12 freetaging terms should go into the keywords...
         return $ret;
     }
   }
@@ -125,3 +147,91 @@ function audio_itunes_explicit($value) {
   }
   return 'no';
 }
+
+/**
+ * Get an array with the iTunes podcast categories.
+ *
+ * @see http://www.apple.com/itunes/whatson/podcasts/specs.html#categories
+ */
+function audio_itunes_categories() {
+  return array(
+    'Arts' => array(
+      'Design',
+      'Fashion & Beauty',
+      'Food',
+      'Literature',
+      'Performing Arts',
+      'Visual Arts',
+    ),
+    'Business' => array(
+      'Business News',
+      'Careers',
+      'Investing',
+      'Management & Marketing',
+      'Shopping',
+    ),
+    'Comedy' => array(),
+    'Education' => array(
+      'Education Technology',
+      'Higher Education',
+      'K-12',
+      'Language Courses',
+      'Training',
+    ),
+    'Games & Hobbies' => array(
+      'Automotive',
+      'Aviation',
+      'Hobbies',
+      'Other Games',
+      'Video Games',
+    ),
+    'Government & Organizations' => array(
+      'Local',
+      'National',
+      'Non-Profit',
+      'Regional',
+    ),
+    'Health' => array(
+      'Alternative Health',
+      'Fitness & Nutrition',
+      'Self-Help',
+      'Sexuality',
+    ),
+    'Kids & Family' => array(),
+    'Music' => array(),
+    'News & Politics' => array(),
+    'Religion & Spirituality' => array(
+      'Buddhism',
+      'Christianity',
+      'Hinduism',
+      'Islam',
+      'Judaism',
+      'Other',
+      'Spirituality',
+    ),
+    'Science & Medicine' => array(
+      'Medicine',
+      'Natural Sciences',
+      'Social Sciences',
+    ),
+    'Society & Culture' => array(
+      'History',
+      'Personal Journals',
+      'Philosophy',
+      'Places & Travel',
+    ),
+    'Sports & Recreation' => array(
+      'Amateur',
+      'College & High School',
+      'Outdoor',
+      'Professional',
+    ),
+    'Technology' => array(
+      'Gadgets',
+      'Tech News',
+      'Podcasting',
+      'Software How-To',
+    ),
+    'TV & Film' => array(),
+  );
+}
\ No newline at end of file
Index: audio_itunes_plugin_style_rss.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/audio/contrib/itunes/audio_itunes_plugin_style_rss.inc,v
retrieving revision 1.1
diff -u -p -r1.1 audio_itunes_plugin_style_rss.inc
--- audio_itunes_plugin_style_rss.inc	24 Nov 2008 21:11:13 -0000	1.1
+++ audio_itunes_plugin_style_rss.inc	25 Nov 2008 14:03:41 -0000
@@ -20,10 +20,11 @@ class audio_itunes_plugin_style_rss exte
     $options['author'] = array('default' => '', 'translatable' => TRUE);
     $options['copyright'] = array('default' => '', 'translatable' => TRUE);
     $options['image_url'] = array('default' => '', 'translatable' => FALSE);
-    $options['explicit'] = array('default' => '', 'translatable' => FALSE);
-    $options['block'] = array('default' => '', 'translatable' => FALSE);
+    $options['explicit'] = array('default' => 0, 'translatable' => FALSE);
+    $options['block'] = array('default' => 0, 'translatable' => FALSE);
     $options['owner_name'] = array('default' => '', 'translatable' => FALSE);
     $options['owner_email'] = array('default' => '', 'translatable' => FALSE);
+    $options['categories'] = array('default' => array('', '', ''), 'translatable' => FALSE);
 
     return $options;
   }
@@ -89,6 +90,42 @@ class audio_itunes_plugin_style_rss exte
       '#default_value' => $this->options['owner_email'],
       '#maxlength' => 255,
     );
+    $category_options = array('' => t('- None selected -'));
+    foreach (audio_itunes_categories() as $top_level => $children) {
+      $category_options[] = (object) array(
+        'option' => array($top_level => $top_level)
+      );
+      foreach ($children as $second_level) {
+        $category_options[] = (object) array(
+          'option' => array($top_level . '|' . $second_level => ' - ' . $second_level)
+        );
+      }
+    }
+    $form['categories'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Categories'),
+      '#collapsible' => TRUE,
+      '#description' => '<p>'. t('There are two ways to browse podcast subject categories on iTunes: click Browse in the Quick Links box or click a selection in the Category box. The former method leads to a text-based table, while the latter leads to pages that include the podcast art.') .'</p>'
+        .'<p>'. t('For placement within the older, text-based browse system, podcast feeds may list up to 3 category/subcategory pairs. (For example, "Music" counts as 1, as does "Business > Careers.") For placement within the newer browse system based on Category links, however, and for placement within the Top Podcasts lists that appear in the right column of most podcast pages, only the first category listed in the feed is used.') .'</p>',
+    );
+    $form['categories'][0] = array(
+      '#type' => 'select',
+      '#title' => t('First Category'),
+      '#default_value' => $this->options['categories'][0],
+      '#options' => $category_options,
+    );
+    $form['categories'][1] = array(
+      '#type' => 'select',
+      '#title' => t('Second Category'),
+      '#default_value' => $this->options['categories'][1],
+      '#options' => $category_options,
+    );
+    $form['categories'][2] = array(
+      '#type' => 'select',
+      '#title' => t('Third Category'),
+      '#default_value' => $this->options['categories'][2],
+      '#options' => $category_options,
+    );
   }
 
   function options_validate(&$form, &$form_state) {
@@ -129,6 +166,7 @@ class audio_itunes_plugin_style_rss exte
       $extra[] = array(
         'key' => 'itunes:image',
         'attributes' => array('href' => $this->options['image_url']),
+        'value' => NULL,
       );
     }
     if ($this->options['subtitle']) {
@@ -159,13 +197,28 @@ class audio_itunes_plugin_style_rss exte
         'value' => $this->options['owner_email'],
       );
     }
+    // We've got up to three categories which can consist of a parent and
+    // child stored as "Parent" or "Parent|Child". We need to split them up and
+    // create nested elements.
+    foreach ($this->options['categories'] as $category) {
+      if ($category) {
+        $parts = explode('|', $category);
+        $element = array(
+          'key' => 'itunes:category',
+          'attributes' => array('text' => $parts[0]),
+          'value' => NULL,
+        );
+        if (isset($parts[1])) {
+          $element['value'][] = array(
+            'key' => 'itunes:category',
+            'attributes' => array('text' => $parts[1]),
+            'value' => NULL,
+          );
+        }
+        $extra[] = $element;
+      }
+    }
 
     return $extra;
   }
-
-/*  function render() {
-    dvm($this->theme_functions());
-//    parent::render();
-  }
-*/
 }
\ No newline at end of file
