audio_player-1.0.x-dev/audio_player.module
audio_player.module
<?php
/**
* @file
* Audio player module.
*/
use Drupal\Component\Utility\Html;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\audio_player\Plugin\views\style\ViewsAudioPlayer;
use Drupal\file\Entity\File;
use Drupal\media\Entity\Media;
/**
* Implements hook_help().
*/
function audio_player_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the audio_player module.
case 'help.page.audio_player':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('Audio Player provides a field formatter that allows
you to apply it to your image field.') . '</p>';
return $output;
default:
}
}
/**
* Implements hook_theme().
*/
function audio_player_theme() {
return [
'audio_player' => [
'variables' => [
'audios' => NULL,
'data_attributes' => NULL,
'skin' => NULL,
'audio_display' => NULL,
'template_part' => NULL,
'equalizer' => NULL,
'palette' => NULL,
],
'template' => 'audio-player',
],
];
}
/**
* Implements hook_preprocess_audio_player().
*/
function template_preprocess_audio_player(&$variables) {
$skin = $variables['skin'] ?? '';
$audio_display = $variables['audio_display'] ?? '';
$equalizer = $variables['equalizer'] ?? '';
$variables['#attached']['library'][] = "audio_player/audio_player.base";
// Determine the library only if skin or audio_display is set.
if ($skin || $audio_display) {
$library = $audio_display && $skin ? "{$audio_display}.{$skin}" : $skin;
// Attach the library if determined.
$variables['#attached']['library'][] = "audio_player/audio_player.{$library}";
}
if ($equalizer) {
$variables['#attached']['library'][] = "audio_player/audio_player.equalizer";
}
if ($audio_display) {
$variables['#attached']['library'][] = "audio_player/audio_player.playlist-color-palettes";
}
else {
$variables['#attached']['library'][] = "audio_player/audio_player.color-palettes";
}
}
/**
* Returns a list of available audio player skin options for one player.
*
* This function provides a set of predefined skins for the audio player
* interface. Each skin has a unique identifier (e.g., 'skin-one', 'skin-two')
* and a human-readable label (e.g., 'Skin One', 'Skin Two') that can be used
* in the UI to allow users to choose a skin for the audio player.
*
* @return array
* An array with skin IDs as keys and readable labels as values.
*/
function audio_player_single_audio_skins() {
return [
'skin-one' => 'Skin One',
'skin-two' => 'Skin Two',
'skin-three' => 'Skin Three',
'skin-four' => 'Skin Four',
'skin-five' => 'Skin Five',
'skin-six' => 'Skin Six',
'skin-seven' => 'Skin Seven',
'skin-eight' => 'Skin Eight',
'skin-nine' => 'Skin Nine',
'skin-ten' => 'Skin Ten',
'skin-eleven' => 'Skin Eleven',
'skin-twelve' => 'Skin Twelve',
'skin-thirteen' => 'Skin Thirteen',
'skin-fourteen' => 'Skin Fourteen',
'skin-fifteen' => 'Skin Fifteen',
'skin-sixteen' => 'Skin Sixteen',
'skin-seventeen' => 'Skin Seventeen',
'skin-eighteen' => 'Skin Eighteen',
];
}
/**
* Returns a list of available audio player skin options for an audio playlist.
*
* This function provides a simplified set of skin options that are specific
* to the audio playlist interface. Similar to the single audio skins, but with
* fewer options for playlist displays.
*
* @return array
* An array with skin IDs as keys and user-friendly labels as values.
*/
function audio_player_audio_playlist_skins() {
return [
'skin-one' => 'Skin One',
'skin-two' => 'Skin Two',
];
}
/**
* Returns a list of available equalizer visualizations for the player.
*
* This function offers a variety of equalizer visualizations that can
* be applied to the audio player.
* The available options include different styles such as waveform,
* frequency, circular, and more. Each option has a unique identifier
* and a user-friendly label that will be displayed to the user in the UI.
*
* @return array
* An array with visualization IDs as keys and readable labels as values.
*/
function audio_player_equalizer_options() {
return [
'' => t('None'),
'waveform' => t('Waveform'),
'frequency' => t('Frequency'),
'circular' => t('Circular'),
'dots' => t('Dots'),
'blob' => t('Blob'),
'audioSpectrumVisualizer' => t('Audio Spectrum Visualizer'),
'soundwave' => t('Soundwave'),
'visualEqualizer' => t('Visual Equalizer'),
'wavesurferLike' => t('Wavesurfer Like'),
'audioSoundGraphic' => t('Audio Sound Graphic'),
'verticalSymmetricalBars' => t('Vertical Symmetrical Bars'),
'particleCloud' => t('Particle Cloud'),
'rotatingRing' => t('Rotating Ring'),
'abstractLines' => t('Abstract Lines'),
'spherePulse' => t('Sphere Pulse'),
'lineGrid' => t('Line Grid'),
'growingCircles' => t('Growing Circles'),
'raindropEffect' => t('Raindrop Effect'),
'tunnelEffect' => t('Tunnel Effect'),
'firefliesSwarm' => t('Fireflies Swarm'),
'pixelGridHeatmap' => t('Pixel Grid Heatmap'),
'lissajousCurve' => t('Lissajous Curve'),
'rippleEffect' => t('Ripple Effect'),
'glowTrails' => t('Glow Trails'),
'rainAndLightning' => t('Rain and Lightning'),
'dataStream' => t('Data Stream'),
'vortexSpectrum' => t('Vortex Spectrum'),
];
}
/**
* Returns a list of available color palette options for the audio player.
*
* This function defines a set of color schemes (palettes) that can be
* applied to the audio player. Each palette has a unique identifier
* (e.g., 'palette-1', 'palette-2') and a descriptive name
* (e.g., 'Deep Ocean Green', 'Warm Amber Charcoal'). These palettes can
* be used to customize the appearance of the audio player interface.
*
* @return array
* An array with palette IDs as keys and readable palette names as values.
*/
function audio_player_palette_options() {
$palettes = [
'default-palette' => 'Default',
'palette-1' => 'Deep Ocean Green (Dark blue/grey base with vibrant green accent)',
'palette-2' => 'Warm Amber Charcoal (Dark, muted base with a bright amber/gold accent)',
'palette-3' => 'Royal Plum Pink (Deep purple/plum base with a vibrant fuchsia/pink accent)',
'palette-4' => 'Cadet Blue Steel (Cool blue/grey base with a bright light blue accent)',
'palette-5' => 'Dark Mode Orange Pop (Dark grey base with a striking amber orange accent)',
'palette-6' => 'Midnight Violet (Nearly black base with a deep purple accent)',
'palette-7' => 'Twilight Deep Orange (Dark purple-ish base with a bold deep orange accent)',
'palette-8' => 'Forest Sage Green (Dark green base with a muted, earthy green accent)',
'palette-9' => 'Urban Cyan Grey (Dark grey base with a cool cyan accent)',
'palette-10' => 'Nautical Blue Grey (Deep blue/grey base with a classic vibrant blue accent)',
'palette-11' => 'Crisp Light Gray (Very light grey/white base with a dark grey accent)',
'palette-12' => 'Cotton Candy Pink (White base with a vibrant pink accent)',
'palette-13' => 'Earthy Sepia Tone (Warm, light beige/brown base with a deeper brown accent)',
'palette-14' => 'Sky Blue Serenity (Light blue/green base with a bright light blue accent)',
'palette-15' => 'Lavender Haze (Light grey base with a deep purple accent)',
'palette-16' => 'Minty Fresh Green (Light green base with a standard Google Green accent)',
'palette-17' => 'Sandy Gold Glow (Light sandy/yellow base with a bright amber/gold accent)',
'palette-18' => 'Arctic Red Ember (Very light grey/white base with a strong red accent)',
'palette-19' => 'Porcelain Aqua Blue (Light grey base with a soft, bright blue accent)',
'palette-20' => 'Modern Blue & White (Classic white base with a vibrant blue accent)',
];
return $palettes;
}
/**
* Generate a clean, human-readable audio file name.
*
* This function processes an audio file name by removing its extension,
* cleaning up any special characters, trimming excess spaces, and capitalizing
* the first letter of the first word in the name.
*
* @param string $name
* string $name The original audio file name.
*
* @return string
* string The cleaned audio file name.
*/
function audio_player_generate_name($name) {
$name = preg_replace('/\.(mp3|wav|flac|aac|ogg|m4a|wma)$/i', '', $name);
// Removes special characters, allows spaces.
$cleanString = preg_replace('/[^a-zA-Z0-9\s]/', '', $name);
$cleanString = trim($cleanString);
$cleanString = Html::escape(ucfirst(strtolower($cleanString)));
// Return the final cleaned filename without any extension.
return $cleanString;
}
/**
* Implements hook_preprocess_views_view().
*/
function audio_player_preprocess_views_view(array &$variables) {
$view = $variables['view'];
// Check if the view uses the specific StylePluginBase.
if ($view->style_plugin instanceof ViewsAudioPlayer) {
$style_plugin = $view->style_plugin->options;
$audio_player_title = $style_plugin['audio_player_title'] ?? '';
$audio_player_subtitle = $style_plugin['audio_player_subtitle'] ?? '';
$audio_player_video = $style_plugin['audio_player_video'] ?? '';
$audio_player_thumbnail = $style_plugin['audio_player_thumbnail'] ?? '';
$file_url_generator = \Drupal::service('file_url_generator');
// Optimize field value and URL generation.
foreach ($view->result as &$row) {
$entity = $row->_entity;
// Get the URL for the audio or video field.
$video_url = audio_player_get_field_url($file_url_generator, $entity, $audio_player_video);
if ($video_url) {
$video_title = isset($entity->{$audio_player_title}) ? Html::escape($entity->{$audio_player_title}->value) : NULL;
$video_subtitle = isset($entity->{$audio_player_subtitle}) ? Html::escape($entity->{$audio_player_subtitle}->value) : '';
if (!$video_title) {
$video_title = basename($video_url);
$video_title = urldecode($video_title);
}
$video_title = audio_player_generate_name($video_title);
$row->video_title = $video_title;
$row->video_subtitle = $video_subtitle;
$row->video_url = $video_url;
$row->video_thumbnail = $audio_player_thumbnail;
}
else {
\Drupal::logger('audio_player')->error('No valid URL found for video field for entity ID: @entity_id', ['@entity_id' => $entity->id()]);
}
}
// Attach style and scripts for the audio player.
$variables['skin'] = $style_plugin['skin'] ?? '';
$variables['#attached']['library'] = array_merge(
$variables['#attached']['library'] ?? [],
[
'audio_player/audio_player.playlist-color-palettes',
'audio_player/audio_player.base',
"audio_player/audio_player.audio-playlist.{$variables['skin']}",
]
);
// Attach equalizer effect if needed.
if (!empty($style_plugin['equalizer_effect'])) {
$variables['#attached']['library'][] = 'audio_player/audio_player.equalizer';
}
$variables['#cache'] = ['max-age' => 0];
}
}
/**
* Helper function to get the field URL for audio/video.
*/
function audio_player_get_field_url($file_url_generator, $entity, $audio_player_video) {
// Get the field value.
$field_value = $entity->get($audio_player_video)->first();
if (isset($field_value->entity)) {
// If the field is a file (direct file upload)
if ($field_value->entity instanceof File) {
return audio_player_generate_file_url($file_url_generator, $field_value->entity);
}
elseif ($field_value->entity instanceof Media) {
// If the field is a media entity (media reference)
$media = $field_value->entity;
$fid = $media->getSource()->getSourceFieldValue($media);
return audio_player_generate_file_url($file_url_generator, File::load($fid));
}
}
// Default if no valid URL found.
return NULL;
}
/**
* Helper function to generate an absolute URL from a file.
*/
function audio_player_generate_file_url($file_url_generator, File $file) {
if ($file->getMimeType() && in_array($file->getMimeType(), ['audio/mpeg', 'audio/wav', 'audio/flac'])) {
$uri = $file->getFileUri();
return $file_url_generator->generateAbsoluteString($uri);
}
else {
// Log or handle invalid file type.
\Drupal::logger('audio_player')->warning('Invalid file type detected for file with URI: ' . $uri);
return NULL;
}
}
/**
* Prepares variables for the Views Timeline.
*/
function template_preprocess_views_audio_player(&$variables) {
$view = $variables['view'];
$style_plugin = $view->style_plugin->options;
// Extract style options with null coalescing for defaults.
$skin = $style_plugin['skin'] ?? '';
$variables['audio_player_title'] = $style_plugin['audio_player_title'] ?? '';
$equalizer = $style_plugin['equalizer_effect'] ?? '';
$variables['equalizer'] = $equalizer;
$variables['palette'] = $style_plugin['palette'] ?? '';
$variables['thumbnail'] = $style_plugin['audio_player_thumbnail'] ?? '';
$variables['data_attributes'] = ['equalizer' => $equalizer];
// Template layout base path.
$audio_player_layout = 'audio-playlist/' . $skin;
$layout = $audio_player_layout . '.html.twig';
// Get theme and module paths.
$theme = \Drupal::theme()->getActiveTheme();
$theme_path = $theme->getPath() . '/templates/' . $layout;
$module_path = \Drupal::moduleHandler()->getModule('audio_player')->getPath() . '/templates/' . $layout;
// Set template part based on the existence of the theme or module template.
if (file_exists($theme_path)) {
$variables['template_part'] = '@' . $theme->getName() . '/' . $audio_player_layout . '.html.twig';
}
elseif (file_exists($module_path)) {
$variables['template_part'] = '@audio_player/' . $audio_player_layout . '.html.twig';
}
}
