| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: audio.module,v 1.159 2009/11/29 19:45:22 drewish Exp $ 3 4 /** 5 * Implementation of hook_help(). 6 */ 7 function audio_help($section, $arg) { 8 switch ($section) { 9 case 'audio/by': 10 return t("You can browse for audio by any of the following fields."); 11 case 'admin/help#audio': 12 $help = '<p>'. t('The audio module allows users to upload and store audio files on a Drupal site. Audio is an important medium for community communication as the recent rise of the <a href="!elink-en-wikipedia-org">podcast phenomenon</a> demonstrates.', array('!elink-en-wikipedia-org' => 'http://en.wikipedia.org/wiki/Podcasting')) .'</p>'; 13 $help .= '<p>'. t('Users create audio nodes by uploading a file from their computer. They are then able to make changes to the metadata, perhaps adding an artist, or removing the track number. Visitors can download the audio file, view the file\'s metadata and encoding information, or browse for audio by metadata (artist, title, year, etc). Visitors can even play MP3s within their browser using the <a href="!elink-musicplayer-sourceforge-net">XSPF flash player</a> that is bundled with the module.', array('!elink-musicplayer-sourceforge-net' => 'http://musicplayer.sourceforge.net/')) .'</p>'; 14 $help .= '<p>'. t('The module uses the <a href="!elink-www-getid3-org">getID3 library</a> to read and write <a href="%elink-en-wikipedia-org">ID3 tag</a> information from the audio file. getID3 can read metadata from a many different audio and video formats giving the audio module a great deal of flexibility.', array('!elink-www-getid3-org' => 'http://www.getid3.org', '!elink-en-wikipedia-org' => 'http://en.wikipedia.org/wiki/Id3')) .'</p>'; 15 $help .= t('<p>You can:</p> 16 <ul> 17 <li>add an audio file at <a href="!node-add-audio">create content >> audio</a>.</li> 18 <li>see your most recent audio files at <a href="!user">user account</a>.</li> 19 <li>see all of the most recently added audio files at <a href="!audio">audio</a>.</li> 20 <li>browse for audio by its metadata (artist, album, genre, etc) at <a href="!audio-by">audio >> by</a>.</li> 21 <li>enable the <em>latest audio</em>, <em>random audio</em>, and <em>browse for audio</em> blocks at <a href="!admin-build-block">administer >> build >> block</a>.</li> 22 <li>administer audio module at <a href="!admin-settings-audio">administer >> site configuration >> audio</a>.</li> 23 </ul>', array('!audio' => url('audio'), '!audio-by' => url('audio/by'), '!user' => url('user'), '!node-add-audio' => url('node/add/audio'), '!admin-build-block' => url('admin/build/block'), '!admin-settings-audio' => url('admin/settings/audio/audio'))); 24 $help .= '<p>'. t('For more information please read the configuration and customization handbook <a href="!audio">Audio page</a>.', array('!audio' => 'http://www.drupal.org/handbook/modules/audio/')) .'</p>'; 25 return $help; 26 case 'admin/settings/audio': 27 $help = '<p><b>'. t('The current PHP configuration limits file uploads to %maxsize.', array('%maxsize' => format_size(file_upload_max_size()))) .'</b><br />'; 28 $help .= '<p>'. t("There are two PHP ini settings, upload_max_filesize and post_max_size, that limit the maximum size of uploads. You can change these settings in the php.ini file or by using a php_value directive in Apache .htaccess file. Consult the PHP documentation for more info.") .'</p>'; 29 return $help; 30 case 'admin/settings/audio/metadata': 31 $help = t("These settings let you determine what metadata the audio module tracks. You can add or remove metadata tags and select how they will be used. 32 <ul> 33 <li><em>Autocompleted</em> enables javacript autocompletion of the tag based on existing values.</li> 34 <li><em>Required</em> forces a user to enter a value</li> 35 <li><em>Hidden</em> prevents the tag from being listed in the node view</li> 36 <li><em>Browsable</em> allows users to browse for audio using that tag</li> 37 <li><em>Written to file</em> indicates that the tag should be saved to the file (this requires getid3 support)</li> 38 <li><em>Weight</em> determines the order of the tags, lower weights are listed first</li> 39 <li><em>Delete</em> indicates that you would like to remove the tag from the allowed list</li> 40 </ul>"); 41 $help .= '<p>'. t('<strong>Note:</strong> deleting a tag will not remove it from the database or file until the node is saved again.') .'</p>'; 42 return $help; 43 } 44 } 45 46 /** 47 * Implementation of hook_menu(). 48 */ 49 function audio_menu() { 50 $items = array(); 51 52 $items['admin/settings/audio'] = array( 53 'title' => 'Audio settings', 54 'description' => 'Change settings for the audio module.', 55 'page callback' => 'drupal_get_form', 56 'page arguments' => array('audio_admin_settings'), 57 'access arguments' => array('administer site configuration'), 58 'file' => 'audio.admin.inc', 59 ); 60 $items['admin/settings/audio/main'] = array( 61 'title' => 'Audio', 62 'type' => MENU_DEFAULT_LOCAL_TASK, 63 'weight' => '-10', 64 ); 65 $items['admin/settings/audio/metadata'] = array( 66 'title' => 'Metadata tags', 67 'page callback' => 'drupal_get_form', 68 'page arguments' => array('audio_admin_settings_metadata'), 69 'access arguments' => array('administer audio'), 70 'file' => 'audio.admin.inc', 71 'type' => MENU_LOCAL_TASK, 72 ); 73 $items['admin/settings/audio/players'] = array( 74 'title' => 'Players', 75 'page callback' => 'drupal_get_form', 76 'page arguments' => array('audio_admin_settings_players'), 77 'access arguments' => array('administer audio'), 78 'file' => 'audio.admin.inc', 79 'type' => MENU_LOCAL_TASK, 80 ); 81 82 $items['audio/autocomplete'] = array( 83 'page callback' => 'audio_autocomplete', 84 'access arguments' => array('access content'), 85 'type' => MENU_CALLBACK, 86 ); 87 $items['audio/by'] = array( 88 'title' => 'Browse by...', 89 'page callback' => 'audio_page_browse_by', 90 'file' => 'audio.pages.inc', 91 'access arguments' => array('access content'), 92 'type' => MENU_NORMAL_ITEM, 93 ); 94 $items['audio/by/%'] = array( 95 'title' => 'Audio by @tag', 96 'title arguments' => array('@tag' => 2), 97 'page callback' => 'audio_page_browse_by', 98 'page arguments' => array(2), 99 'file' => 'audio.pages.inc', 100 'access arguments' => array('access content'), 101 'type' => MENU_NORMAL_ITEM, 102 ); 103 $items['audio/by/%/%'] = array( 104 'title' => 'Audio by @tag @value', 105 'title arguments' => array('@tag' => 2, '@value' => 3), 106 'page callback' => 'audio_page_browse_by', 107 'page arguments' => array(2, 3), 108 'file' => 'audio.pages.inc', 109 'access arguments' => array('access content'), 110 'type' => MENU_NORMAL_ITEM, 111 ); 112 113 $items['audio/download/%node'] = array( 114 'page callback' => 'audio_download', 115 'page arguments' => array(2), 116 'file' => 'audio.pages.inc', 117 'access callback' => '_audio_allow_download', 118 'access arguments' => array(2), 119 'type' => MENU_CALLBACK, 120 ); 121 $items['audio/play/%node'] = array( 122 'page callback' => 'audio_play', 123 'page arguments' => array(2), 124 'file' => 'audio.pages.inc', 125 'access callback' => '_audio_allow_play', 126 'access arguments' => array(2), 127 'type' => MENU_CALLBACK, 128 ); 129 130 return $items; 131 } 132 133 /** 134 * Implementation of hook_theme 135 */ 136 function audio_theme() { 137 $theme = array( 138 'audio_file_form' => array( 139 'arguments' => array('form'), 140 ), 141 'audio_admin_settings_metadata_table' => array( 142 'arguments' => array('form_element'), 143 'file' => 'audio.admin.inc', 144 ), 145 'audio_admin_settings_players' => array( 146 'arguments' => array('form_element'), 147 'file' => 'audio.admin.inc', 148 ), 149 'audio_default_node_player' => array( 150 'arguments' => array('node'), 151 ), 152 'audio_teaser' => array( 153 'arguments' => array('node'), 154 'file' => 'audio.theme.inc', 155 ), 156 'audio_display' => array( 157 'arguments' => array('node'), 158 'file' => 'audio.theme.inc', 159 ), 160 'audio_format_tag' => array( 161 'arguments' => array('tag', 'value', 'setting'), 162 'file' => 'audio.theme.inc', 163 ), 164 'audio_format_filelength' => array( 165 'arguments' => array('fileinfo'), 166 'file' => 'audio.theme.inc', 167 ), 168 'audio_format_fileformat' => array( 169 'arguments' => array('fileinfo'), 170 'file' => 'audio.theme.inc', 171 ), 172 ); 173 174 $player_path = drupal_get_path('module', 'audio') .'/players'; 175 foreach (audio_get_players('names') as $name => $player) { 176 if ($player['module'] == 'audio') { 177 $theme[$player['theme_node']] = array( 178 'arguments' => array('node', 'options'), 179 'file' => $player['file'], 180 'path' => $player_path, 181 ); 182 if (!empty($player['theme_xspf'])) { 183 $theme[$player['theme_xspf']] = array( 184 'arguments' => array('path', 'options'), 185 'file' => $player['file'], 186 'path' => $player_path, 187 ); 188 } 189 } 190 } 191 return $theme; 192 } 193 194 /** 195 * Implementation of hook_node_info(). 196 */ 197 function audio_node_info() { 198 return array( 199 'audio' => array( 200 'name' => t('Audio'), 201 'module' => 'audio', 202 'description' => t('An audio file. The audio file could be used for adding music, podcasts, or audio clips to your site.'), 203 ) 204 ); 205 } 206 207 /** 208 * Invoke hook_audio api methods. 209 * 210 * The audio module provide a hook for contributed modules. Use this rather than 211 * the nodeapi so you don't have to worry about the module invocation order. 212 * 213 * function hook_audio($op, $node, $arg1) 214 * 215 * @param $op 216 * The $op value will be one of the following: 217 * 'upload' 218 * A new audio file has been uploaded. Contrib modules can read data from 219 * the file and append it to the audio node at this point. 220 * 'access' 221 * An operation is being performed on the node and other modules can 222 * determine if this will be allowed. $arg1 will describe the operation 223 * (i.e. 'play' or 'download'). Return a boolean if you want to allow or 224 * deny this, or NULL if you don't. 225 * 'download' 226 * A user is playing the audio node. This can be handy if you're recording 227 * user statistics. 228 * 'play' 229 * A user is downloading an audio node. This can be handy if you're 230 * recording user statistics. 231 * @param $node 232 * An audio node object. 233 */ 234 function audio_invoke_audioapi($op, &$node, $a3 = NULL, $a4 = NULL) { 235 $return = array(); 236 foreach (module_implements('audio') as $name) { 237 $function = $name .'_audio'; 238 $result = $function($op, $node, $a3, $a4); 239 if (isset($result) && is_array($result)) { 240 $return = array_merge($return, $result); 241 } 242 else if (isset($result)) { 243 $return[] = $result; 244 } 245 } 246 return $return; 247 } 248 249 /** 250 * Implementation of hook_perm(). 251 */ 252 function audio_perm() { 253 return array('administer audio', 'create audio', 'edit own audio', 254 'play audio', 'download audio', 'view download stats'); 255 } 256 257 /** 258 * Implementation of hook_access(). 259 */ 260 function audio_access($op, $node = NULL) { 261 global $user; 262 263 if (user_access('administer audio')) { 264 return TRUE; 265 } 266 267 if ($op == 'update' || $op == 'delete') { 268 if (($user->uid == $node->uid) && user_access('edit own audio')) { 269 return TRUE; 270 } 271 } 272 if ($op == 'create') { 273 if (user_access('create audio')) { 274 return TRUE; 275 } 276 } 277 } 278 279 /** 280 * Is the current user allowed to download an audio node? 281 * 282 * @return 283 * boolean indicating if it's allowed. 284 */ 285 function _audio_allow_download($node) { 286 if ($node->type == 'audio' && isset($node->url_download) && $node->audio['downloadable']) { 287 $result = audio_invoke_audioapi('access', $node, 'download'); 288 289 if (in_array(TRUE, $result)) { 290 return TRUE; 291 } 292 if (in_array(FALSE, $result)) { 293 return FALSE; 294 } 295 return user_access('download audio'); 296 } 297 return FALSE; 298 } 299 300 /** 301 * Is the current user allowed to play an audio node? 302 * 303 * @return 304 * boolean indicating if it's allowed. 305 */ 306 function _audio_allow_play($node) { 307 if ($node->type == 'audio' && isset($node->url_play)) { 308 $result = audio_invoke_audioapi('access', $node, 'play'); 309 310 if (in_array(TRUE, $result)) { 311 return TRUE; 312 } 313 if (in_array(FALSE, $result)) { 314 return FALSE; 315 } 316 return user_access('play audio'); 317 } 318 return FALSE; 319 } 320 321 /** 322 * Implements hook_cron(). 323 * 324 * This deletes old temp files. 325 */ 326 function audio_cron() { 327 $path = audio_get_directory() .'/temp'; 328 $files = file_scan_directory(file_create_path($path), '.*'); 329 foreach ($files as $file => $info) { 330 if (time() - filemtime($file) > 60*60*6) { 331 file_delete($file); 332 } 333 } 334 } 335 336 /** 337 * Implementation of hook_link(). 338 */ 339 function audio_link($type, $node, $main = 0) { 340 $links = array(); 341 $link_access = user_access('view download stats'); 342 343 if ($type == 'node' && $node->type == 'audio') { 344 if (_audio_allow_download($node)) { 345 $links['audio_download_link'] = array( 346 'title' => t('Download audio file'), 347 'href' => $node->url_download, 348 ); 349 if ($link_access) { 350 $links['audio_download_count'] = array( 351 'title' => t('@download_count downloads', array('@download_count' => $node->audio['download_count'])), 352 ); 353 } 354 } 355 if (_audio_allow_play($node) && $link_access) { 356 $links['audio_play_count'] = array( 357 'title' => t('@play_count plays', array('@play_count' => $node->audio['play_count'])), 358 ); 359 } 360 } 361 362 return $links; 363 } 364 365 /** 366 * Implementation of hook_nodeapi(). 367 */ 368 function audio_nodeapi(&$node, $op, $arg) { 369 if ($node->type == 'audio') { 370 switch ($op) { 371 case 'delete revision': 372 audio_delete_revision($node); 373 break; 374 375 case 'rss item': 376 $ret = array(); 377 if (_audio_allow_download($node)) { 378 // Reset the node's body to remove theming. 379 $body = db_result(db_query("SELECT r.body FROM {node} n INNER JOIN {node_revisions} r ON n.nid = r.nid WHERE n.vid=%d", $node->vid)); 380 $node->body = $body; 381 $node = node_prepare($node, FALSE); 382 383 $ret[] = array( 384 'key' => 'enclosure', 385 'value' => '', 386 'attributes' => array( 387 'url' => $node->url_download, 388 'length' => $node->audio['file']->filesize, 389 'type' => $node->audio['file']->filemime 390 )); 391 // Provide very basic iTunes support. 392 $ret[] = array( 393 'namespace' => array('xmlns:itunes' => 'http://www.itunes.com/dtds/podcast-1.0.dtd'), 394 'key' => 'itunes:duration', 395 'value' => $node->audio['playtime'], 396 ); 397 $ret[] = array( 398 'namespace' => array('xmlns:itunes' => 'http://www.itunes.com/dtds/podcast-1.0.dtd'), 399 'key' => 'itunes:author', 400 'value' => $node->audio_tags['artist'], 401 ); 402 } 403 return $ret; 404 405 case 'update index': 406 // Since the theme might hide the tag values we'll manually add them to 407 // the search index. 408 $cleantags = array(); 409 foreach ($node->audio_tags as $value) { 410 $cleantags[] = check_plain($value); 411 } 412 return $cleantags; 413 } 414 } 415 } 416 417 /** 418 * Implementation of hook_view(). 419 */ 420 function audio_view(&$node, $teaser = FALSE, $page = FALSE) { 421 drupal_add_css(drupal_get_path('module', 'audio') .'/audio.css'); 422 423 $node = node_prepare($node, $teaser); 424 if ($teaser) { 425 $node->content['audio'] = array( 426 '#value' => theme('audio_teaser', $node), 427 '#weight' => 0, 428 ); 429 } 430 else { 431 $node->content['audio'] = array( 432 '#value' => theme('audio_display', $node), 433 '#weight' => -1, 434 ); 435 } 436 return $node; 437 } 438 439 /** 440 * Implementation of hook_validate(). 441 */ 442 function audio_validate(&$node, &$form) { 443 if (!isset($node->audio['file']->filepath)) { 444 form_set_error('audio_upload', t("A file must be provided. If you tried uploading a file, make sure it's less than the upload size limit.")); 445 } 446 447 if (empty($form_state['values']['title_format'])) { 448 $form_state['values']['title_format'] = variable_get('audio_default_title_format', '[audio-tag-title-raw] by [audio-tag-artist-raw]'); 449 } 450 } 451 452 /** 453 * Implementation of hook_load(). 454 */ 455 function audio_load($node) { 456 if ($node->vid) { 457 // This is a wonky way to load the fields but its handy right now while 458 // I'm renaming fields in the databases. 459 $fields = db_fetch_array(db_query("SELECT a.* FROM {audio} a WHERE vid=%d", $node->vid)); 460 $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE fid=%d", $fields['fid'])); 461 462 $ret = array( 463 'title_format' => $fields['title_format'], 464 'audio' => array( 465 'play_count' => $fields['play_count'], 466 'download_count' => $fields['download_count'], 467 'downloadable' => $fields['downloadable'], 468 'format' => $fields['format'], 469 'sample_rate' => $fields['sample_rate'], 470 'channel_mode' => $fields['channel_mode'], 471 'bitrate' => $fields['bitrate'], 472 'bitrate_mode' => $fields['bitrate_mode'], 473 'playtime' => $fields['playtime'], 474 'bitrate' => $fields['bitrate'], 475 'file' => $file, 476 ), 477 ); 478 479 if (isset($file->filepath) && file_exists($file->filepath)) { 480 // TODO: should these links be by vid? 481 $ret['url_play'] = url('audio/play/'. $node->nid, array('absolute' => TRUE)); 482 if ($ret['audio']['downloadable']) { 483 // iTunes and other podcasting programs check the url to determine the 484 // file type. we'll add the original file name on to the end. see issues 485 // #35398 and #68716 for more info. 486 $url = 'audio/download/'. $node->nid .'/'. $file->filename; 487 $ret['url_download'] = url($url, array('absolute' => TRUE)); 488 } 489 } 490 491 // Load the audio tags. 492 $result = db_query("SELECT tag, value FROM {audio_metadata} WHERE vid=%d", $node->vid); 493 $ret['audio_tags'] = array(); 494 while ($obj = db_fetch_object($result)) { 495 $ret['audio_tags'][$obj->tag] = $obj->value; 496 } 497 498 return $ret; 499 } 500 return array(); 501 } 502 503 /** 504 * Implementation of hook_insert(). 505 */ 506 function audio_insert(&$node) { 507 file_move($node->audio['file']->filepath, audio_get_directory(), FILE_EXISTS_RENAME); 508 _audio_save($node); 509 } 510 511 /** 512 * Implementation of hook_update(). 513 */ 514 function audio_update(&$node) { 515 // If there's a new file we need to move it to the correct location. 516 if (($node->audio['file']->status & FILE_STATUS_PERMANENT) != FILE_STATUS_PERMANENT) { 517 if (!$node->revision) { 518 // If it's not a revision the existing file needs to be removed. 519 $oldfile = db_fetch_object(db_query('SELECT f.* FROM {files} f INNER JOIN {audio} a ON f.fid = a.fid WHERE a.vid = %d', $node->vid)); 520 _audio_file_delete($oldfile); 521 } 522 file_move($node->audio['file']->filepath, audio_get_directory(), FILE_EXISTS_RENAME); 523 } 524 else if ($node->revision) { 525 // New revision using existing file so we need to copy it. 526 file_copy($node->audio['file']->filepath, file_create_filename($node->audio['file']->filename, audio_get_directory())); 527 // Unset the fid so a new record is created. 528 $node->audio['file']->fid = NULL; 529 } 530 531 _audio_save($node); 532 } 533 534 /** 535 * Handle the busy work of saving the node's audio and file records. 536 * 537 * @param $node Node opject. 538 */ 539 function _audio_save(&$node) { 540 // Save the file 541 $node->audio['file']->timestamp = time(); 542 $node->audio['file']->filesize = filesize($node->audio['file']->filepath); 543 $node->audio['file']->status |= FILE_STATUS_PERMANENT; 544 // If there's an fid update, otherwise insert. 545 $file_update = empty($node->audio['file']->fid) ? array() : array('fid'); 546 drupal_write_record('files', $node->audio['file'], empty($node->audio['file']->fid) ? array() : array('fid')); 547 548 // Save the audio row. 549 $audio = array_merge($node->audio, array('nid' => $node->nid, 'vid' => $node->vid, 'title_format' => $node->title_format, 'fid' => $node->audio['file']->fid)); 550 $audio_update = ($node->is_new || $node->revision) ? array() : array('vid'); 551 drupal_write_record('audio', $audio, $audio_update); 552 553 // Remove any existing metadata. 554 db_query("DELETE FROM {audio_metadata} WHERE vid=%d", $node->vid); 555 556 // Save the new tags. 557 $allowed_tags = audio_get_tags_allowed(); 558 foreach ($node->audio_tags as $tag => $value) { 559 if (in_array($tag, $allowed_tags) && $value) { 560 $metadata = array('vid' => $node->vid, 'tag' => $tag, 'value' => $value, 'clean' => audio_clean_tag($value)); 561 drupal_write_record('audio_metadata', $metadata); 562 } 563 } 564 } 565 566 /** 567 * Implementation of hook_delete(). 568 */ 569 function audio_delete($node) { 570 $result = db_query('SELECT a.vid, f.* FROM {audio} a LEFT JOIN {files} f ON a.fid = f.fid WHERE nid = %d', $node->nid); 571 while ($o = db_fetch_object($result)) { 572 _audio_file_delete($o); 573 db_query('DELETE FROM {audio_metadata} WHERE vid = %d', $o->vid); 574 } 575 db_query('DELETE FROM {audio} WHERE nid = %d', $node->nid); 576 } 577 578 /** 579 * Delete a single revision. 580 */ 581 function audio_delete_revision($node) { 582 $file = db_result(db_query('SELECT a.vid, f.* FROM {audio} a LEFT JOIN {files} f ON a.fid = f.fid WHERE vid = %d', $node->vid)); 583 _audio_file_delete($file); 584 585 db_query('DELETE FROM {audio_metadata} WHERE vid = %d', $node->vid); 586 db_query('DELETE FROM {audio} WHERE vid = %d', $node->vid); 587 } 588 589 /** 590 * Handle the busy work of deleting the file record and the file. 591 * 592 * @param unknown_type $file 593 */ 594 function _audio_file_delete($file) { 595 if (!empty($file->filepath)) { 596 file_delete($file->filepath); 597 } 598 if (!empty($file->fid)) { 599 db_query('DELETE FROM {files} WHERE fid = %d', array($file->fid)); 600 } 601 } 602 603 /** 604 * Implementation of hook_form(). 605 */ 606 function audio_form(&$node, &$form_state) { 607 drupal_add_js(drupal_get_path('module', 'audio') .'/audio.js'); 608 609 $type = node_get_types('type', $node); 610 if ($type->has_title) { 611 $form['title']['#weight'] = -5; 612 $form['title']['title_format'] = array( 613 '#type' => 'textfield', 614 '#title' => check_plain($type->title_label), 615 '#default_value' => !empty($node->title_format) ? $node->title_format : variable_get('audio_default_title_format', '[audio-tag-title-raw] by [audio-tag-artist-raw]'), 616 '#description' => t("The title can use the file's metadata. You can use the tokens listed below to insert information into the title. <strong>Note:</strong> the node title is escaped so it is safe to use the -raw tokens."), 617 '#required' => TRUE, 618 ); 619 $form['title']['token_help'] = array( 620 '#title' => t('Token list'), 621 '#type' => 'fieldset', 622 '#collapsible' => TRUE, 623 '#collapsed' => TRUE, 624 '#description' => t('This is a list of the tokens that can be used in the title of audio nodes.'), 625 'help' => array('#value' => theme('token_help', 'node')), 626 ); 627 } 628 629 if ($type->has_body) { 630 $form['body_filter']['#weight'] = -4; 631 $form['body_filter']['body'] = array( 632 '#type' => 'textarea', 633 '#title' => check_plain($type->body_label), 634 '#default_value' => $node->body, 635 '#rows' => 5, 636 '#required' => ($type->min_word_count > 0), 637 ); 638 $form['body_filter']['format'] = filter_form($node->format); 639 } 640 641 642 $form['audio'] = array( 643 '#type' => 'fieldset', 644 '#title' => t('Audio File Info'), 645 '#collapsible' => TRUE, 646 '#weight' => -1, 647 '#tree' => TRUE, 648 ); 649 650 // Place a visible copy of the file path on the form (after removing the 651 // directory info from non-admins). 652 $form['audio']['display_filepath'] = array( 653 '#type' => 'item', 654 '#title' => t('Current File'), 655 '#value' => empty($node->audio['file']->filepath) ? t('No file is attached.') : (user_access('administer audio') ? $node->audio['file']->filepath : basename($node->audio['file']->filepath)), 656 ); 657 658 // If we've got a file, add the file information fields. 659 if (!empty($node->audio['file']->filename)) { 660 $form['audio']['#theme'] = 'audio_file_form'; 661 662 // Store the non-user editable file information as values. 663 $form['audio']['file'] = array( 664 '#type' => 'value', 665 '#value' => $node->audio['file'], 666 ); 667 668 $form['audio']['format'] = array( 669 '#type' => 'select', 670 '#title' => t('Format'), 671 '#default_value' => $node->audio['format'], 672 '#options' => drupal_map_assoc(array('', 'aac', 'ac3', 'au', 'avr', 'flac', 'midi', 'mod', 'mp3', 'mpc', 'ogg', 'voc'), 'drupal_strtoupper'), 673 ); 674 $form['audio']['file_size'] = array( 675 '#type' => 'textfield', 676 '#title' => t('File Size'), 677 '#default_value' => $node->audio['file']->filesize, 678 ); 679 $form['audio']['playtime'] = array( 680 '#type' => 'textfield', 681 '#title' => t('Length'), 682 '#default_value' => $node->audio['playtime'], 683 '#description' => t('The format is hours:minutes:seconds.'), 684 ); 685 $form['audio']['sample_rate'] = array( 686 '#type' => 'select', 687 '#title' => t('Sample rate'), 688 '#default_value' => $node->audio['sample_rate'], 689 '#options' => array('' => '', '48000' => '48,000 Hz', '44100' => '44,100 Hz', '32000' => '32,000 Hz', '22050' => '22,050 Hz', '11025' => '11,025 Hz', '8000' => '8,000 Hz'), 690 ); 691 $form['audio']['channel_mode'] = array( 692 '#type' => 'select', 693 '#title' => t('Channel mode'), 694 '#default_value' => $node->audio['channel_mode'], 695 '#options' => array('stereo' => t('Stereo'), 'mono' => t('Mono')), 696 ); 697 $form['audio']['bitrate'] = array( 698 '#type' => 'textfield', 699 '#title' => t('Bitrate'), 700 '#default_value' => $node->audio['bitrate'], 701 ); 702 $form['audio']['bitrate_mode'] = array( 703 '#type' => 'select', 704 '#title' => t('Bitrate mode'), 705 '#default_value' => $node->audio['bitrate_mode'], 706 '#options' => array('' => '', 'cbr' => t('Constant'), 'vbr' => t('Variable')), 707 ); 708 709 // Users shouldn't be able to change the play and download counts so we'll 710 // put these for viewing... 711 $form['audio']['display_play_count'] = array( 712 '#type' => 'item', 713 '#title' => t('Play count'), 714 '#value' => $node->audio['play_count'], 715 ); 716 $form['audio']['display_download_count'] = array( 717 '#type' => 'item', 718 '#title' => t('Download count'), 719 '#value' => $node->audio['download_count'], 720 ); 721 // ...and these are what we'll save back to the node. 722 $form['audio']['play_count'] = array( 723 '#type' => 'value', 724 '#value' => $node->audio['play_count'], 725 ); 726 $form['audio']['download_count'] = array( 727 '#type' => 'value', 728 '#value' => $node->audio['download_count'], 729 ); 730 } 731 732 $extensions = implode(', ', array_filter(explode(' ', variable_get('audio_allowed_extensions', 'mp3 wav ogg')))); 733 $form['audio']['audio_upload'] = array( 734 '#tree' => FALSE, 735 '#type' => 'file', 736 '#title' => empty($node->audio['file']->filename) ? t('Add a new audio file') : t('Replace this with a new file'), 737 '#attributes' => array('audio_accept' => $extensions), 738 '#description' => t('Click "Browse..." to select an audio file to upload. Only files with the following extensions are allowed: %allowed-extensions.', array('%allowed-extensions' => $extensions)) .'<br />' 739 . t('<strong>NOTE:</strong> the current PHP configuration limits uploads to %maxsize.', array('%maxsize' => format_size(file_upload_max_size()))), 740 ); 741 $form['audio']['downloadable'] = array( 742 '#type' => 'checkbox', 743 '#title' => t('Allow file downloads.'), 744 '#default_value' => isset($node->audio['downloadable']) ? $node->audio['downloadable'] : variable_get('audio_default_downloadable', 1), 745 '#description' => t('If checked, a link will be displayed allowing visitors to download this audio file on to their own computer.') .'<br />' 746 . t('<strong>WARNING:</strong> even if you leave this unchecked, clever users will be able to find a way to download the file. This just makes them work a little harder to find the link.'), 747 ); 748 749 750 // If we've got a file, add the fields for editing meta data. 751 if (!empty($node->audio['file']->filepath)) { 752 $form['audio_tags'] = array( 753 '#type' => 'fieldset', 754 '#title' => t('Audio Metadata'), 755 '#collapsible' => TRUE, 756 '#tree' => TRUE, 757 '#weight' => -3, 758 ); 759 // Delegate out the dirty work of building form elements. 760 foreach (audio_get_tag_settings() as $tag => $tag_settings) { 761 $form['audio_tags'][$tag] = _audio_build_tag_form($tag, $tag_settings, empty($node->audio_tags[$tag]) ? '' : $node->audio_tags[$tag]); 762 } 763 } 764 765 $form['#validate'][] = 'audio_node_form_validate'; 766 $form['#submit'][] = 'audio_node_form_submit'; 767 $form['#attributes'] = array('enctype' => 'multipart/form-data'); 768 769 return $form; 770 } 771 772 /** 773 * Theme function to put the form elements into a table. Steal some CSS from 774 * the watchdog module. 775 */ 776 function theme_audio_file_form($form) { 777 // List of elements to leave out of the table. 778 $skip_list = array('audio_upload' => 1, 'downloadable' => 1); 779 780 $rows = array(); 781 foreach (element_children($form) as $key) { 782 if (!isset($skip_list[$key])) { 783 if ($form[$key]['#type'] != 'hidden' && $form[$key]['#type'] != 'value') { 784 $title = $form[$key]['#title']; 785 unset($form[$key]['#title']); 786 $rows[] = array( 787 array('data' => $title, 'header' => TRUE), 788 drupal_render($form[$key]), 789 ); 790 } 791 } 792 } 793 794 $output = theme('table', array(), $rows, array('class' => 'watchdog-event')); 795 return $output . drupal_render($form); 796 } 797 798 /** 799 * Node submit handler 800 */ 801 function audio_node_form_validate($form, &$form_state) { 802 // Check for an upload. 803 $validators = array( 804 'file_validate_extensions' => array(variable_get('audio_allowed_extensions', 'mp3 wav ogg')), 805 ); 806 if ($file = file_save_upload('audio_upload', $validators)) { 807 $node = (object) $form_state['values']; 808 $node->audio = array( 809 'play_count' => 0, 810 'download_count' => 0, 811 'downloadable' => (bool) $form_state['values']['audio']['downloadable'], 812 'file' => $file, 813 ); 814 815 // Allow other modules to modify the node. 816 audio_invoke_audioapi('upload', $node); 817 818 // ...save info so that it shows up in both the preview and 819 // form. Note that we do this after calling we called our api hook with 820 // the upload operation, it gives the audio_id3 module a chance to read 821 // the tags. 822 $form_state['values']['audio'] = $node->audio; 823 $form_state['values']['audio_tags'] = $node->audio_tags; 824 $form_state['values']['audio_images'] = $node->audio_images; 825 } 826 } 827 828 /** 829 * Node submit handler 830 */ 831 function audio_node_form_submit($form, &$form_state) { 832 $node = (object) $form_state['values']; 833 834 // Use the token module to build the title. Clear the existing title to 835 // prevent the [title] tag from being expanded. 836 $node->title = ''; 837 token_get_values('node', $node, TRUE); 838 $form_state['values']['title'] = token_replace($form_state['values']['title_format'], 'node', $node); 839 } 840 841 /** 842 * Construct a form element to represent a tag. 843 * 844 * @param $tag 845 * Name of the tag. 846 * @param $tag_settings 847 * Array of settings that determine the way the tag is handled. 848 * @param $value 849 * Value of the tag. 850 * @return 851 * Array with a form element. 852 */ 853 function _audio_build_tag_form($tag, $tag_settings, $value) { 854 $form_element = array( 855 '#type' => 'textfield', 856 '#title' => t(ucwords(str_replace('_', ' ', $tag))), 857 '#default_value' => $value, 858 '#maxlength' => 255, 859 '#required' => (boolean) $tag_settings['required'], 860 ); 861 862 if ($tag_settings['autocomplete']) { 863 $form_element['#autocomplete_path'] = 'audio/autocomplete/'. $tag; 864 } 865 866 switch ($tag) { 867 case 'track': 868 $form_element['#title'] = t('Track Number'); 869 $form_element['#maxlength'] = 10; 870 $form_element['#description'] = t("Enter either a single number or fraction here. '1' means that this is the first track on the album, and '1/8' ."); 871 break; 872 873 case 'genre': 874 $form_element['#maxlength'] = 40; 875 break; 876 } 877 878 return $form_element; 879 } 880 881 882 /** 883 * Implementation of hook_user(). 884 */ 885 function audio_user($type, &$edit, &$user) { 886 if ($type == 'view' && db_result(db_query(db_rewrite_sql("SELECT COUNT(*) FROM {node} n WHERE n.type = 'audio' AND n.uid = %d AND n.status = 1"), $user->uid))) { 887 $user->content['summary']['audio'] = array( 888 '#type' => 'user_profile_item', 889 '#title' => t('Audio'), 890 '#value' => l(t("Listen to @username's recent audio files", array('@username' => $user->name)), "audio/user/$user->uid"), 891 '#attributes' => array('class' => 'audio'), 892 ); 893 } 894 } 895 896 /** 897 * Implementation of hook_block(). 898 * 899 * Provides a block for browsing by metadata. 900 */ 901 function audio_block($op = 'list', $delta = 0, $edit = array()) { 902 switch ($op) { 903 case 'list': 904 $blocks[2]['info'] = t('Audio: Browse by'); 905 return $blocks; 906 907 case 'view': 908 if (user_access('access content')) { 909 switch ($delta) { 910 case 2: 911 $items = array(); 912 $settings = audio_get_tag_settings(); 913 $result = db_query(db_rewrite_sql('SELECT DISTINCT a.tag FROM {node} n INNER JOIN {audio_metadata} a ON n.vid = a.vid WHERE n.status = 1 ORDER BY a.tag ASC')); 914 while ($obj = db_fetch_object($result)) { 915 if ($settings[$obj->tag]['browsable']) { 916 $items[] = l($obj->tag, 'audio/by/'. $obj->tag); 917 } 918 } 919 $block['subject'] = t('Browse for audio by'); 920 $block['content'] = theme('item_list', $items); 921 break; 922 } 923 return $block; 924 } 925 } 926 } 927 928 /** 929 * Implementation of hook_file_download(). 930 */ 931 function audio_file_download($filename) { 932 $filepath = file_create_path($filename); 933 934 // Check if it's one of our files. 935 if ($file = db_fetch_object(db_query("SELECT a.nid, f.* FROM {audio} a INNER JOIN {files} f ON a.fid = f.fid WHERE f.filepath = '%s'", $filepath))) { 936 if (isset($file->nid) && $node = node_load($file->nid)) { 937 // Make sure they're allowed to view the node. 938 if (node_access('view', $node)) { 939 return array( 940 'Content-Type: '. mime_header_encode($file->filemime), 941 'Content-Length: '. (int) $file->filesize, 942 ); 943 } 944 945 // Access denied. 946 return -1; 947 } 948 } 949 } 950 /** 951 * Get an array of the allowed tags. 952 * 953 * @return 954 * Array of allowed tags. 955 */ 956 function audio_get_tags_allowed() { 957 return array_keys(audio_get_tag_settings()); 958 } 959 960 /** 961 * Get an array of the tags and their settings. 962 * 963 * @return 964 * Array of allowed tags. 965 */ 966 function audio_get_tag_settings() { 967 $defaults = array( 968 'artist' => array('autocomplete' => 1, 'required' => 1, 'hidden' => 0, 969 'writetofile' => 1, 'browsable' => 1, 'weight' => -2), 970 'title' => array('autocomplete' => 0, 'required' => 1, 'hidden' => 0, 971 'writetofile' => 1, 'browsable' => 1, 'weight' => -2), 972 'album' => array('autocomplete' => 1, 'required' => 0, 'hidden' => 0, 973 'writetofile' => 1, 'browsable' => 1, 'weight' => -1), 974 'track' => array('autocomplete' => 0, 'required' => 0, 'hidden' => 0, 975 'writetofile' => 1, 'browsable' => 0, 'weight' => -1), 976 'genre' => array('autocomplete' => 1, 'required' => 0, 'hidden' => 0, 977 'writetofile' => 1, 'browsable' => 1, 'weight' => 0), 978 'year' => array('autocomplete' => 0, 'required' => 0, 'hidden' => 0, 979 'writetofile' => 1, 'browsable' => 1, 'weight' => 1), 980 ); 981 return variable_get('audio_tag_settings', $defaults); 982 } 983 984 /** 985 * Retrieve autocomplete suggestions for existing audio metadata tags. 986 * 987 * @param $tag 988 * tag listed in audio_get_tag_settings() where autocomplete is true. 989 * @param $value 990 * partial tag value to try to find in the database. 991 */ 992 function audio_autocomplete($tag = '', $value = '') { 993 $matches = array(); 994 $tags = audio_get_tag_settings(); 995 if (isset($tags[$tag]) && $tags[$tag]['autocomplete']) { 996 $result = db_query_range("SELECT DISTINCT a.value FROM {audio_metadata} a WHERE a.tag = '%s' AND LOWER(a.value) LIKE LOWER('%s%%') ORDER BY a.value", $tag, $value, 0, 10); 997 while ($tag = db_fetch_object($result)) { 998 $matches[$tag->value] = check_plain($tag->value); 999 } 1000 } 1001 print drupal_to_js($matches); 1002 exit(); 1003 } 1004 1005 /** 1006 * Get the audio files directory. 1007 * 1008 * @return 1009 * string path to the audio directory 1010 */ 1011 function audio_get_directory() { 1012 // We have to make sure the files directory exists first... 1013 $dir = file_directory_path(); 1014 file_check_directory($dir, FILE_CREATE_DIRECTORY, 'made up element name'); 1015 // ...then that our audio sub-directory exists. 1016 $dir .= '/audio'; 1017 file_check_directory($dir, FILE_CREATE_DIRECTORY, 'made up element name'); 1018 1019 return $dir; 1020 } 1021 1022 1023 /** 1024 * Loads the player plugs-ins and returns their details. 1025 * 1026 * @return 1027 * Array with two sub arrays. The first keyed by player name, the second 1028 * keyed by format and then player name. The same player may be listed for 1029 * mulaudio_page_browse_bytiple formats. 1030 */ 1031 function _audio_player_build_list() { 1032 // Invoke any modules that implement the hook. 1033 $players_name = module_invoke_all('audio_player'); 1034 1035 // Load all our module's player plugins. 1036 $path = drupal_get_path('module', 'audio') .'/players'; 1037 $files = drupal_system_listing('.inc$', $path, 'name', 0); 1038 foreach ($files as $file) { 1039 require_once('./'. $file->filename); 1040 $function = 'audio_'. $file->name .'_audio_player'; 1041 if (function_exists($function)) { 1042 $result = $function(); 1043 if (isset($result) && is_array($result)) { 1044 foreach (array_keys($result) as $player) { 1045 // Keep track of the file where this player was found. 1046 $result[$player]['file'] = $file->basename; 1047 } 1048 $players_name = array_merge($players_name, $result); 1049 } 1050 } 1051 } 1052 1053 // Group players by format. 1054 $players_format = array(); 1055 foreach ($players_name as $name => $player) { 1056 foreach ($player['formats'] as $format) { 1057 $players_format[$format][$name] = $player; 1058 } 1059 } 1060 1061 return array($players_name, $players_format); 1062 } 1063 1064 /** 1065 * Return information on the installed player plugins. 1066 * 1067 * @param $op 1068 * String specifying the operation. Possible values are: 1069 * 'formats' 1070 * 'format' 1071 * 'names' 1072 * 'name' 1073 * @param $name 1074 * Name of a specific player, used with $op = 'format' or 'name'. 1075 */ 1076 function audio_get_players($op = 'names', $name = '') { 1077 static $_player_name, $_player_format; 1078 1079 if (!isset($_player_format)) { 1080 list($_player_name, $_player_format) = _audio_player_build_list(); 1081 } 1082 1083 switch ($op) { 1084 case 'formats': 1085 return $_player_format; 1086 case 'format': 1087 if (isset($_player_format[$name])) { 1088 return $_player_format[$name]; 1089 } 1090 return FALSE; 1091 case 'names': 1092 return $_player_name; 1093 case 'name': 1094 if (isset($_player_name[$name])) { 1095 return $_player_name[$name]; 1096 } 1097 return FALSE; 1098 default: 1099 return FALSE; 1100 } 1101 } 1102 1103 /** 1104 * Build HTML to play an audio node. 1105 * 1106 * @param $node 1107 * Node object. 1108 * @param $playername 1109 * Optional, string specifying the name of the desired player. 1110 * @return 1111 * HTML to play the audio tracks. 1112 */ 1113 function audio_get_node_player($node, $playername = NULL) { 1114 if (_audio_allow_play($node)) { 1115 $format = $node->audio['format']; 1116 if (!isset($playername)) { 1117 $playername = variable_get('audio_player_'. $format, '1pixelout'); 1118 } 1119 $player = audio_get_players('name', $playername); 1120 // Try to use the requested player, if that doesn't work out, use the generic one. 1121 return theme(array($player['theme_node'], 'audio_default_node_player'), $node, isset($player['options']) ? $player['options'] : array()); 1122 } 1123 } 1124 1125 /** 1126 * Provide a link to the audio file. 1127 * 1128 * @param $node 1129 * Node object. 1130 */ 1131 function theme_audio_default_node_player($node) { 1132 return '<span class="audio">'. l(t('Click to play'), $node->url_play) ."</span>\n"; 1133 } 1134 1135 /** 1136 * Take a tag and force it to be a-z 0-9 _ - 1137 * 1138 * @param $string 1139 * ID3 tag value 1140 * @return 1141 * cleaned up tag value for URL or database 1142 */ 1143 function audio_clean_tag($string) { 1144 // If we've got characters besides 0-9 A-Z a-z hyphen and underscore, replace 1145 // them. 1146 if (preg_match('/[^-\w]/', $string)) { 1147 // Remove accents... 1148 $string = strtr($string, '������������������������������������������������������������', 'SZszYAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy'); 1149 // ...convert to equivalent chars... 1150 $string = strtr($string, array('�' => 'TH', '�' => 'th', '�' => 'DH', '�' => 'dh', '�' => 'ss', '�' => 'OE', '�' => 'oe', '�' => 'AE', '�' => 'ae', '�' => 'u')); 1151 // ... and remove anything else that's not alphanumeric and replace it with an underscore. 1152 $string = preg_replace('/[^-\w]+/', '_', $string); 1153 } 1154 // Remove leading and trailing underscores. 1155 $string = trim($string, '_'); 1156 // Finally, make it to lower case. 1157 return strtolower($string); 1158 } 1159 1160 1161 /** 1162 * Create audio nodes from a file. 1163 * 1164 * Function for other modules to use to create a audio node from a file. Once 1165 * you've created it you can make any changes and then save it using 1166 * node_save(). 1167 * 1168 * @param $filepath 1169 * Full path to an audio file. be aware that the file will be moved into 1170 * drupal's directory. 1171 * @param $title_format 1172 * An optional, token string for generating the node's title. If nothing is 1173 * provided the default title format will be used. 1174 * @param $body 1175 * An optional string to use for the node's body. 1176 * @param $taxonomy 1177 * An optional array of taxonomy terms to assign to the node if the taxonomy 1178 * module is installed. 1179 * @param $tags 1180 * An optional array of metadata to add to the node. These will overwrite 1181 * any values loaded from the ID3 tags. 1182 * @return 1183 * A node or FALSE on error. 1184 */ 1185 function audio_api_insert($filepath, $title_format = NULL, $body = NULL, $tags = array(), $taxonomy = array()) { 1186 global $user; 1187 1188 // For node_object_prepare() 1189 module_load_include('inc', 'node', 'node.pages'); 1190 1191 // Check for user permission. 1192 if (!audio_access('create')) { 1193 drupal_access_denied(); 1194 } 1195 1196 // Begin building file object. 1197 $file = new stdClass(); 1198 $file->uid = $user->uid; 1199 $file->filepath = $filepath; 1200 $file->filename = basename($file->filepath); 1201 $file->filemime = module_exists('mimedetect') ? mimedetect_mime($file->filepath) : file_get_mimetype($file->filepath); 1202 $file->filesize = filesize($file->filepath); 1203 $file->timestamp = time(); 1204 $file->status = FILE_STATUS_TEMPORARY; 1205 drupal_write_record('files', $file); 1206 1207 $node = new stdClass(); 1208 $node->nid = NULL; 1209 $node->type = 'audio'; 1210 $node->uid = $user->uid; 1211 $node->name = $user->name; 1212 $node->language = ''; 1213 $node->title = ''; 1214 $node->title_format = $title_format; 1215 $node->body = $body; 1216 1217 // Set the node's defaults... (copied this from node and comment.module) 1218 $node_options = variable_get('node_options_'. $node->type, array('status', 'promote')); 1219 $node->status = in_array('status', $node_options); 1220 $node->moderate = in_array('moderate', $node_options); 1221 $node->promote = in_array('promote', $node_options); 1222 if (module_exists('comment')) { 1223 $node->comment = variable_get("comment_$node->type", COMMENT_NODE_READ_WRITE); 1224 } 1225 if (module_exists('taxonomy') && is_array($taxonomy)) { 1226 $node->taxonomy = $taxonomy; 1227 } 1228 1229 $node->audio_tags = array(); 1230 $node->audio_images = array(); 1231 1232 $node->audio = array( 1233 'downloadable' => variable_get('audio_default_downloadable', 1), 1234 'play_count' => 0, 1235 'download_count' => 0, 1236 'file' => $file, 1237 ); 1238 1239 node_object_prepare($node); 1240 1241 // Allow other modules to modify the node (hopefully reading in tags). 1242 audio_invoke_audioapi('upload', $node); 1243 1244 // Add the tags (overwriting any that audio_getid3 may have loaded). 1245 if (is_array($tags)) { 1246 $node->audio_tags = array_merge($node->audio_tags, $tags); 1247 } 1248 1249 // Build the title manually (since we don't call node_validate()). 1250 if (empty($node->title_format)) { 1251 $node->title_format = variable_get('audio_default_title_format', '[audio-tag-title-raw] by [audio-tag-artist-raw]'); 1252 } 1253 // Flush the token cache, otherwise when importing multiple nodes they'll all 1254 // have the same title. 1255 token_get_values('node', $node, TRUE); 1256 $node->title = token_replace($node->title_format, 'node', $node); 1257 1258 // Save it. 1259 $node = node_submit($node); 1260 node_save($node); 1261 1262 return $node; 1263 } 1264 1265 /** 1266 * Parse an array into a valid urlencoded query string. 1267 * 1268 * This function is a work-around for a drupal_urlencode issue in core. 1269 * See: http://drupal.org/node/158687 for details. 1270 * 1271 * @param $query 1272 * The array to be processed e.g. $_GET. 1273 * @param $exclude 1274 * The array filled with keys to be excluded. Use parent[child] to exclude 1275 * nested items. 1276 * @param $parent 1277 * Should not be passed, only used in recursive calls. 1278 * @return 1279 * urlencoded string which can be appended to/as the URL query string. 1280 */ 1281 function audio_query_string_encode($query, $exclude = array(), $parent = '') { 1282 $params = array(); 1283 1284 foreach ($query as $key => $value) { 1285 $key = urlencode($key); 1286 if ($parent) { 1287 $key = $parent .'['. $key .']'; 1288 } 1289 1290 if (in_array($key, $exclude)) { 1291 continue; 1292 } 1293 1294 if (is_array($value)) { 1295 $params[] = audio_query_string_encode($value, $exclude, $key); 1296 } 1297 else { 1298 $params[] = $key .'='. urlencode($value); 1299 } 1300 } 1301 1302 return implode('&', $params); 1303 } 1304 1305 /** 1306 * Determines if an audio node can be played by Flash players. 1307 * 1308 * @param $node 1309 * Node object. 1310 * @return 1311 * Boolean 1312 */ 1313 function audio_is_flash_playable($node) { 1314 // Flash only supports a limited range of sample rates. 1315 switch ($node->audio['sample_rate']) { 1316 case '44100': case '22050': case '11025': 1317 return TRUE; 1318 default: 1319 return FALSE; 1320 } 1321 } 1322 1323 /** 1324 * Implementation of hook_view_api(). 1325 */ 1326 function audio_views_api() { 1327 return array( 1328 'api' => 2.0, 1329 'path' => drupal_get_path('module', 'audio') . '/views', 1330 ); 1331 } 1332 1333 /** 1334 * Implementation of the token.module's hook_token_values(). 1335 * 1336 * @param $type 1337 * The current context -- 'node', 'user', 'global', etc. 1338 * @param $object 1339 * The specific node, user, etc. that should be used as the basis for the 1340 * replacements. 1341 * @return 1342 * Array of tokens. 1343 */ 1344 function audio_token_values($type, $object = NULL) { 1345 $node = $object; 1346 if ($type == 'node' && $node->type == 'audio') { 1347 // Tags. 1348 foreach (audio_get_tags_allowed() as $tag) { 1349 if (isset($node->audio_tags[$tag])) { 1350 $name = strtr($tag, '_', '-'); 1351 $tokens['audio-tag-'. $name] = check_plain($node->audio_tags[$tag]); 1352 $tokens['audio-tag-'. $name .'-raw'] = $node->audio_tags[$tag]; 1353 } 1354 } 1355 1356 // Formatted file info. 1357 $tokens['audio-length'] = theme('audio_format_filelength', $node->audio); 1358 $tokens['audio-format'] = theme('audio_format_fileformat', $node->audio); 1359 1360 // Raw file info. 1361 $keys = array('format', 'filename', 'filepath', 'filemime', 'file_size', 'sample_rate', 'channel_mode', 'bitrate', 'bitrate_mode', 'playtime'); 1362 foreach ($keys as $key) { 1363 if (isset($node->audio[$key])) { 1364 $tokens['audio-'. strtr($key, '_', '-')] = check_plain($node->audio[$key]); 1365 } 1366 } 1367 // Play and download links. 1368 if (isset($node->url_play)) { 1369 $tokens['audio-player'] = audio_get_node_player($node); 1370 $tokens['audio-url-play'] = $node->url_play; 1371 } 1372 if (isset($node->url_download)) { 1373 $tokens['audio-url-download'] = $node->url_download; 1374 } 1375 1376 return $tokens; 1377 } 1378 } 1379 1380 /** 1381 * Implementation of the token.module's hook_token_values(). 1382 * 1383 * @param $type 1384 * Indicates the context that token help is being generated for. Unlike 1385 * hook_token_values however, you should show ALL tokens at the same time if 1386 * $type is 'all'. 1387 * @return 1388 * Array of token information. 1389 */ 1390 function audio_token_list($type = 'all') { 1391 if ($type == 'node' || $type == 'all') { 1392 // Tags. 1393 foreach (audio_get_tags_allowed() as $tag) { 1394 $name = strtr($tag, '_', '-'); 1395 $tokens['node']['audio-tag-'. $name] = t("Audio node @tag tag value.", array('@tag' => $tag)); 1396 $tokens['node']['audio-tag-'. $name .'-raw'] = t("Audio node @tag tag value. WARNING - raw user input.", array('@tag' => $tag)); 1397 } 1398 1399 // Formatted file info. 1400 $tokens['node']['audio-length'] = t("Audio node formatted file length information."); 1401 $tokens['node']['audio-format'] = t("Audio node formatted file format information."); 1402 1403 // Raw file info. 1404 $tokens['node']['audio-sample-rate'] = t("Audio node sample rate, integer e.g. 44100."); 1405 $tokens['node']['audio-channel-mode'] = t("Audio node channels, e.g. mono, stereo."); 1406 $tokens['node']['audio-bitrate'] = t("Audio node bitrate, integer e.g. 19200."); 1407 $tokens['node']['audio-bitrate-mode'] = t("Audio node bitrate encoding mode, e.g. vbr, cbr."); 1408 $tokens['node']['audio-playtime'] = t("Audio node play time, minutes:seconds."); 1409 $tokens['node']['audio-file-format'] = t("Audio node file format, e.g. mp3, ogg"); 1410 $tokens['node']['audio-file-name'] = t("Audio node original, uploaded file name."); 1411 $tokens['node']['audio-file-path'] = t("Audio node file path."); 1412 $tokens['node']['audio-file-mime'] = t("Audio node MIME type."); 1413 $tokens['node']['audio-file-size'] = t("Audio node file size, in bytes."); 1414 1415 // Play and download links. 1416 $tokens['node']['audio-player'] = t("Audio node player."); 1417 $tokens['node']['audio-url-play'] = t("Audio node play URL."); 1418 $tokens['node']['audio-url-download'] = t("Audio node download URL."); 1419 return $tokens; 1420 } 1421 } 1422 1423 /** 1424 * Implements hook_content_extra_fields() 1425 * 1426 * CCK hook to allow sorting of the audio settings field. 1427 */ 1428 function audio_content_extra_fields($type_name) { 1429 if ($type_name == 'audio') { 1430 return array( 1431 'audio' => array( 1432 'label' => t('Audio files'), 1433 'description' => t('Audio uploads for posts'), 1434 'weight' => 1, 1435 ), 1436 ); 1437 } 1438 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |