'. t('The audio module allows users to add audio media content to a site. Audio is an important medium for community communication. The recent rise of the podcast phenomenon is an example of the trend towards audio content. The audio module enables music, spoken word, and voicemail messages to be played on a site.', array('%elink-en-wikipedia-org' => 'http://en.wikipedia.org/wiki/Podcast')) .'

'; $output .= '

'. t('The audio module allows a user to create a new audio post. An audio post lets you upload, stream, and download audio files, and uses the getID3 library to read and write ID3 tag information from the audio file. The getID3 library is required. This module comes with a handy flash player that can be embeded in your site. Audio files can be submitted by browsing users computer for files to upload. Audio posts can also be configured to allow the files to be downloaded. Audio administration allows the path for audio files to be uploaded to be configured. The getID3 library can also be configured in audio administration.', array('%elink-en-wikipedia-org' => 'http://en.wikipedia.org/wiki/Id3')) .'

'; $output .= t('

You can:

', array('%user' => url('user'), '%node-add-audio' => url('node/add/audio'), '%admin-block' => url('admin/block'), '%admin-settings-audio' => url('admin/settings/audio'), '%elink-prdownloads-sourceforge-net' => 'http://prdownloads.sourceforge.net/getid3')); $output .= '

'. t('For more information please read the configuration and customization handbook Audio page.', array('%audio' => 'http://www.drupal.org/handbook/modules/audio/')) .'

'; return $output; case 'admin/modules#description': return t('Allows uploading and playback of audio files.'); case 'node/add#audio': return t('An audio file. The audio file could be used for adding music, podcasts, or audio clips to your site.'); } } /** * Implementation of hook_node_name */ function audio_node_name() { return t('audio'); } /** * Implementation of hook_perm */ function audio_perm() { return array('administer audio', 'create audio'); } /** * Implementation of hook_access */ function audio_access($op, $node = null) { global $user; if ($op == 'create' && user_access('create audio')) { return TRUE; } if ($op == 'update' && $user->uid == $node->uid) { return TRUE; } if ($op == 'delete' && $user->uid == $node->uid) { return TRUE; } } /** * Implementation of hook_settings */ function audio_settings() { _audio_check_settings(); $output.= form_hidden('audio_updated', time()); $paths .= form_textfield(t('Path to uploaded audio files'), 'audio_default_path', variable_get('audio_default_path', 'audio'), 30, 255, t('Subdirectory in the directory "%dir" where audio files will be stored.', array('%dir' => ''. variable_get('file_directory_path', 'files') .'/'))); $paths .= form_textfield(t('Path to the \'getID3\' folder'), 'audio_getid3_path', variable_get('audio_getid3_path', drupal_get_path('module', 'audio').'/getid3/'), 30, 255, t('The path to the \'getid3\' library folder. (include trailing slash.)')); $output.= form_group(t('File paths'), $paths); return $output; } /** * Implementation of hook_menu */ function audio_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array('path' => 'node/add/audio', 'title' => t('audio'), 'access' => user_access('create audio'), 'type' => MENU_NORMAL_ITEM); $items[] = array('path' => 'audio', 'title' => t('audio files'), 'access' => user_access('access content'), 'type' => MENU_SUGGESTED_ITEM, 'callback' => 'audio_page'); $items[] = array('path' => 'audio/download', 'title' => t('audio'), 'access' => user_access('access content'), 'type' => MENU_CALLBACK, 'callback' => 'audio_fetch'); $items[] = array('path' => 'audio/play', 'title' => t('audio'), 'access' => user_access('access content'), 'type' => MENU_CALLBACK, 'callback' => 'audio_play'); $items[] = array('path' => 'admin/audio/add', 'title' => t('add audio'), 'access' => user_access('administer audio'), 'type' => MENU_LOCAL_TASK); } return $items; } /** * Implementation of hook_link. */ function audio_link($type, $node, $main = 0) { $links = array(); if ($type == 'node' && $node->type == 'audio' && _is_downloadable($node->audio['fid'])) $links[] = l(t('download audio file'), 'audio/download/'.$node->nid, NULL); return $links; } /** * Implementation of hook_nodeapi(). */ function audio_nodeapi(&$node, $op, $arg) { global $base_url; switch ($op) { case 'rss item': //NOTE: RSS only allows one enclosure per item if ($node->type == 'audio' && $node->audio['fid']) { $node->teaser = db_result(db_query("SELECT body FROM {node} WHERE nid=%d", $node->nid)); $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE nid=%d", $node->nid)); return array(array('key' => 'enclosure', 'attributes' => array('url' => $GLOBALS['base_url'].'/'.variable_get('file_directory_path', 'files') .'/'.variable_get('audio_default_path', 'audio') .'/'. rawurlencode($file->filename), 'length' => $file->filesize, 'type' => $file->filemime))); } break; } } /** * Implementation of hook_block. * * Offers 2 blocks: latest audio and random audio */ function audio_block($op, $delta = 0) { switch ($op) { case 'list': $block[0]['info'] = t('Latest audio'); $block[1]['info'] = t('Random audio'); return $block; case 'view': if (user_access('access content')) { switch($delta) { case 0: $audio = audio_get_latest(); $block['subject'] = t('Latest audio'); $block['content'] = theme('audio_block', $audio[0]); break; case 1: $audio = audio_get_random(); $block['subject'] = t('Random audio'); $block['content'] = theme('audio_block', $audio[0]); break; } } return $block; } } /** * Fetch a random N audio file(s) - optionally from a given term. */ function audio_get_random($count = 1, $tid = 0) { $result = db_query_range(db_rewrite_sql("SELECT nid FROM {node} n WHERE n.type='audio' AND n.status=1 ORDER BY RAND()"), 0, $count); $output = array(); while ($nid = db_fetch_object($result)) { $output[] = node_load(array('nid' => $nid->nid)); } return $output; } /** * Fetch the latest N audio files(s). */ function audio_get_latest($count = 1, $tid = 0) { $result = db_query_range(db_rewrite_sql("SELECT nid FROM {node} n WHERE n.type='audio' AND n.status=1 ORDER BY changed DESC"), 0, $count); $output = array(); while ($nid = db_fetch_object($result)) { $output[] = node_load(array('nid' => $nid->nid)); } return $output; } /** * Implementation of hook_form */ function audio_form(&$node, &$param) { _audio_check_settings(); // This sets the form param reference. $param['options'] = array("enctype" => "multipart/form-data", "name" => "audio_forms"); $output .= form_textarea(t('Description'), 'body', $node->body, 60, 10, '', NULL, TRUE); $output .= form_hidden('audio_file_tmp', _is_set_or($node->audio['filepath'], $node->audio_file_tmp->filepath)); // Taxonomy select form if (module_exist('taxonomy')) $output .= implode('', taxonomy_node_form('audio', $node)); //show the user their current file, if one exists.. if ($node->audio['title'] || $node->audio_file_tmp->filename){ $file_output.= form_item(t('Current Audio File'), t("Your current audio file is:")."" . _is_set_or($node->audio['title'], $node->audio_file_tmp->filename) . "
".t("Use the 'browse' button below to upload a different audio file, or do nothing to keep it the same." )); } //make this required... only if the file has not been uploaded.. $file_output .= form_file(t('Audio File'), 'audio_file', 50, t('Click "Browse..." to select an audio file to upload. NOTE: the current PHP configuration limits uploads to %maxsize. ', array('%maxsize' => format_size(audio_get_max_upload_size()))), TRUE); $file_output .= form_checkbox(t('Allow file downloads.'), 'audio][downloadable', 1, _is_set_or($node->audio['downloadable'],1) , t('If checked, people will be able to download this audio file on to their own computer.'), NULL, FALSE); $output .= form_group(t('Audio File'), $file_output); //show all current file metadata, if an audio file has been uploaded, or is being previewed... if (!empty($node->audio)) { $audio_output .= form_textfield(t("Song Title"), 'audio][title', $node->audio['title'], 40, 80); $audio_output .= form_textfield(t("Artist"), 'audio][artist', $node->audio['artist'], 40, 80); $audio_output .= form_textfield(t("Album"), 'audio][album', $node->audio['album'], 40, 80); $audio_output .= form_textfield(t("Year"), 'audio][year', $node->audio['year'], 10, 15); $audio_output .= form_textfield(t("Track Number"), 'audio][track', $node->audio['track'], 5, 10,t('Enter a single number here. "1" means that this is the first track on the album.')); $audio_output .= form_textfield(t("Genre"), 'audio][genre', $node->audio['genre'], 20, 40); $output .= form_group(t("Audio File Information"), $audio_output); } return $output; } /** * Implementation of hook_view */ function audio_view(&$node, $main = 0, $page = 0) { $node = node_prepare($node, $main); $node->teaser = theme('audio_display_teaser', $node); $node->body = audio_display($node) . $node->body; } //-- Page functions --// /** * Menu callback; displays a Drupal page containing recent audio entries. */ function audio_page($a = NULL, $b = NULL) { if (is_numeric($a)) { // $a is a user ID if ($b == 'feed') { audio_feed_user($a); } else { audio_page_user($a); } } else if ($a == 'feed') { audio_feed_last(); } else { audio_page_last(); } } /** * Displays an RSS feed containing recent blog entries of a given user. */ function audio_feed_user($uid = 0) { global $user; if ($uid) { $account = user_load(array('uid' => $uid, 'status' => 1)); } else { $account = $user; } $result = db_query_range(db_rewrite_sql("SELECT n.nid, n.title, n.teaser, n.created, u.name, u.uid FROM {node} n INNER JOIN {users} u ON n.uid = u.uid WHERE n.type = 'audio' AND u.uid = %d AND n.status = 1 ORDER BY n.created DESC"), $uid, 0, 15); $channel['title'] = $account->name ."'s audio files"; $channel['link'] = url("audio/$uid", NULL, NULL, TRUE); $channel['description'] = $term->description; node_feed($result, $channel); } /** * Displays an RSS feed containing recent audio feeds of all users. */ function audio_feed_last() { $result = db_query_range(db_rewrite_sql("SELECT n.nid, n.title, n.teaser, n.created, u.name, u.uid FROM {node} n INNER JOIN {users} u ON n.uid = u.uid WHERE n.type = 'audio' AND n.status = 1 ORDER BY n.created DESC"), 0, 15); $channel['title'] = variable_get('site_name', 'drupal') .t(' audio files'); $channel['link'] = url('audio', NULL, NULL, TRUE); $channel['description'] = $term->description; node_feed($result, $channel); } /** * Displays a Drupal page containing recent blog entries of a given user. */ function audio_page_user($uid) { global $user; $account = user_load(array((is_numeric($uid) ? 'uid' : 'name') => $uid, 'status' => 1)); if ($account->uid) { drupal_set_title($title = t("%name's audio files", array('%name' => $account->name))); if (($account->uid == $user->uid) && user_access('create audio')) { $output = '
  • '. l(t('Add a new audio file.'), "node/add/audio") .'
  • '; } else if ($account->uid == $user->uid) { $output = '
  • '. t('You are not allowed to add audio files.') .'
  • '; } if ($output) { $output = ''; } else { $output = ''; } $result = pager_query(db_rewrite_sql("SELECT n.nid, n.sticky, n.created FROM {node} n WHERE type = 'audio' AND n.uid = %d AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC"), variable_get('default_nodes_main', 10), 0, NULL, $account->uid); while ($node = db_fetch_object($result)) { $output .= node_view(node_load(array('nid' => $node->nid)), 1); } $output .= theme('pager', NULL, variable_get('default_nodes_main', 10)); $output .= theme('xml_icon', url("audio/$account->uid/feed")); _audio_add_link(array('rel' => 'alternate', 'type' => 'application/rss+xml', 'title' => t('RSS - %title', array('%title' => $title)), 'href' => url("audio/$account->uid/feed"))); print theme('page', $output); } else { drupal_not_found(); } } /** * Displays a Drupal page containing recent audio entries of all users. */ function audio_page_last() { global $user; $output = ''; $result = pager_query(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n WHERE n.type = 'audio' AND n.status = 1 ORDER BY n.created DESC"), variable_get('default_nodes_main', 10)); while ($node = db_fetch_object($result)) { $output .= node_view(node_load(array('nid' => $node->nid)), 1); } $output .= theme('pager', NULL, variable_get('default_nodes_main', 10)); $output .= theme('xml_icon', url('audio/feed')); _audio_add_link(array('rel' => 'alternate', 'type' => 'application/rss+xml', 'title' => t('RSS - Latest audio files'), 'href' => url("audio/feed"))); print theme('page', $output); } /** * Implementation of hook_user(). */ function audio_user($type, &$edit, &$user) { if ($type == 'view') { //&& user_access('edit own blog', $user) //Not needed??... return array(t('History') => form_item(t('Audio'), l(t('listen to the most recent audio files added'), "audio/$user->uid", array('title' => t("Listen to %username's latest audio files.", array('%username' => $user->name)))))); } } /** * Implementation of hook_load */ function audio_load(&$node) { $fid = db_result(db_query("SELECT fid FROM {files} WHERE nid=%d limit 1", $node->nid)); if ($fid){ //If a file has been uploaded and is located in the file table... $node->audio = db_fetch_array(db_query("SELECT * FROM {audio_node_metadata} WHERE fid=%d", $fid)); } } /** * The default mp3 player: This uses the flash XSPF player... * You can override this at the theme layer to change the behavior of this. */ function theme_mp3_player($params) { $url = drupal_get_path('module', 'audio') .'/players/mp3.swf?song_title='. $params->title .'&song_url='. $params->url; $output .= ''; $output .= ''; $output .= ''; $output .= ''; return $output; } /** * This is the default player... */ function theme_audio_player($params) { $output = ''; $output .= ''.t("Click here").''; $output .= "\n"; return $output; } /** * Implementation of hook_insert */ function audio_insert(&$node) { $dest = variable_get('audio_default_path', 'audio')."/". basename($node->audio['filepath']); if (file_copy($node->audio['filepath'], $dest)) { $fid = db_next_id('{files}_fid'); //insert into file table... db_query("INSERT INTO {files} (fid, nid, filename, filepath, filemime, filesize, list) VALUES (%d, %d, '%s', '%s', '%s', '%s', %d)", $fid, $node->nid, $node->audio['filename'], $node->audio['filepath'], $node->audio['filemime'], $node->audio['filesize'], 0); //insert into audio_node table db_query("INSERT INTO {audio_node_metadata} (fid, playcount, fileformat, bitrate, sample_rate, playtime_seconds, title, artist, album, year, track, genre, comment, downloadable) VALUES (%d, %d, '%s', %f, %f, %d, '%s', '%s', '%s', '%s', %d, '%s', '%s', %d)", $fid, 0, $node->audio['fileformat'], $node->audio['bitrate'], $node->audio['sample_rate'], $node->audio['playtime_seconds'], $node->audio['title'], $node->audio['artist'], $node->audio['album'], $node->audio['year'], $node->audio['track'], $node->audio['genre'], $node->audio['comment'], $node->audio['downloadable']); } return $node->nid; } /** * This is a single functions that can be called from other modules * to create an audio node. This doesn't 'attach' an audio node to * anything (yet), but is just a convient way to have an external * piece of code create an audio node. * * Just pass in two associative arrays containing the following * fields. * * node_params = array('title' => 'A post title here', * 'body' => 'The body goes here', * 'publish' => 1 //this is 0 or 1, * 'promote' => 1, * 'uid' => uid //this is an optional paramater * ) * * file_params = array('filepath' => 'the/temp/filepath/', * 'filename' => 'a filename', * 'filemime' => 'mime/type', * 'filesize' => '12345', * 'downloadable' => '1' //this is 0 or 1 * ) */ function audio_api_create_item($file_params, $node_params){ //some quick error checks... if (!is_array($file_params) || !is_array($node_params)) return 0; //check for user permission... if (!audio_access('create')) drupal_access_denied(); //create the base node type items (uid, title, body, etc.)... $audio_node = _audio_create_new_base_node($node_params); //parse the audio file and grab any ID3 tags, if they exist... $audio_node->audio = audio_get_info($file_params['filepath']); //add extra fields regarding the file passed in to the function //through the file_params array... foreach ($file_params as $key => $value) $audio_node->audio[$key] = $value; //save the node, and call the audio_insert(&node) function node_save($audio_node); //return the new id return $audio_node->nid; //return the new 'nid' } //create a basic node with a title and a body to attach the audio file to. function _audio_create_new_base_node($node_params){ global $user; $node->type = 'audio'; $node->title = $node_params['title']; $node->body = $node_params['body']; $node_options = variable_get('node_options_'. $node->type, array('status', 'promote')); $node->publish = $node_params['publish']; //Should we do this here?... $node->status = in_array('status', $node_options); $node->moderate = in_array('moderate', $node_options); $node->promote = _is_set_or($node_params['promote'], in_array('promote', $node_options)); $node->sticky = in_array('sticky', $node_options); $node->revision = in_array('revision', $node_options); $node->uid = ($node_params['uid']) ? $node_params['uid'] : $user->uid; return $node; } function audio_api_delete($nid = false){ global $user; if (!$nid) return; $audio_node = node_load(array('nid' => $nid)); //check for user permission... if (!audio_access('delete', $audio_node)) drupal_access_denied(); //otherwise... audio_delete($audio_node); } /** * Implementation of hook_update */ function audio_update(&$node) { //if a new file has been uploaded, delete all meta information and read in new info from file... if ($node->audio_file_tmp) { $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE nid=%d", $node->nid)); file_delete(file_create_path($file->filepath)); //delete from the files table... db_query("DELETE FROM {files} WHERE filename='%s' AND nid=%d", $file->filename, $node->nid); //delete from the audio_node_meta table... db_query("DELETE FROM {audio_node_metadata} WHERE fid=%d", $file->fid); //insert the new audio file... audio_insert($node); } else { $fid = db_result(db_query("SELECT fid FROM {files} WHERE nid=%d limit 1", $node->nid)); //no new file.. Just updating the meta fields... db_query("UPDATE {audio_node_metadata} SET title = '%s', artist = '%s', album = '%s', year = '%s', track =%d, genre = '%s', downloadable = %d WHERE fid = %d", $node->audio['title'], $node->audio['artist'], $node->audio['album'], $node->audio['year'], $node->audio['track'], $node->audio['genre'], $node->audio['downloadable'], $fid); //update ID3 info in the actual file... audio_write_ID3tags($node); } } /** * Implementation of hook_validate */ function audio_validate(&$node) { if (!empty($_FILES['edit']['name']['audio_file'])) { $file = file_check_upload('audio_file'); if (!empty($file)) { $file = file_save_upload($file); $node->audio = audio_get_info($file->filepath); if (!empty($node->audio['error'])){ form_set_error('audio_file', t('Uploaded file is not an audio file')); } else { $node->audio_file_tmp = $file; _copy_fileinfo($node, $file); //add "downloadable" field to the audio array. This field is a bit of a lost dog since //it is the only field in the $node->audio array that is set in the form, rather then //by the getID3 function... $node->audio['downloadable'] = $_POST['edit']['audio']['downloadable']; } } } elseif (isset($_POST['edit']['audio']) || $_POST['op'] == "Preview") { $node->audio = array_merge(audio_get_info($_POST['edit']['audio_file_tmp']), $_POST['edit']['audio']); if ($_SESSION['file_uploads']){ _copy_fileinfo($node, $_SESSION['file_uploads']['audio_file']); } } if ($_POST['edit']['audio_file_tmp']){ $node->audio_file_tmp = $_POST['edit']['audio_file_tmp']; } } function _copy_fileinfo(&$node, $var){ $node->audio['filename'] = $var->filename; $node->audio['filepath'] = $var->filepath; $node->audio['filesize'] = $var->filesize; } /** * Admin callback for managing audio categories * TODO: add some sensible settings here... */ function audio_admin() { switch (arg(2)) { case 'add': case 'edit': if ($_POST['edit']) { if ($_POST['op'] == t('Delete')) { if ($_POST['edit']['confirm']) { taxonomy_del_term($_POST['edit']['tid']); drupal_goto('admin/audio'); } else { $content = _taxonomy_confirm_del_term($_POST['edit']['tid']); } } else { taxonomy_save_term($_POST['edit']); drupal_goto('admin/audio'); } } else { //$content = ...; } break; default: $content = 'something here...'; } print theme('page', $content); } /** * Uses ID3 tags to get information about an audio file... * Returns one masive array (or false) if the file is not found. */ function audio_get_info($filepath){ $id3_path = variable_get('audio_getid3_path', drupal_get_path('module', 'audio').'/getid3/'); require_once($id3_path.'getid3.php'); // Initialize getID3 engine $getID3 = new getID3; $getID3->encoding = 'UTF-8'; // Analyze file $info = $getID3->analyze($filepath); //Copies data from all subarrays of [tags] into [comments] so // metadata is all available in one location for all tag formats // metainformation is always available under [tags] even if this is not called getid3_lib::CopyTagsToComments($info); // Exit here on error if (isset($info['error'])) { return array ('error' => $info['error']); } $the_goods = array(); if (is_array($info['comments'])){ foreach ($info['comments'] as $key => $value ) { $the_goods[$key] = $value[0]; } } //add some additional fields to our return array.. $the_goods['fileformat'] = $info['fileformat']; $the_goods['filemime'] = $info['mime_type']; $the_goods['playtime_seconds'] = $info['playtime_seconds']; $the_goods['sample_rate'] = $info['audio']['sample_rate']; $the_goods['bitrate'] = $info['audio']['bitrate']; return $the_goods; } /** * Uses the getID3 library to write updated ID3 tag information * back to the actual audio file. This function will write over * any exisitng ID3 tag information contained in the file, and * this function does not make a copy of this information anywhere... * */ function audio_write_ID3tags(&$node){ //grab the fid based on nid, since there is only one file per node... $fid = db_result(db_query("SELECT fid FROM {files} WHERE nid=%d limit 1", $node->nid)); //include the getid3 library files... $id3_path = variable_get('audio_getid3_path', drupal_get_path('module', 'audio').'/getid3/'); require_once($id3_path.'getid3.php'); // Initialize getID3 engine $getID3 = new getID3; $getID3->encoding = $TaggingFormat; // Initialize getID3 tag-writing module. // NOTE: Because of their wanky includes, this file must be included // AFTER an instance of the getID3 class is instantiated. require_once($id3_path.'write.php'); $tagwriter = new getid3_writetags; $tagwriter->filename = file_create_path($node->files[$fid]->filepath); //needs to be full path $tagwriter->tagformats = array('id3v1', 'id3v2.3'); // set various options (optional) $tagwriter->overwrite_tags = true; $tagwriter->tag_encoding = 'UTF-8'; $tagwriter->remove_other_tags = true; //populate data array. Ugly mapping, but what can one do?... $tag_data['title'][] = $node->audio['title']; $tag_data['artist'][] = $node->audio['artist']; $tag_data['album'][] = $node->audio['album']; $tag_data['year'][] = $node->audio['year']; $tag_data['genre'][] = $node->audio['genre']; $tag_data['comment'][] = $node->audio['comment']; $tag_data['track'][] = $node->audio['track']; $tagwriter->tag_data = $tag_data; // write tags //TODO: error handling!.... if ($tagwriter->WriteTags()) { //echo 'Successfully wrote tags
    '; if (!empty($tagwriter->warnings)) { //echo 'There were some warnings:
    '.implode('

    ', $tagwriter->warnings); } } else { //echo 'Failed to write tags!
    '.implode('

    ', $tagwriter->errors); } } /** * Implementation of hook_delete. */ function audio_delete($node) { $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE nid=%d", $node->nid)); file_delete(file_create_path($file->filepath)); //delete from the files table... db_query("DELETE FROM {files} WHERE filename='%s' AND nid=%d", $file->filename, $node->nid); //delete from the audio_node_meta table... db_query("DELETE FROM {audio_node_metadata} WHERE fid=%d", $node->audio['fid']); } /** * Build HTML for a node's audio player */ function _audio_get_player($node) { $params->url = url('audio/play/'.$node->nid, NULL, NULL, TRUE); $params->title = $node->audio['title']; // flash only supports playing MP3s with 44kHz, 22kHz, and 11kHz sample rates $flashable = false; switch ($node->audio['sample_rate']) { case '44100': case '22050': case '11025': $flashable = true; } //if there is no theme function that provides a player of this file type, use the default. //The default just shows a bare link to the file... $player = theme($node->audio['fileformat'] . '_player', $params); if ($player && $flashable) { return $player; } else { return theme('audio_player', $params); } } /** * Create a tag for an audio file. (Grab the player code for the audio file type (mp3, ogg, etc..) */ function audio_display(&$node) { $output = theme('audio_display', $node); return $output; } function theme_audio_display($node){ //add style sheet... theme_add_style(drupal_get_path('module','audio').'/audio.css'); $node->audio['player'] = _audio_get_player($node); $output .= ''; return $output; } function theme_audio_display_teaser($node){ if ($node->audio['title'] and $node->audio['artist']) $output .= $node->audio['title'] ." ".t("by")." ". $node->audio['artist'] ." "; return $output . _audio_get_player($node) . "
    "; } function theme_audio_block($node){ $output .= '
    ' . l($node->audio['title'] ." by ". $node->audio['artist'], 'node/'.$node->nid); $output .= "
    "; //$output .= "
    " . $node->audio['player'] . ""; return $output; } //very simple view - for album (or playlist) view... function theme_audio_micro_teaser($node){ return l($node->audio['title'], 'node/'.$node->nid) . _audio_get_player($node) . "
    "; } /* returns nodes (or html) representation of audio files specified by taxonomy id, * or all audio files, if no tid is present... */ function audio_get_files($tid = NULL, $as_html = TRUE){ $result = pager_query(db_rewrite_sql("SELECT n.nid FROM {term_node} t INNER JOIN {node} n ON t.nid=n.nid WHERE n.status=1 AND n.type='audio' AND t.tid=%d ORDER BY n.sticky DESC, n.created DESC"), 6, 0, NULL, $tid); while ($node = db_fetch_object($result)) $audio_nodes[] = node_load(array('nid' => $node->nid)); if (!$as_html) return $audio_nodes; //otherwise lets genererate some html... foreach ($audio_nodes as $audio_node) $html .= ++$i . ". " . theme_audio_micro_teaser($audio_node); return $html; } /** * Fetches an audio file, allows "shorthand" urls such of the form: * audio/view/$nid * (e.g. audio/download/25/ or audio/download/14) */ function audio_fetch($nid = false) { _audio_download($nid, true); } /** * Similar to audio_fetch, but for playback instead of download. */ function audio_play($nid = false) { _audio_download($nid, false); } function _audio_download($nid, $attach) { if ($nid) { $node = node_load(array('nid' => $nid)); if (user_access('access content')) { $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE fid=%d", $node->audio['fid'])); $headers = array( "Pragma: public", // required "Expires: 0", "Cache-Control: must-revalidate, post-check=0, pre-check=0, private", "Content-Type: ". $file->filemime, "Content-Length: ".$file->filesize); if($attach) { array_push($headers, "Content-Disposition: attachment; filename=\"". $file->filename ."\";", "Content-Transfer-Encoding: binary"); // required for IE, otherwise Content-disposition is ignored if(ini_get('zlib.output_compression')) ini_set('zlib.output_compression', 'Off'); } else { //TODO: increment the play counter } file_transfer($file->filepath, $headers); exit(); } } } /** * Verify that the folders are set up... */ function _audio_check_settings() { // File paths $audio_path = file_create_path(variable_get('audio_default_path', 'audio')); file_check_directory($audio_path, FILE_CREATE_DIRECTORY, 'audio_default_path'); } /** * Check PHP's post_max_size and upload_max_filesize settings and determine * the maximum size of a file upload. * @return an integer number of bytes */ function audio_get_max_upload_size() { $values = array(); foreach (array('upload_max_filesize', 'post_max_size') as $setting) { // the post_max_size and upload_max_filesize settings could be a string // ('2m', '1G') or an integer (2097152 or 1073741824). $val = ini_get($setting); if (!is_numeric($val)) { // separate the numeric and alpha parts, then get to multiplying $val = trim($val); $last = strtolower($val{strlen($val)-1}); switch($last) { case 'g': $val *= 1024; case 'm': $val *= 1024; case 'k': $val *= 1024; } } $values[] = $val; } // the smallest value will be the limiting factor so retun it. return min($values); } //----------------------------------------------------------------------------------- // U t i l i t i e s A n d H e l p e r s //----------------------------------------------------------------------------------- function _print_rp($var){ echo '
    ';
        print_r($var);
        echo '
    '; } function _is_downloadable($fid) { return db_result(db_query("SELECT downloadable FROM {audio_node_metadata} WHERE fid=%d", $fid)); } function _is_set_or($var, $default){ return (isset($var)) ? $var : $default; } function _if_set_show($var, $display_string){ return (!empty($var)) ? $display_string : ""; } function _audio_add_link($attributes) { drupal_set_html_head('\n"); }