cvs diff: Diffing .
Index: icecast.inc
===================================================================
RCS file: icecast.inc
diff -N icecast.inc
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ icecast.inc 11 Dec 2008 00:46:07 -0000
@@ -0,0 +1,353 @@
+<?php
+// $Id: icecast.inc,v 1.1.4.5 2008/07/25 11:45:50 alexua Exp $
+
+/**
+ * @file
+ * This include processes Icecast audio files for use by emaudio.module.
+ */
+
+define('EMAUDIO_ICECAST_MAIN_URL', 'http://www.icecast.org/');
+define('EMAUDIO_ICECAST_CROSSDOMAINS_XML', 'crossdomain.xml');
+define('EMAUDIO_ICECAST_CROSSDOMAINS_ERR', 'Could not find a valid crossdomains.xml. Please create it (or fix it) and place it in the root of your drupal installation. Find more information about crossdomain.xml at <a href="http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_14213">adobe.com</a>.');
+
+/**
+ * hook emaudio_PROVIDER_info
+ * this returns information relevant to a specific 3rd party audio provider
+ * @return
+ *   an array of strings requested by various admin and other forms
+ *   'name' => the translated name of the provider
+ *   'url' => the url to the main page for the provider
+ *   'settings_description' => a description of the provider that will be posted in the admin settings form
+ *   'supported_features' => an array of rows describing the state of certain supported features by the provider.
+ *      These will be rendered in a table, with the columns being 'Feature', 'Supported', 'Notes'.
+ */
+function emaudio_icecast_info() {
+  $name = t('Icecast');
+  $features = array(
+    array(t('Autoplay'), t('Yes'), ''),
+    array(t('RSS Attachment'), t('No'), ''),
+    array(t('Thumbnails'), t('No'), t('')),
+  );
+  return array(
+    'provider' => 'icecast',
+    'name' => $name,
+    'url' => EMAUDIO_ICECAST_MAIN_URL,
+    'settings_description' => t('These settings specifically affect audio streams from !icecast.', array('!icecast' => l($name, EMAUDIO_ICECAST_MAIN_URL, array('target' => '_blank')))),
+    'supported_features' => $features,
+    'weight' => 9,
+  );
+}
+
+/**
+ * hook emaudio_PROVIDER_settings
+ * this should return a subform to be added to the emaudio_settings() admin settings page.
+ * note that a form field will already be provided, at $form['PROVIDER'] (such as $form['icecast'])
+ * so if you want specific provider settings within that field, you can add the elements to that form field.
+ */
+function emaudio_icecast_settings() {
+  if (!file_exists(EMAUDIO_ICECAST_CROSSDOMAINS_XML)) {
+    drupal_set_message(t(EMAUDIO_ICECAST_CROSSDOMAINS_ERR), 'error', FALSE);
+  }
+
+  $form = array();
+  return $form;
+}
+
+function emaudio_icecast_form(&$field, &$item) {
+  $form = array();
+  
+  $form['icecast'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Icecast'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+  $form['icecast']['username'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Username'),
+    '#default_value' => $item['data']['icecast']['username'],
+    '#size' => 32,
+    '#maxlength' => 32,
+  );
+  $form['icecast']['password'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Password'),
+    '#default_value' => $item['data']['icecast']['password'],
+    '#size' => 32,
+    '#maxlength' => 32,
+  );
+  
+  return $form;
+}
+
+/**
+ * hook emaudio_PROVIDER_extract
+ * this is called to extract the video code from a pasted URL or embed code.
+ * @param $embed
+ *   an optional string with the pasted URL or embed code
+ * @return
+ *   either an array of regex expressions to be tested, or a string with the audio code to be used
+ *   if the hook tests the code itself, it should return either the string of the audio code (if matched), or an empty array.
+ *   otherwise, the calling function will handle testing the embed code against each regex string in the returned array.
+ */
+function emaudio_icecast_extract($embed = '') {
+  if (!$xml = simplexml_load_file(EMAUDIO_ICECAST_CROSSDOMAINS_XML)) {
+    drupal_set_message(t(EMAUDIO_ICECAST_CROSSDOMAINS_ERR), 'error', FALSE);
+    return array();
+  }
+  
+  $domains = array();
+  $tag = 'allow-access-from';
+  foreach ($xml->$tag as $domain) {
+    $domains[] = (string) $domain['domain'];
+  }
+  $domains = str_replace('.', '\.', implode('|', $domains));
+  
+  return array(
+    '@http://((?:'. $domains .').*)@i',
+  );
+}
+
+/**
+ * hook emfield_PROVIDER_data
+ *
+ * provides an array to be serialised and made available with $item elsewhere
+ */
+function emaudio_icecast_data($field, $item) {
+  $data = array();
+  $data['icecast'] = $item['icecast']['icecast'];
+  return $data;
+}
+
+/**
+ * hook emaudio_PROVIDER_embedded_link($audio_code)
+ * returns a link to view the audio at the provider's site
+ *  @param $audio_code
+ *    the string containing the audio to watch
+ *  @return
+ *    a string containing the URL to view the audio at the original provider's site
+ */
+function emaudio_icecast_embedded_link($audio_code) {
+  return $audio_code;
+}
+
+/**
+ * hook emaudio_PROVIDER_thumbnail
+ * returns the external url for a thumbnail of a specific audio
+ * TODO: make the args: ($embed, $field, $item), with $field/$item provided if we need it, but otherwise simplifying things
+ *  @param $field
+ *    the field of the requesting node
+ *  @param $item
+ *    the actual content of the field from the requesting node
+ *  @return
+ *    a URL pointing to the thumbnail
+ */
+function emaudio_icecast_thumbnail($field, $item, $formatter, $node, $width, $height) {
+  return $tn;
+}
+
+/**
+ * hook emaudio_PROVIDER_audio
+ * this actually displays the full/normal-sized video we want, usually on the default page view
+ *  @param $embed
+ *    the video code for the audio to embed
+ *  @param $width
+ *    the width to display the audio
+ *  @param $height
+ *    the height to display the audio
+ *  @param $field
+ *    the field info from the requesting node
+ *  @param $item
+ *    the actual content from the field
+ *  @return
+ *    the html of the embedded audio
+ */
+function emaudio_icecast_audio($embed, $width, $height, $field, $item, &$node, $autoplay) {
+  $settings = array(
+    'emaudio_icecast' => array(
+      'fields' => array(),
+    ),
+  );
+  $settings['emaudioIcecast']['fields'][0] = implode('--', array('icecast', $node->nid, $field['field_name'], $item['#delta']));
+  
+  $output = theme('emaudio_icecast_flash_full', $embed, $width, $height, $autoplay, $field, $item, $settings);
+  return $output;
+}
+
+/**
+ * hook emaudio_PROVIDER_preview
+ * this actually displays the preview-sized video we want, commonly for the teaser
+ *  @param $embed
+ *    the video code for the audio to embed
+ *  @param $width
+ *    the width to display the audio
+ *  @param $height
+ *    the height to display the audio
+ *  @param $field
+ *    the field info from the requesting node
+ *  @param $item
+ *    the actual content from the field
+ *  @return
+ *    the html of the embedded audio
+ */
+function emaudio_icecast_preview($embed, $width, $height, $field, $item, &$node, $autoplay) {
+  $output = theme('emaudio_icecast_flash_preview', $embed, $width, $height, $autoplay);
+  return $output;
+}
+
+/**
+ * Implementation of hook_nodeapi()
+ */
+function emaudio_icecast_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
+  switch ($op) {
+    case 'validate':
+      // $form == $a3;
+      break;
+  }
+}
+
+/**
+ * Implementation of hook_emfield_subtheme.
+ */
+function emaudio_icecast_emfield_subtheme() {
+  return array(
+    'emaudio_icecast_flash_preview' => array(
+      'arguments' => array('embed' => NULL, 'width' => NULL, 'height' => NULL, 'autoplay' => FALSE),
+      'file' => 'providers/icecast.inc'
+    ),
+    'emaudio_icecast_flash_full' => array(
+      'arguments' => array('embed' => NULL, 'width' => NULL, 'height' => NULL, 'autoplay' => FALSE, 'field' => NULL, 'item' => NULL, 'settings' => NULL),
+      'file' => 'providers/icecast.inc'
+    ),
+    'emaudio_icecast_current_song' => array(
+      'arguments' => array('embed' => NULL, 'width' => NULL, 'height' => NULL, 'autoplay' => FALSE, 'field' => NULL, 'item' => NULL),
+      'file' => 'providers/icecast.inc'
+    )
+  );
+}
+
+/**
+ * the embedded flash displaying the podomatic audio
+ */
+function theme_emaudio_icecast_flash_preview($embed, $width, $height, $autoplay) {
+  $output = '';
+  if ($embed) {
+    $output .= swf('http://'. $embed, array('methods' => array('action' => SWFTOOLS_MP3_DISPLAY)));
+  }
+  return $output;
+}
+
+/**
+ * the embedded flash displaying the podomatic audio
+ */
+function theme_emaudio_icecast_flash_full($embed, $width, $height, $autoplay, $field, $item, $settings) {
+  $output = '';
+  if ($embed) {
+    // Fetch the currently playing song, and make sure the stream is live
+    $current_song = _emaudio_icecast_extract_current_song($embed, $item['data']['icecast']['username'], $item['data']['icecast']['password']);
+    if ($current_song !== FALSE) {
+      
+      $output .= swf('http://'. $embed, array('methods' => array('action' => SWFTOOLS_MP3_DISPLAY)));
+      $output .= '<div id="'. $settings['emaudioIcecast']['fields'][0] .'" class="emaudio-icecast-current-song"></div>'."\n";
+
+      drupal_add_js(drupal_get_path('module', 'emaudio') .'/providers/icecast.js');
+      drupal_add_js($settings, 'setting');
+    }
+  }
+  return $output;
+}
+
+/**
+ * Called by the AJAX script that updates the currently playing song
+ */
+function theme_emaudio_icecast_current_song($song) {
+  $output  = '<div class="field-label">'. t('Title') .'</div>';
+  $output .= '<div class="field-item icecast-current-song-title">'. $song['title'] .'</div>';
+  $output .= '<div class="field-label">'. t('Artist') .'</div>';
+  $output .= '<div class="field-item icecast-current-song-artist">'. $song['artist'] .'</div>';
+  return $output;
+}
+
+function _emaudio_icecast_extract_current_song($url, $username, $password) {
+  // Separate the icecast server root from the mountpoint
+  $lastslash = strrpos($url, '/');
+  if ($lastslash !== FALSE) {
+    $serverroot = substr($url, 0, $lastslash);
+    $mountpoint = substr($url, $lastslash + 1);
+  
+    // Now use that data to create the url of admin/stats.xml
+    $stats = 'http://'. $username .':'. $password .'@'. $serverroot .'/admin/stats.xml';
+    
+    // Fetch data for our mountpoint
+    $ch = curl_init($stats);
+    if ($ch !== FALSE) {
+      curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
+      curl_setopt($ch, CURLOPT_HEADER, FALSE);
+      $data = curl_exec($ch);
+      
+      if ($data !== FALSE) {
+        $xml = @simplexml_load_string($data);
+        if ($xml !== FALSE) {
+          $count = count($xml->source);
+          for ($i = 0; $i < $count; $i++) {
+            if ((string) $xml->source[$i]['mount'] == '/'. $mountpoint) {
+              /*
+              print 'Stats: '. $stats ."<br />\n";
+              print 'Artist: '. (string) $xml->source[$i]->artist[0] ."<br />\n";
+              print 'Title: '. (string) $xml->source[$i]->title[0] ."<br />\n";
+              print 'Listen URL: '. $xml->source[$i]->listenurl ."<br /><br />\n";
+              */
+              $song = array(
+                'artist' => (string) $xml->source[$i]->artist[0],
+                'title' => (string) $xml->source[$i]->title[0],
+              );
+              
+              curl_close($ch);
+              return $song;
+            }
+          }
+        }
+      }
+      curl_close($ch);
+    }
+  }
+  
+  return FALSE;
+}
+
+/**
+ * Implementation of hook_menu().
+ */
+function emaudio_icecast_emfield_submenu() {
+  $items = array();
+  $items['emaudio/icecast/js'] = array(
+    'page callback' => 'emfield_include_invoke',
+    'page arguments' => array('emaudio', 'icecast', 'js'),
+    'access callback' => 'user_access',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  return $items;
+}
+
+/**
+ * Menu-callback for JavaScript-based uploads.
+ */
+function emaudio_icecast_js($nid, $fieldname, $delta) {
+  $output = '&nbsp;';
+  
+  $node = node_load($nid);
+  if (!empty($node)) {
+    if (isset($node->{$fieldname}[$delta])) {
+      $stream   = $node->{$fieldname}[$delta]['value'];
+      $username = $node->{$fieldname}[$delta]['data']['icecast']['username'];
+      $password = $node->{$fieldname}[$delta]['data']['icecast']['password'];
+      
+      $song = _emaudio_icecast_extract_current_song($stream, $username, $password);
+      $output = theme('emaudio_icecast_current_song', $song);
+    }
+  }
+  
+  print drupal_to_js(array('status' => TRUE, 'data' => $output));
+  exit;
+}
Index: icecast.js
===================================================================
RCS file: icecast.js
diff -N icecast.js
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ icecast.js  11 Dec 2008 00:46:07 -0000
@@ -0,0 +1,19 @@
+// $Id$
+
+Drupal.icecast = Drupal.icecast || {};
+
+Drupal.behaviors.emaudioIcecast = function (context) {
+       for (var i = 0; i < Drupal.settings.emaudioIcecast['fields'].length; i++) {
+               Drupal.icecast.updateSong(Drupal.settings.emaudioIcecast['fields'][i]);
+       }
+};
+
+Drupal.icecast.updateSong = function(streamId) {
+       var streamDetails = streamId.split('--');
+       var $container = $('#' + streamId);
+
+       $.get(Drupal.settings.basePath + 'emaudio/icecast/js/' + streamDetails[1] + '/' + streamDetails[2] + '/' + streamDetails[3], null, function(data){
+               var result = Drupal.parseJson(data);
+               $container.append(result['data']);
+       });
+}