You are here

soundcloudfield.module in SoundCloud field 6

Same filename and directory in other branches
  1. 8 soundcloudfield.module
  2. 7 soundcloudfield.module

SoundCloud CCK field.

@author Attila Fekete - attila.fekete@yahoo.co.uk

File

soundcloudfield.module
View source
<?php

/**
 * @file
 * SoundCloud CCK field.
 *
 *
 * @author Attila Fekete - attila.fekete@yahoo.co.uk
 */
define('SOUNDCLOUDFIELD_DEFAULT_WIDTH', 100);
define('SOUNDCLOUDFIELD_DEFAULT_HEIGHT', 81);
define('SOUNDCLOUDFIELD_DEFAULT_HEIGHT_SETS', 305);
define('SOUNDCLOUDFIELD_DEFAULT_HTML5_PLAYER_HEIGHT', 166);
define('SOUNDCLOUDFIELD_DEFAULT_HTML5_PLAYER_HEIGHT_SETS', 450);
define('SOUNDCLOUDFIELD_DEFAULT_VISUAL_PLAYER_HEIGHT', 450);

/**
 * Implementation of hook_theme().
 */
function soundcloudfield_theme() {
  return array(
    'soundcloud_url' => array(
      'arguments' => array(
        'element' => NULL,
      ),
    ),
    'soundcloudfield_formatter_default' => array(
      'arguments' => array(
        'element' => NULL,
      ),
    ),
    'soundcloudfield_formatter_html5' => array(
      'arguments' => array(
        'element' => NULL,
      ),
      'function' => 'theme_soundcloudfield_formatter_html5',
    ),
    'soundcloudfield_formatter_visual' => array(
      'arguments' => array(
        'element' => NULL,
      ),
      'function' => 'theme_soundcloudfield_formatter_html5',
    ),
    'soundcloudfield_formatter_link' => array(
      'arguments' => array(
        'element' => NULL,
      ),
    ),
  );
}

/**
 * Implementation of hook_field_info().
 */
function soundcloudfield_field_info() {
  return array(
    'soundcloudfield' => array(
      'label' => t('SoundCloud'),
      'description' => t('This CCK field stores a SoundCloud track or set URL.'),
      'callbacks' => array(
        'tables' => CONTENT_CALLBACK_DEFAULT,
        'arguments' => CONTENT_CALLBACK_DEFAULT,
      ),
    ),
  );
}

/**
 * Implementation of hook_field_settings().
 */
function soundcloudfield_field_settings($op, $field) {
  switch ($op) {
    case 'database columns':
      $columns = array(
        'embed' => array(
          'type' => 'varchar',
          'length' => 255,
          'not null' => FALSE,
          'sortable' => TRUE,
        ),
      );
      return $columns;
  }
}

/*
function _player_width_validate($element, &$form_state) {
  $value = $form_state['values']['width'];
  if ($value && !is_numeric($value) || $value < 1 || $value > 100) {
    form_set_error('width', t('Width must be a number between 1 and 100'));
  }
}
*/

/**
 * Implementation of hook_field().
 */
function soundcloudfield_field($op, &$node, $field, &$items, $teaser, $page) {
  switch ($op) {
    case 'validate':
      if (is_array($items)) {
        foreach ($items as $delta => $item) {
          $error_element = isset($item['_error_element']) ? $item['_error_element'] : '';
          if (is_array($item) && isset($item['_error_element'])) {
            unset($item['_error_element']);
          }
          if (!empty($item['embed']) && !preg_match('@^https?://soundcloud\\.com/([^"\\&]+)@i', $item['embed'], $matches)) {
            form_set_error($field['field_name'], t('"%url" is not a valid SoundCloud URL', array(
              '%url' => $item['embed'],
            )));
          }
        }
      }
      break;
    case 'sanitize':
      foreach ($items as $delta => $item) {
        $items[$delta]['safe'] = check_plain($item['embed']);
      }
      break;
  }
}

/**
 * Implementation of hook_content_is_empty().
 */
function soundcloudfield_content_is_empty($item, $field) {
  return empty($item['embed']);
}

/**
 * Implementation of hook_widget_info().
 */
function soundcloudfield_widget_info() {
  return array(
    'soundcloud_url' => array(
      'label' => t('SoundCloud URL'),
      'field types' => array(
        'soundcloudfield',
      ),
      'multiple values' => CONTENT_HANDLE_CORE,
      // or 'CONTENT_HANDLE_MODULE'
      'callbacks' => array(
        'default value' => CONTENT_CALLBACK_NONE,
      ),
    ),
  );
}

/**
 * Implementation of FAPI hook_elements().
 */
function soundcloudfield_elements() {
  return array(
    'soundcloud_url' => array(
      // widget name
      '#input' => TRUE,
      '#columns' => array(
        'embed',
      ),
      '#delta' => 0,
      '#process' => array(
        'soundcloudfield_process',
      ),
    ),
  );
}

/**
 * Implementation of hook_widget_settings().
 */
function soundcloudfield_widget_settings($op, $widget) {
  switch ($op) {
    case 'form':
      $form = array();
      if ($widget['type'] == 'soundcloud_url') {
        $width = variable_get('soundcloudfield_default_width', SOUNDCLOUDFIELD_DEFAULT_WIDTH);
        $height = variable_get('soundcloudfield_default_height', SOUNDCLOUDFIELD_DEFAULT_HEIGHT);
        $setheight = variable_get('soundcloudfield_default_setheight', SOUNDCLOUDFIELD_DEFAULT_HEIGHT_SETS);
        $form['player'] = array(
          '#type' => 'fieldset',
          '#title' => t('SoundCloud settings'),
          '#description' => t('SoundCloud field settings'),
          '#collapsible' => TRUE,
          '#collapsed' => FALSE,
        );
        $form['player']['width'] = array(
          '#type' => 'textfield',
          '#title' => t('Width'),
          '#size' => 4,
          '#default_value' => isset($widget['width']) && is_numeric($widget['width']) ? $widget['width'] : $width,
          '#required' => TRUE,
          '#description' => t('Player width in percent. Default is @width.', array(
            '@width' => $width,
          )),
        );
        $form['player']['height'] = array(
          '#type' => 'textfield',
          '#title' => t('Height for tracks'),
          '#size' => 4,
          '#default_value' => isset($widget['height']) && is_numeric($widget['height']) ? $widget['height'] : $height,
          '#required' => TRUE,
          '#description' => t('Player height for tracks. Default is @height.', array(
            '@height' => $height,
          )),
        );
        $form['player']['setheight'] = array(
          '#type' => 'textfield',
          '#title' => t('Height for sets'),
          '#size' => 4,
          '#default_value' => isset($widget['setheight']) && is_numeric($widget['setheight']) ? $widget['setheight'] : $setheight,
          '#required' => TRUE,
          '#description' => t('Player height for sets. Default is @height.', array(
            '@height' => $setheight,
          )),
        );
        $form['player']['showcomments'] = array(
          '#type' => 'checkbox',
          '#title' => t('Show comments'),
          '#default_value' => isset($widget['showcomments']) ? $widget['showcomments'] : FALSE,
          '#description' => t('Show comments in player.'),
        );
        $form['player']['autoplay'] = array(
          '#type' => 'checkbox',
          '#title' => t('Autoplay'),
          '#default_value' => isset($widget['autoplay']) ? $widget['autoplay'] : FALSE,
          '#description' => t('Player autoplay.'),
        );
        $form['player']['showplaycount'] = array(
          '#type' => 'checkbox',
          '#title' => t('Show play count'),
          '#default_value' => isset($widget['showplaycount']) ? $widget['showplaycount'] : FALSE,
          '#description' => t('Show play count in player.'),
        );
        $form['player']['showartwork'] = array(
          '#type' => 'checkbox',
          '#title' => t('Show artwork'),
          '#default_value' => isset($widget['showartwork']) ? $widget['showartwork'] : FALSE,
          '#description' => t('Show artwork in player.'),
        );
        $form['player']['color'] = array(
          '#type' => module_exists('jquery_colorpicker') ? 'colorpicker' : 'textfield',
          '#title' => t('Player color'),
          '#default_value' => isset($widget['color']) ? $widget['color'] : '0678be',
          '#required' => TRUE,
          '#description' => t('Player color in hexadecimal format. Default is 0678be. Turn on the jQuery Colorpicker module if available.'),
        );
      }
      return $form;
    case 'validate':
      if (!is_numeric($widget['width']) || intval($widget['width']) != $widget['width'] || $widget['width'] < 1 || $widget['width'] > 100) {
        form_set_error('width', t('Player width must be a positive integer between 1-100'));
      }
      if (!is_numeric($widget['height']) || intval($widget['height']) != $widget['height'] || $widget['height'] < 1) {
        form_set_error('height', t('Player height must be a positive integer.'));
      }
      if (!is_numeric($widget['setheight']) || intval($widget['setheight']) != $widget['setheight'] || $widget['setheight'] < 1) {
        form_set_error('setheight', t('Player height for sets must be a positive integer.'));
      }
    case 'save':
      if ($widget['widget_type'] == 'soundcloud_url') {
        $settings = array(
          'width',
          'height',
          'setheight',
          'showcomments',
          'autoplay',
          'showplaycount',
          'showartwork',
          'color',
        );
      }
      return $settings;
  }
}

/**
 * Implementation of hook_widget(). 
 */
function soundcloudfield_widget(&$form, &$form_state, $field, $items, $delta = 0) {
  $element = array(
    '#type' => $field['widget']['type'],
    '#default_value' => isset($items[$delta]) ? $items[$delta] : NULL,
  );
  return $element;
}

/**
 * Process an individual element. Build the form element.
 * 
 * #element['#value'] is already set
 *
 * The $fields array is in $form['#field_info'][$element['#field_name']]
 */
function soundcloudfield_process($element, $edit, $form_state, $form) {
  $field = $form['#field_info'][$element['#field_name']];
  $field_key = $element['#columns'][0];

  // $field_key = 'embed'
  $delta = $element['#delta'];
  $element[$field_key] = array(
    '#type' => 'textfield',
    '#title' => $element['#title'],
    '#description' => 'Here you can type the URL of the Soundcloud track or set',
    // $field['widget']['description']
    '#required' => $element['#required'],
    '#maxlength' => 255,
    '#size' => !empty($field['widget']['size']) ? $field['widget']['size'] : 48,
    '#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
  );
  return $element;
}
function theme_soundcloud_url($element) {
  return $element['#children'];
}

/**
 * Implementation of hook_field_formatter_info().
 */
function soundcloudfield_field_formatter_info() {
  return array(
    'default' => array(
      'label' => t('Flash player'),
      'field types' => array(
        'soundcloudfield',
      ),
      'multiple values' => CONTENT_HANDLE_CORE,
    ),
    'html5' => array(
      'label' => t('HTML5 player'),
      'field types' => array(
        'soundcloudfield',
      ),
      'multiple values' => CONTENT_HANDLE_CORE,
    ),
    'visual' => array(
      'label' => t('Visual player'),
      'field types' => array(
        'soundcloudfield',
      ),
      'multiple values' => CONTENT_HANDLE_CORE,
    ),
    'link' => array(
      'label' => t('Link'),
      'field types' => array(
        'soundcloudfield',
      ),
      'multiple values' => CONTENT_HANDLE_CORE,
    ),
  );
}

/**
 * Theme function for 'default' field formatter.
 *
 * Implementation of theme_formatter_default.
 *
 * @param $element
 * @return string
 */
function theme_soundcloudfield_formatter_default($element) {
  $output = '';

  // if (!empty($element['#item']['embed'])) {
  $field_info = soundcloudfield_get_content_node_field_instance_by_field_name($element['#field_name']);
  if ($field_info['widget_type'] == 'soundcloud_url') {
    $field_info['widget_settings'] = unserialize($field_info['widget_settings']);
    $width = $field_info['widget_settings']['width'];
    $color = $field_info['widget_settings']['color'];
    $showcomments = $field_info['widget_settings']['showcomments'] ? 'true' : 'false';
    $autoplay = $field_info['widget_settings']['autoplay'] ? 'true' : 'false';
    $showplaycount = $field_info['widget_settings']['showplaycount'] ? 'true' : 'false';
    $showartwork = $field_info['widget_settings']['showartwork'] ? 'true' : 'false';
    $encoded_url = urlencode($element['#item']['embed']);
    $parsed_url = parse_url($element['#item']['embed']);
    $splitted_url = explode("/", $parsed_url['path']);
    if ($splitted_url[2] != 'sets') {
      $height = $field_info['widget_settings']['height'];
      $params = 'url=' . $encoded_url . '&amp;show_comments=' . $showcomments . '&amp;auto_play=' . $autoplay . '&amp;color=' . $color;
    }
    else {
      $height = $field_info['widget_settings']['setheight'];
      $params = 'url=' . $encoded_url . '&amp;show_comments=' . $showcomments . '&amp;auto_play=' . $autoplay . '&amp;show_playcount=' . $showplaycount . '&amp;show_artwork=' . $showartwork . '&amp;color=' . $color;
    }
    $output .= '<object height="' . $height . '" width="' . $width . '%"><param name="movie" value="https://player.' . $parsed_url['host'] . '/player.swf?' . $params . '"></param>';
    $output .= '<param name="allowscriptaccess" value="always"></param><embed allowscriptaccess="always" height="' . $height . '" src="http://player.' . $parsed_url['host'] . '/player.swf?' . $params . '" type="application/x-shockwave-flash" width="' . $width . '%"></embed></object>';
  }
  return $output;

  // }
  // else {
  // return NULL;
  // }
}

/**
 * Theme function for 'html5' field formatter.
 *
 * @param $element
 * @return string
 */
function theme_soundcloudfield_formatter_html5($element) {
  $output = '';

  // $field = content_fields($element['#field_name'], $element['#type_name']);
  $oembed_endpoint = 'http://soundcloud.com/oembed';
  $field_info = soundcloudfield_get_content_node_field_instance_by_field_name($element['#field_name']);
  if ($field_info['widget_type'] == 'soundcloud_url') {
    $field_info['widget_settings'] = unserialize($field_info['widget_settings']);
    $field_info['display_settings'] = unserialize($field_info['display_settings']);
    $width = $field_info['widget_settings']['width'];
    $height = $field_info['widget_settings']['height'];
    $autoplay = $field_info['widget_settings']['autoplay'] ? 'true' : 'false';
    $showartwork = $field_info['widget_settings']['showartwork'] ? 'true' : 'false';
    $color = $field_info['widget_settings']['color'];
    $visual_player = $element['#formatter'] == 'visual' ? 'true' : 'false';
    $encoded_url = urlencode($element['#item']['embed']);
    $oembed_url = $oembed_endpoint . '?iframe=true&url=' . $encoded_url;
    $use_errors = libxml_use_internal_errors(TRUE);
    $oembed = simplexml_load_string(soundcloudfield_curl_get($oembed_url));
    if (!$oembed) {
      $output = t('The SoundCloud content at !url is not available, or it is set to private.', array(
        '!url' => l($element['#item']['embed'], $element['#item']['embed']),
      ));
    }
    else {

      // Replace player default settings with our settings,
      // set player width and height first.
      $final_iframe = preg_replace('/(width=)"([^"]+)"/', 'width="' . $width . '%"', $oembed->html);
      $final_iframe = preg_replace('/(height=)"([^"]+)"/', 'height="' . $height . '%"', $oembed->html);
      if (preg_match('/auto_play=(true|false)/', $final_iframe)) {
        $final_iframe = preg_replace('/auto_play=(true|false)/', 'auto_play=' . $autoplay, $final_iframe);
      }
      else {
        $final_iframe = preg_replace('/">/', '&auto_play=' . $autoplay . '">', $final_iframe);
      }
      if (preg_match('/show_artwork=(true|false)/', $final_iframe)) {
        $final_iframe = preg_replace('/show_artwork=(true|false)/', 'show_artwork=' . $showartwork, $final_iframe);
      }
      else {
        $final_iframe = preg_replace('/">/', '&show_artwork=' . $showartwork . '">', $final_iframe);
      }
      if (preg_match('/color=([a-zA-Z0-9]{6})/', $final_iframe)) {
        $final_iframe = preg_replace('/color=([a-zA-Z0-9]{6})/', 'color=' . $color, $final_iframe);
      }
      else {
        $final_iframe = preg_replace('/">/', '&color=' . $color . '">', $final_iframe);
      }

      // Set HTML5 player type based on formatter: classic/visual player.
      if (preg_match('/visual=(true|false)/', $final_iframe)) {
        $final_iframe = preg_replace('/visual=(true|false)/', 'visual=' . $visual_player, $final_iframe);
      }
      else {
        $final_iframe = preg_replace('/">/', '&visual=' . $visual_player . '">', $final_iframe);
      }
      $output = html_entity_decode($final_iframe);

      // '$oembed->html' for original embed
    }

    // More info: http://php.net/manual/en/function.libxml-use-internal-errors.php
    libxml_clear_errors();
    libxml_use_internal_errors($use_errors);
    return $output;
  }
}

/**
 * Theme function for 'link' field formatter.
 *
 * @param $element
 * @return string
 */
function theme_soundcloudfield_formatter_link($element) {
  $output = l($element['#item']['safe'], $element['#item']['safe']);
  return $output;
}

/**
 * Get the field instance by field name.
 *
 * Get field data from database.
 *
 * @param string $field_name
 * @return array with a row of content_node_field_instance table
 * 
 */
function soundcloudfield_get_content_node_field_instance_by_field_name($field_name) {
  return db_fetch_array(db_query("SELECT * FROM {content_node_field_instance} WHERE field_name = '%s'", $field_name));
}

/**
 * Curl helper function.
 */
function soundcloudfield_curl_get($url) {
  $curl = curl_init($url);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($curl, CURLOPT_TIMEOUT, 30);
  curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
  $return = curl_exec($curl);
  curl_close($curl);
  return $return;
}

Functions

Namesort descending Description
soundcloudfield_content_is_empty Implementation of hook_content_is_empty().
soundcloudfield_curl_get Curl helper function.
soundcloudfield_elements Implementation of FAPI hook_elements().
soundcloudfield_field Implementation of hook_field().
soundcloudfield_field_formatter_info Implementation of hook_field_formatter_info().
soundcloudfield_field_info Implementation of hook_field_info().
soundcloudfield_field_settings Implementation of hook_field_settings().
soundcloudfield_get_content_node_field_instance_by_field_name Get the field instance by field name.
soundcloudfield_process Process an individual element. Build the form element.
soundcloudfield_theme Implementation of hook_theme().
soundcloudfield_widget Implementation of hook_widget().
soundcloudfield_widget_info Implementation of hook_widget_info().
soundcloudfield_widget_settings Implementation of hook_widget_settings().
theme_soundcloudfield_formatter_default Theme function for 'default' field formatter.
theme_soundcloudfield_formatter_html5 Theme function for 'html5' field formatter.
theme_soundcloudfield_formatter_link Theme function for 'link' field formatter.
theme_soundcloud_url

Constants