You are here

soundcloudfield.module in SoundCloud field 7

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

@author Attila Fekete - http://drupal.org/user/762986

File

soundcloudfield.module
View source
<?php

/**
 * @file
 *
 *
 *
 * @author Attila Fekete - http://drupal.org/user/762986
 */
define('SOUNDCLOUDFIELD_DEFAULT_WIDTH', 100);
define('SOUNDCLOUDFIELD_DEFAULT_HTML5_PLAYER_HEIGHT', 166);
define('SOUNDCLOUDFIELD_DEFAULT_HTML5_PLAYER_HEIGHT_SETS', 450);

// Usable sizes for visual player: 300, 450, 600.
define('SOUNDCLOUDFIELD_DEFAULT_VISUAL_PLAYER_HEIGHT', 450);

/**
 * Implements hook_field_info().
 */
function soundcloudfield_field_info() {
  return array(
    'soundcloud' => array(
      'label' => t('SoundCloud'),
      'description' => t('This field stores a SoundCloud track or set URL.'),
      'instance_settings' => array(
        'width' => SOUNDCLOUDFIELD_DEFAULT_WIDTH,
        'autoplay' => FALSE,
        'showplaycount' => FALSE,
        'showartwork' => FALSE,
        'color' => 'ff7700',
        'html5_player_height' => SOUNDCLOUDFIELD_DEFAULT_HTML5_PLAYER_HEIGHT,
        'html5_player_height_sets' => SOUNDCLOUDFIELD_DEFAULT_HTML5_PLAYER_HEIGHT_SETS,
        // New visual player setting.
        'visual_player_height' => SOUNDCLOUDFIELD_DEFAULT_VISUAL_PLAYER_HEIGHT,
      ),
      'default_widget' => 'soundcloud_url',
      'default_formatter' => 'soundcloud_html5',
    ),
  );
}

/**
 * Implements hook_field_validate().
 *
 * Pseudo-hook.
 */
function soundcloudfield_field_validate($entity_type, $entity, $field, $instance, $langcode, &$items, &$errors) {
  if ($field['type'] == 'soundcloud') {
    foreach ($items as $delta => $item) {
      if (!empty($item['url']) && !preg_match('@^https?://soundcloud\\.com/([^"\\&]+)@i', $item['url'], $matches)) {
        $errors[$field['field_name']][$langcode][$delta][] = array(
          'error' => 'soundcloudfield_invalid_url',
          'message' => t('%url is not a valid SoundCloud URL.', array(
            '%url' => $item['url'],
          )),
        );
      }
    }
  }
}

/**
 * Implements hook_field_is_empty().
 *
 * Pseudo-hook.
 */
function soundcloudfield_field_is_empty($item, $field) {
  if ($field['type'] == 'soundcloud') {
    if (empty($item['url'])) {
      return TRUE;
    }
  }
  return FALSE;
}

/**
 * Implements hook_field_settings_form().
 *
 * Pseudo-hook.
 */
function soundcloudfield_field_instance_settings_form($field, $instance) {
  $settings = $instance['settings'];
  if ($field['type'] == 'soundcloud') {
    $form = array(
      '#element_validate' => array(
        'soundcloudfield_settings_form_validate',
      ),
    );
    $form['soundcloudplayer'] = array(
      '#type' => 'fieldset',
      '#title' => t('SoundCloud settings'),
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
    );
    $form['soundcloudplayer']['width'] = array(
      '#type' => 'textfield',
      '#title' => t('Width'),
      '#size' => 4,
      '#default_value' => empty($settings['soundcloudplayer']['width']) ? SOUNDCLOUDFIELD_DEFAULT_WIDTH : $settings['soundcloudplayer']['width'],
      '#description' => t('Player width in percent. Default is @width.', array(
        '@width' => SOUNDCLOUDFIELD_DEFAULT_WIDTH,
      )),
      '#required' => TRUE,
      '#element_validate' => array(
        'element_validate_integer_positive',
      ),
    );

    // HTML5 (classic) player-only settings.
    $form['soundcloudplayer']['html5_player'] = array(
      '#type' => 'fieldset',
      '#title' => t('SoundCloud HTML5 player-only settings'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );
    $form['soundcloudplayer']['html5_player']['html5_player_height'] = array(
      '#type' => 'textfield',
      '#title' => t('Height for tracks'),
      '#size' => 4,
      '#default_value' => empty($settings['soundcloudplayer']['html5_player']['html5_player_height']) ? SOUNDCLOUDFIELD_DEFAULT_HTML5_PLAYER_HEIGHT : $settings['soundcloudplayer']['html5_player']['html5_player_height'],
      '#description' => t('Player height for tracks. Default is @height.', array(
        '@height' => SOUNDCLOUDFIELD_DEFAULT_HTML5_PLAYER_HEIGHT,
      )),
      '#required' => TRUE,
      '#element_validate' => array(
        'element_validate_integer_positive',
      ),
    );
    $form['soundcloudplayer']['html5_player']['html5_player_height_sets'] = array(
      '#type' => 'textfield',
      '#title' => t('Height for sets'),
      '#size' => 4,
      '#default_value' => empty($settings['soundcloudplayer']['html5_player']['html5_player_height_sets']) ? SOUNDCLOUDFIELD_DEFAULT_HTML5_PLAYER_HEIGHT_SETS : $settings['soundcloudplayer']['html5_player']['html5_player_height_sets'],
      '#description' => t('Player height for sets. Default is @height.', array(
        '@height' => SOUNDCLOUDFIELD_DEFAULT_HTML5_PLAYER_HEIGHT_SETS,
      )),
      '#required' => TRUE,
      '#element_validate' => array(
        'element_validate_integer_positive',
      ),
    );

    // Visual (new) player-only settings.
    $form['soundcloudplayer']['visual_player'] = array(
      '#type' => 'fieldset',
      '#title' => t('SoundCloud HTML5 visual player-only settings'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );
    $form['soundcloudplayer']['visual_player']['visual_player_height'] = array(
      '#type' => 'select',
      '#title' => t('Size of the visual player (height):'),
      '#default_value' => empty($settings['soundcloudplayer']['visual_player']['visual_player_height']) ? SOUNDCLOUDFIELD_DEFAULT_VISUAL_PLAYER_HEIGHT : $settings['soundcloudplayer']['visual_player']['visual_player_height'],
      '#options' => array(
        300 => '300px',
        450 => '450px',
        600 => '600px',
      ),
      '#description' => t('Height of the "new" HTML5 visual player.'),
    );

    // Common settings.
    $form['soundcloudplayer']['autoplay'] = array(
      '#type' => 'checkbox',
      '#title' => t('Autoplay'),
      '#default_value' => empty($settings['soundcloudplayer']['autoplay']) ? FALSE : $settings['soundcloudplayer']['autoplay'],
      '#description' => t('Autoplay track or set.'),
    );
    $form['soundcloudplayer']['showplaycount'] = array(
      '#type' => 'checkbox',
      '#title' => t('Show play count'),
      '#default_value' => empty($settings['soundcloudplayer']['showplaycount']) ? FALSE : $settings['soundcloudplayer']['showplaycount'],
      '#description' => t('Show play count in player.'),
    );
    $form['soundcloudplayer']['showartwork'] = array(
      '#type' => 'checkbox',
      '#title' => t('Show artwork'),
      '#default_value' => empty($settings['soundcloudplayer']['showartwork']) ? FALSE : $settings['soundcloudplayer']['showartwork'],
      '#description' => t('Show artwork in player. Has no effect when using the visual player.'),
    );
    $form['soundcloudplayer']['color'] = array(
      '#type' => module_exists('jquery_colorpicker') ? 'jquery_colorpicker' : 'textfield',
      '#title' => t('Player color'),
      '#default_value' => empty($settings['soundcloudplayer']['color']) ? 'ff7700' : $settings['soundcloudplayer']['color'],
      '#required' => TRUE,
      '#description' => t('Player color in hexadecimal format. Default is ff7700. Turn on the jQuery Colorpicker module if available.'),
    );
  }
  return $form;
}

/**
 * Validate the field settings form.
 */
function soundcloudfield_settings_form_validate($element, &$form_state, $complete_form) {

  // Validate width.
  $width = $form_state['values']['instance']['settings']['soundcloudplayer']['width'];
  if (!empty($width) && ($width < 1 || $width > 100)) {
    form_set_error('instance][settings][soundcloudplayer][width', t('Player width must be a positive integer between 1-100'));
  }
}

/**
 * Implements hook_widget_info().
 */
function soundcloudfield_field_widget_info() {
  return array(
    'soundcloud_url' => array(
      'label' => t('SoundCloud URL'),
      'field types' => array(
        'soundcloud',
      ),
      'behaviors' => array(
        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
        'default value' => FIELD_BEHAVIOR_DEFAULT,
      ),
    ),
  );
}

/**
 * Implements hook_field_widget_form().
 *
 * Pseudo-hook.
 */
function soundcloudfield_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $base = $element;
  if ($instance['widget']['type'] == 'soundcloud_url') {
    $element['url'] = array(
      '#type' => 'textfield',
      '#default_value' => isset($items[$delta]['url']) ? $items[$delta]['url'] : NULL,
      '#maxlength' => 255,
    ) + $base;
  }
  return $element;
}

/**
 * Implements hook_field_formatter_info().
 */
function soundcloudfield_field_formatter_info() {
  return array(
    'soundcloud_html5' => array(
      'label' => t('HTML5 player'),
      'field types' => array(
        'soundcloud',
      ),
      'settings' => array(
        // Give a default value for when the form is first loaded.
        'player_type' => 'classic',
      ),
    ),
    'soundcloud_link' => array(
      'label' => t('Link'),
      'field types' => array(
        'soundcloud',
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_settings_form().
 */
function soundcloudfield_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {

  // This gets the view_mode where our settings are stored.
  $display = $instance['display'][$view_mode];

  // This gets the actual settings.
  $settings = $display['settings'];

  // Initialize the element variable.
  $element = array();

  // Add select box, for HTML5 only.
  if (strpos($display['type'], '_html5') !== FALSE) {
    $element['player_type'] = array(
      '#type' => 'select',
      '#title' => t('HTML5 player type'),
      '#description' => t('Select which HTML5 player to use.'),
      '#default_value' => $settings['player_type'],
      '#options' => array(
        'classic' => 'Classic (old)',
        'visual' => 'Visual Player (new)',
      ),
    );
  }
  return $element;
}

/**
 * Implements hook_field_formatter_settings_summary().
 */
function soundcloudfield_field_formatter_settings_summary($field, $instance, $view_mode) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $summary = '';
  if (strpos($display['type'], '_html5') !== FALSE) {
    $summary = t('Use the ') . $settings['player_type'] . t(' HTML5 player.');
  }
  return $summary;
}

/**
 * Implements hook_field_formatter_view().
 */
function soundcloudfield_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();

  // if player custom settings array is not available, use default settings
  if (!empty($instance['settings']['soundcloudplayer'])) {
    $settings = $instance['settings']['soundcloudplayer'];
  }
  else {
    $settings = $instance['settings'];
    watchdog('soundcloudfield', 'Instance settings array is missing. Falling back to default player settings.', NULL, WATCHDOG_WARNING);
  }

  // Get the "common" settings.
  $autoplay = $settings['autoplay'] ? 'true' : 'false';
  $showplaycount = $settings['showplaycount'] ? 'true' : 'false';
  $showartwork = $settings['showartwork'] ? 'true' : 'false';
  $color = $settings['color'];
  switch ($display['type']) {

    // HTML5 (classic or visual) player case.
    case 'soundcloud_html5':
      $oembed_endpoint = 'https://soundcloud.com/oembed';

      // Get HTML5 player-specific settings.
      $html5_player_height = empty($settings['html5_player']['html5_player_height']) ? SOUNDCLOUDFIELD_DEFAULT_HTML5_PLAYER_HEIGHT : $settings['html5_player']['html5_player_height'];
      $html5_player_height_sets = empty($settings['html5_player']['html5_player_height_sets']) ? SOUNDCLOUDFIELD_DEFAULT_HTML5_PLAYER_HEIGHT_SETS : $settings['html5_player']['html5_player_height_sets'];
      $visual_player = $display['settings']['player_type'] == 'visual' ? 'true' : 'false';
      foreach ($items as $delta => $item) {
        $output = '';
        $encoded_url = urlencode($item['url']);

        // Set the proper height for this item.
        // - classic player: track default is 166px, set default is 450px.
        // - visual player: player height it's the same for tracks and sets.
        if ($visual_player == 'true') {
          $iframe_height = $settings['visual_player']['visual_player_height'];
        }
        else {
          $parsed_url = parse_url($item['url']);
          $splitted_url = explode("/", $parsed_url['path']);

          // An artist page or a set or a track?
          $iframe_height = !isset($splitted_url[2]) || $splitted_url[2] == 'sets' ? $html5_player_height_sets : $html5_player_height;
        }

        // Create the URL
        $oembed_url = $oembed_endpoint . '?iframe=true&format=json&url=' . $encoded_url;

        // curl get
        $soundcloud_curl_get = soundcloudfield_curl_get($oembed_url);
        if ($soundcloud_curl_get != ' ') {

          // Load in the oEmbed XML
          $oembed = drupal_json_decode($soundcloud_curl_get);

          // Replace player default settings with our settings,
          // set player width and height first.
          $final_iframe = preg_replace('/(width=)"([^"]+)"/', 'width="' . $settings['width'] . '%"', $oembed['html']);
          $final_iframe = preg_replace('/(height=)"([^"]+)"/', 'height="' . $iframe_height . '"', $oembed['html']);

          // Set autoplay.
          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);
          }

          // Show playcount?
          if (preg_match('/show_playcount=(true|false)/', $final_iframe)) {
            $final_iframe = preg_replace('/show_playcount=(true|false)/', 'show_playcount=' . $showplaycount, $final_iframe);
          }
          else {
            $final_iframe = preg_replace('/">/', '&show_playcount=' . $showplaycount . '">', $final_iframe);
          }

          // Show artwork?
          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);
          }

          // Set player color.
          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);
          }

          // Final output. Use '$oembed->html' for original embed code.
          $output = html_entity_decode($final_iframe);
        }
        else {
          $output = t('The SoundCloud content at !url is not available, or it is set to private.', array(
            '!url' => l($item['url'], $item['url']),
          ));
        }
        $element[$delta] = array(
          '#markup' => $output,
        );
      }
      break;

    // Link formatter.
    case 'soundcloud_link':
      foreach ($items as $delta => $item) {
        $element[$delta] = array(
          '#markup' => l($item['url'], $item['url']),
        );
      }
      break;
  }
  return $element;
}

/**
 * Implement hook_field_error().
 */
function soundcloudfield_field_widget_error($element, $error) {
  switch ($error['error']) {
    case 'soundcloudfield_invalid_url':
      form_error($element, $error['message']);
      break;
  }
}

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