? .audio.module.swp ? audio_image.patch ? db_audio.sql Index: audio.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/audio/audio.install,v retrieving revision 1.22 diff -u -p -r1.22 audio.install --- audio.install 14 Aug 2008 20:42:04 -0000 1.22 +++ audio.install 1 Oct 2008 23:46:40 -0000 @@ -41,6 +41,12 @@ function audio_schema() { 'not null' => TRUE, 'default' => 0, ), + 'fid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => t('Primary Key: The {files}.fid.'), + ), 'title_format' => array( 'type' => 'varchar', 'length' => 128, @@ -64,36 +70,12 @@ function audio_schema() { 'not null' => TRUE, 'default' => 1, ), - 'file_format' => array( + 'format' => array( 'type' => 'varchar', 'length' => 10, 'not null' => TRUE, 'default' => '', ), - 'file_mime' => array( - 'type' => 'varchar', - 'length' => 255, - 'not null' => TRUE, - 'default' => '', - ), - 'file_name' => array( - 'type' => 'varchar', - 'length' => 255, - 'not null' => TRUE, - 'default' => '', - ), - 'file_path' => array( - 'type' => 'varchar', - 'length' => 255, - 'not null' => TRUE, - 'default' => '', - ), - 'file_size' => array( - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => TRUE, - 'default' => 0, - ), 'sample_rate' => array( 'type' => 'int', 'size' => 'medium', @@ -126,6 +108,9 @@ function audio_schema() { ), ), 'primary key' => array('vid'), + 'indexes' => array( + 'audio_fid' => array('fid'), + ), ); $schema['audio_metadata'] = array( 'description' => t('Extended data about audio files.'), @@ -533,3 +518,50 @@ function audio_update_6001() { db_add_primary_key($ret, 'audio_metadata', array('vid', 'tag', 'value')); return $ret; } + +/** + * Move the audio files from the {audio} table to the {files} table and then + * remove the columns. + * + * @return unknown + */ +function audio_update_6002() { + $ret = array(); + + // Create the fid field so we've got a place to store the file id's as we + // migrate them. + $fid_field = array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => t('Primary Key: The {files}.fid.'), + ); + db_add_field($ret, 'audio', 'fid', $fid_field); + db_add_index($ret, 'audio', 'audio_fid', array('fid')); + + // Load all the distinct filepaths, note that this may update multiple audio + // rows at once. + $result = db_query("SELECT DISTINCT file_path FROM {audio} WHERE fid IS NULL OR fid = 0"); + while ($file = db_fetch_object($result)) { + // Then move the data into the files table. + db_query("INSERT INTO {files} (uid, filename, filepath, filemime, filesize, status, timestamp) SELECT n.uid, '%s', ai.file_path, ai.file_mime, ai.file_size, 1, n.created AS timestamp FROM {node} n INNER JOIN {audio} ai ON n.vid = ai.vid WHERE ai.file_path = '%s' LIMIT 1", array(basename($file->file_path), $file->file_path)); + db_query("UPDATE {audio} SET fid = %d WHERE file_path = '%s'", db_last_insert_id('files', 'fid'), $file->file_path); + } + + // Drop the old fields. + db_drop_field($ret, 'audio', 'file_mime'); + db_drop_field($ret, 'audio', 'file_name'); + db_drop_field($ret, 'audio', 'file_path'); + db_drop_field($ret, 'audio', 'file_size'); + + // Rename the file_format field to format. + $format_field = array( + 'type' => 'varchar', + 'length' => 10, + 'not null' => TRUE, + 'default' => '', + ); + db_change_field($ret, 'audio', 'file_format', 'format', $format_field); + + return $ret; +} \ No newline at end of file Index: audio.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/audio/audio.module,v retrieving revision 1.144 diff -u -p -r1.144 audio.module --- audio.module 30 Sep 2008 05:00:52 -0000 1.144 +++ audio.module 1 Oct 2008 23:46:40 -0000 @@ -276,7 +276,7 @@ function audio_access($op, $node = NULL) * boolean indicating if it's allowed. */ function _audio_allow_download($node) { - if ($node->type == 'audio' && isset($node->url_download) && $node->audio_file['downloadable']) { + if ($node->type == 'audio' && isset($node->url_download) && $node->audio['downloadable']) { $result = audio_invoke_audioapi('access', $node, 'download'); if (in_array(TRUE, $result)) { @@ -341,13 +341,13 @@ function audio_link($type, $node, $main ); if ($link_access) { $links['audio_download_count'] = array( - 'title' => t('@download_count downloads', array('@download_count' => $node->audio_file['download_count'])), + 'title' => t('@download_count downloads', array('@download_count' => $node->audio['download_count'])), ); } } if (_audio_allow_play($node) && $link_access) { $links['audio_play_count'] = array( - 'title' => t('@play_count plays', array('@play_count' => $node->audio_file['play_count'])), + 'title' => t('@play_count plays', array('@play_count' => $node->audio['play_count'])), ); } } @@ -377,8 +377,8 @@ function audio_nodeapi(&$node, $op, $arg 'key' => 'enclosure', 'attributes' => array( 'url' => $node->url_download, - 'length' => $node->audio_file['file_size'], - 'type' => $node->audio_file['file_mime'] + 'length' => $node->audio['file']->filesize, + 'type' => $node->audio['file']->filemime )); // Provide very basic iTunes support. $ret[] = array( @@ -386,7 +386,7 @@ function audio_nodeapi(&$node, $op, $arg ); $ret[] = array( 'key' => 'itunes:duration', - 'value' => $node->audio_file['playtime'], + 'value' => $node->audio['playtime'], ); $ret[] = array( 'key' => 'itunes:author', @@ -433,8 +433,7 @@ function audio_view(&$node, $teaser = FA * Implementation of hook_validate(). */ function audio_validate(&$node, &$form) { - $nid = ($node->nid) ? $node->nid : 'new_node'; - if (!isset($node->audio_file['file_path'])) { + if (!isset($node->audio['file']->filepath)) { 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.")); } @@ -450,35 +449,34 @@ function audio_load($node) { if ($node->vid) { // This is a wonky way to load the fields but its handy right now while // I'm renaming fields in the databases. - $fields = db_fetch_array(db_query("SELECT * FROM {audio} WHERE vid=%d", $node->vid)); + $fields = db_fetch_array(db_query("SELECT a.* FROM {audio} a WHERE vid=%d", $node->vid)); + $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE fid=%d", $fields['fid'])); + $ret = array( 'title_format' => $fields['title_format'], - 'audio_file' => array( + 'audio' => array( 'play_count' => $fields['play_count'], 'download_count' => $fields['download_count'], 'downloadable' => $fields['downloadable'], - 'file_format' => $fields['file_format'], - 'file_mime' => $fields['file_mime'], - 'file_name' => $fields['file_name'], - 'file_path' => $fields['file_path'], - 'file_size' => $fields['file_size'], + 'format' => $fields['format'], 'sample_rate' => $fields['sample_rate'], 'channel_mode' => $fields['channel_mode'], 'bitrate' => $fields['bitrate'], 'bitrate_mode' => $fields['bitrate_mode'], 'playtime' => $fields['playtime'], 'bitrate' => $fields['bitrate'], + 'file' => $file, ), ); - if (file_exists($fields['file_path'])) { + if (isset($file->filepath) && file_exists($file->filepath)) { // TODO: should these links be by vid? $ret['url_play'] = url('audio/play/'. $node->nid, array('absolute' => TRUE)); - if ($ret['audio_file']['downloadable']) { + if ($ret['audio']['downloadable']) { // iTunes and other podcasting programs check the url to determine the // file type. we'll add the original file name on to the end. see issues // #35398 and #68716 for more info. - $url = 'audio/download/'. $node->nid .'/'. $fields['file_name']; + $url = 'audio/download/'. $node->nid .'/'. $file->filename; $ret['url_download'] = url($url, array('absolute' => TRUE)); } } @@ -499,83 +497,75 @@ function audio_load($node) { * Implementation of hook_insert(). */ function audio_insert(&$node) { - file_move($node->audio_file['file_path'], audio_get_directory(), FILE_EXISTS_RENAME); - - $f = $node->audio_file; - db_query("INSERT INTO {audio} (vid, nid, title_format, downloadable, file_format, file_name, file_path, file_mime, file_size, bitrate, bitrate_mode, sample_rate, channel_mode, playtime) - VALUES (%d, %d, '%s', %d, '%s', '%s', '%s', '%s', %d, %f, '%s', %d, '%s', '%s')", - $node->vid, $node->nid, $node->title_format, $f['downloadable'], $f['file_format'], $f['file_name'], $f['file_path'], $f['file_mime'], filesize($f['file_path']), $f['bitrate'], $f['bitrate_mode'], $f['sample_rate'], $f['channel_mode'], $f['playtime']); - - _audio_save_tags_to_db($node); - - // Unset the new file flag incase this node is re-saved. - unset($node->audio_file['newfile']); + file_move($node->audio['file']->filepath, audio_get_directory(), FILE_EXISTS_RENAME); + _audio_save($node); } /** - * Insert a new node revision. - * - * If a new file wasn't uploaded, make a copy of the existing file. + * Implementation of hook_update(). */ -function audio_insert_revision($node) { - if (isset($node->audio_file['newfile'])) { - file_move($node->audio_file['file_path'], audio_get_directory(), FILE_EXISTS_RENAME); +function audio_update(&$node) { + // If there's a new file we need to move it to the correct location. + if (isset($node->audio['newfile'])) { + if (!$node->revision) { + // If it's not a revision the existing file needs to be removed. + $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)); + _audio_file_delete($oldfile); + } + file_move($node->audio['file']->filepath, audio_get_directory(), FILE_EXISTS_RENAME); } - else { - $newname = file_create_filename($node->audio_file['file_name'], audio_get_directory()); - file_copy($node->audio_file['file_path'], $newname); + else if ($node->revision) { + // New revision using existing file so we need to copy it. + file_copy($node->audio['file']->filepath, file_create_filename($node->audio['file']->filename, audio_get_directory())); + // Unset the fid so a new record is created. + $node->audio['file']->fid = NULL; } - $f = $node->audio_file; - db_query("INSERT INTO {audio} (vid, nid, title_format, downloadable, file_format, file_name, file_path, file_mime, file_size, bitrate, bitrate_mode, sample_rate, channel_mode, playtime) - VALUES (%d, %d, '%s', %d, '%s', '%s', '%s', '%s', %d, %f, '%s', %d, '%s', '%s')", - $node->vid, $node->nid, $node->title_format, $f['downloadable'], $f['file_format'], $f['file_name'], $f['file_path'], $f['file_mime'], filesize($f['file_path']), $f['bitrate'], $f['bitrate_mode'], $f['sample_rate'], $f['channel_mode'], $f['playtime']); - - _audio_save_tags_to_db($node); + _audio_save($node, array('vid')); } /** - * Implementation of hook_update(). + * Handle the busy work of saving the node's audio and file records. + * + * @param $node Node opject. + * @param $update Array of fields to match for an update, empty array inserts + * a new record. */ -function audio_update(&$node) { - // Check for new revsion. - if ($node->revision) { - return audio_insert_revision($node); - } +function _audio_save(&$node, $update = array()) { + // Save the file + $node->audio['file']->timestamp = time(); + $node->audio['file']->filesize = filesize($node->audio['file']->filepath); + $node->audio['file']->status |= FILE_STATUS_PERMANENT; + // If there's an fid update, otherwise insert. + drupal_write_record('files', $node->audio['file'], empty($node->audio['file']->fid) ? array() : array('fid')); - if (isset($node->audio_file['newfile'])) { - unset($node->audio_file['newfile']); + // Save the audio row. + $audio = array_merge($node->audio, array('nid' => $node->nid, 'vid' => $node->vid, 'title_format' => $node->title_format, 'fid' => $node->audio['file']->fid)); + drupal_write_record('audio', $audio, $update); - // Remove the old file. - $oldfile = db_fetch_object(db_query('SELECT file_path FROM {audio} f WHERE f.vid = %d', $node->vid)); - file_delete($oldfile->file_path); + // Remove any existing metadata. + db_query("DELETE FROM {audio_metadata} WHERE vid=%d", $node->vid); - // Save the new one. - file_move($node->audio_file['file_path'], audio_get_directory(), FILE_EXISTS_RENAME); + // Save the new tags. + $allowed_tags = audio_get_tags_allowed(); + foreach ($node->audio_tags as $tag => $value) { + if (in_array($tag, $allowed_tags) && $value) { + $metadata = array('vid' => $node->vid, 'tag' => $tag, 'value' => $value, 'clean' => audio_clean_tag($value)); + drupal_write_record('audio_metadata', $metadata); + } } - // Do a delete and insert rather than an update to ensure that we've got db - // records. it takes a bit longer but it allows us to carry on if one of the - // records wasn't created by audio_insert(). - db_query("DELETE FROM {audio} WHERE vid=%d", $node->vid); - - $f = $node->audio_file; - db_query("INSERT INTO {audio} (vid, nid, title_format, play_count, download_count, downloadable, file_format, file_name, file_path, file_mime, file_size, bitrate, bitrate_mode, sample_rate, channel_mode, playtime) - VALUES (%d, %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', %d, %f, '%s', %d, '%s', '%s')", - $node->vid, $node->nid, $node->title_format, $f['play_count'], $f['download_count'], $f['downloadable'], $f['file_format'], $f['file_name'], $f['file_path'], $f['file_mime'], filesize($f['file_path']), $f['bitrate'], $f['bitrate_mode'], $f['sample_rate'], $f['channel_mode'], $f['playtime']); - - _audio_save_tags_to_db($node); + // Unset the new file flag incase this node is re-saved. + unset($node->audio['newfile']); } /** * Implementation of hook_delete(). */ function audio_delete($node) { - $result = db_query('SELECT vid, file_path FROM {audio} WHERE nid = %d', $node->nid); + $result = db_query('SELECT a.vid, f.* FROM {audio} a LEFT JOIN {files} f ON a.fid = f.fid WHERE nid = %d', $node->nid); while ($o = db_fetch_object($result)) { - if (isset($o->file_path)) { - file_delete($o->file_path); - } + _audio_file_delete($o); db_query('DELETE FROM {audio_metadata} WHERE vid = %d', $o->vid); } db_query('DELETE FROM {audio} WHERE nid = %d', $node->nid); @@ -585,15 +575,28 @@ function audio_delete($node) { * Delete a single revision. */ function audio_delete_revision($node) { - if ($filepath = db_result(db_query('SELECT file_path FROM {audio} WHERE vid = %d', $node->vid))) { - file_delete($filepath); - } + $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)); + _audio_file_delete($file); db_query('DELETE FROM {audio_metadata} WHERE vid = %d', $node->vid); db_query('DELETE FROM {audio} WHERE vid = %d', $node->vid); } /** + * Handle the busy work of deleting the file record and the file. + * + * @param unknown_type $file + */ +function _audio_file_delete($file) { + if (!empty($file->filepath)) { + file_delete($file->filepath); + } + if (!empty($file->fid)) { + db_query('DELETE FROM {files} WHERE fid = %d', array($file->fid)); + } +} + +/** * Implementation of hook_form(). */ function audio_form(&$node, &$form_state) { @@ -630,7 +633,7 @@ function audio_form(&$node, &$form_state } - $form['audio_file'] = array( + $form['audio'] = array( '#type' => 'fieldset', '#title' => t('Audio File Info'), '#collapsible' => TRUE, @@ -640,112 +643,104 @@ function audio_form(&$node, &$form_state // Place a visible copy of the file path on the form (after removing the // directory info from non-admins). - $form['audio_file']['display_file_path'] = array( + $form['audio']['display_filepath'] = array( '#type' => 'item', '#title' => t('Current File'), - '#value' => empty($node->audio_file['file_path']) ? t('No file is attached.') : (user_access('administer audio') ? $node->audio_file['file_path'] : basename($node->audio_file['file_path'])), + '#value' => empty($node->audio['file']->filepath) ? t('No file is attached.') : (user_access('administer audio') ? $node->audio['file']->filepath : basename($node->audio['file']->filepath)), ); // If we've got a file, add the file information fields. - if (!empty($node->audio_file['file_name'])) { - $form['audio_file']['#theme'] = 'audio_file_form'; + if (!empty($node->audio['file']->filename)) { + $form['audio']['#theme'] = 'audio_file_form'; // Store the non-user editable file information as values. - $form['audio_file']['file_path'] = array( - '#type' => 'value', - '#value' => $node->audio_file['file_path'], - ); - $form['audio_file']['file_name'] = array( - '#type' => 'value', - '#value' => $node->audio_file['file_name'], - ); - $form['audio_file']['file_mime'] = array( + $form['audio']['file'] = array( '#type' => 'value', - '#value' => $node->audio_file['file_mime'], + '#value' => $node->audio['file'], ); - $form['audio_file']['file_format'] = array( + $form['audio']['format'] = array( '#type' => 'select', '#title' => t('Format'), - '#default_value' => $node->audio_file['file_format'], + '#default_value' => $node->audio['format'], '#options' => drupal_map_assoc(array('', 'aac', 'ac3', 'au', 'avr', 'flac', 'midi', 'mod', 'mp3', 'mpc', 'ogg', 'voc'), 'drupal_strtoupper'), ); - $form['audio_file']['file_size'] = array( + $form['audio']['file_size'] = array( '#type' => 'textfield', '#title' => t('File Size'), - '#default_value' => $node->audio_file['file_size'], + '#default_value' => $node->audio['file']->filesize, ); - $form['audio_file']['playtime'] = array( + $form['audio']['playtime'] = array( '#type' => 'textfield', '#title' => t('Length'), - '#default_value' => $node->audio_file['playtime'], + '#default_value' => $node->audio['playtime'], '#description' => t('The format is hours:minutes:seconds.'), ); - $form['audio_file']['sample_rate'] = array( + $form['audio']['sample_rate'] = array( '#type' => 'select', '#title' => t('Sample rate'), - '#default_value' => $node->audio_file['sample_rate'], + '#default_value' => $node->audio['sample_rate'], '#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'), ); - $form['audio_file']['channel_mode'] = array( + $form['audio']['channel_mode'] = array( '#type' => 'select', '#title' => t('Channel mode'), - '#default_value' => $node->audio_file['channel_mode'], + '#default_value' => $node->audio['channel_mode'], '#options' => array('stereo' => t('Stereo'), 'mono' => t('Mono')), ); - $form['audio_file']['bitrate'] = array( + $form['audio']['bitrate'] = array( '#type' => 'textfield', '#title' => t('Bitrate'), - '#default_value' => $node->audio_file['bitrate'], + '#default_value' => $node->audio['bitrate'], ); - $form['audio_file']['bitrate_mode'] = array( + $form['audio']['bitrate_mode'] = array( '#type' => 'select', '#title' => t('Bitrate mode'), - '#default_value' => $node->audio_file['bitrate_mode'], + '#default_value' => $node->audio['bitrate_mode'], '#options' => array('' => '', 'cbr' => t('Constant'), 'vbr' => t('Variable')), ); // Users shouldn't be able to change the play and download counts so we'll // put these for viewing... - $form['audio_file']['display_play_count'] = array( + $form['audio']['display_play_count'] = array( '#type' => 'item', '#title' => t('Play count'), - '#value' => $node->audio_file['play_count'], + '#value' => $node->audio['play_count'], ); - $form['audio_file']['display_download_count'] = array( + $form['audio']['display_download_count'] = array( '#type' => 'item', '#title' => t('Download count'), - '#value' => $node->audio_file['download_count'], + '#value' => $node->audio['download_count'], ); // ...and these are what we'll save back to the node. - $form['audio_file']['play_count'] = array( + $form['audio']['play_count'] = array( '#type' => 'value', - '#value' => $node->audio_file['play_count'], + '#value' => $node->audio['play_count'], ); - $form['audio_file']['download_count'] = array( + $form['audio']['download_count'] = array( '#type' => 'value', - '#value' => $node->audio_file['download_count'], + '#value' => $node->audio['download_count'], ); } - $form['audio_file']['audio_upload'] = array( + $form['audio']['audio_upload'] = array( '#tree' => FALSE, '#type' => 'file', - '#title' => empty($node->audio_file['file_name']) ? t('Add a new audio file') : t('Replace this with a new file'), + '#title' => empty($node->audio['file']->filename) ? t('Add a new audio file') : t('Replace this with a new file'), '#description' => t('Click "Browse..." to select an audio file to upload. Only files with the following extensions are allowed: %allowed-extensions.', array('%allowed-extensions' => variable_get('audio_allowed_extensions', 'mp3 wav ogg'))) .'
' . t('NOTE: the current PHP configuration limits uploads to %maxsize.', array('%maxsize' => format_size(file_upload_max_size()))), ); - $form['audio_file']['downloadable'] = array( + $form['audio']['downloadable'] = array( '#type' => 'checkbox', '#title' => t('Allow file downloads.'), - '#default_value' => !empty($node->audio_file['downloadable']) ? $node->audio_file['downloadable'] : variable_get('audio_default_downloadable', 1), + '#default_value' => !empty($node->audio['downloadable']) ? $node->audio['downloadable'] : variable_get('audio_default_downloadable', 1), '#description' => t('If checked, a link will be displayed allowing visitors to download this audio file on to their own computer.') .'
' . t('WARNING: 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.'), ); // If we've got a file, add the fields for editing meta data. - if (!empty($node->audio_file['file_path'])) { + if (!empty($node->audio['file']->filepath)) { $form['audio_tags'] = array( '#type' => 'fieldset', '#title' => t('Audio Metadata'), @@ -802,15 +797,12 @@ function audio_node_form_validate($form, ); if ($file = file_save_upload('audio_upload', $validators)) { $node = (object) $form_state['values']; - $node->audio_file = array( + $node->audio = array( 'newfile' => TRUE, 'play_count' => 0, 'download_count' => 0, - 'downloadable' => (bool) $form_state['values']['audio_file']['downloadable'], - 'file_name' => $file->filename, - 'file_path' => $file->filepath, - 'file_mime' => $file->filemime, - 'file_size' => $file->filesize, + 'downloadable' => (bool) $form_state['values']['audio']['downloadable'], + 'file' => $file, ); // Allow other modules to modify the node. @@ -820,8 +812,9 @@ function audio_node_form_validate($form, // form. Note that we do this after calling we called our api hook with // the upload operation, it gives the audio_id3 module a chance to read // the tags. - $form_state['values']['audio_file'] = $node->audio_file; + $form_state['values']['audio'] = $node->audio; $form_state['values']['audio_tags'] = $node->audio_tags; + $form_state['values']['audio_images'] = $node->audio_images; } } @@ -904,7 +897,7 @@ function audio_user($op, &$edit, &$user, function audio_block($op = 'list', $delta = 0, $edit = array()) { switch ($op) { case 'list': - $blocks[2]['info'] = t('audio: Browse by'); + $blocks[2]['info'] = t('Audio: Browse by'); return $blocks; case 'view': @@ -1089,7 +1082,7 @@ function audio_get_players($op = 'names' */ function audio_get_node_player($node, $playername = NULL) { if (_audio_allow_play($node)) { - $format = $node->audio_file['file_format']; + $format = $node->audio['format']; if (!isset($playername)) { $playername = variable_get('audio_player_'. $format, '1pixelout'); } @@ -1166,7 +1159,16 @@ function audio_api_insert($filepath, $ti drupal_access_denied(); } - $filepath = realpath($filepath); + // Begin building file object. + $file = new stdClass(); + $file->uid = $user->uid; + $file->filepath = $filepath; + $file->filename = basename($file->filepath); + $file->filemime = module_exists('mimedetect') ? mimedetect_mime($file->filepath) : file_get_mimetype($file->filepath); + $file->filesize = filesize($file->filepath); + $file->timestamp = time(); + $file->status = FILE_STATUS_TEMPORARY; + drupal_write_record('files', $file); $node = new stdClass(); $node->nid = NULL; @@ -1190,15 +1192,12 @@ function audio_api_insert($filepath, $ti $node->audio_tags = array(); $node->audio_images = array(); - $node->audio_file = array( + $node->audio = array( 'newfile' => TRUE, 'downloadable' => variable_get('audio_default_downloadable', 1), 'play_count' => 0, 'download_count' => 0, - 'file_size' => filesize($filepath), - 'file_name' => basename($filepath), - 'file_path' => $filepath, - 'file_mime' => module_exists('mimedetect') ? mimedetect_mime($filepath) : file_get_mimetype($filepath), + 'file' => $file, ); node_object_prepare($node); @@ -1228,27 +1227,6 @@ function audio_api_insert($filepath, $ti } /** - * Save the node's ID3 tags into the database. - * - * @param $node - * Node object. - */ -function _audio_save_tags_to_db($node) { - $allowed_tags = audio_get_tags_allowed(); - - // Remove any existing metadata. - db_query("DELETE FROM {audio_metadata} WHERE vid=%d", $node->vid); - - // Save the new tags. - foreach ($node->audio_tags as $tag => $value) { - if (in_array($tag, $allowed_tags) && $value) { - db_query("INSERT INTO {audio_metadata} (vid, tag, value, clean) VALUES (%d, '%s', '%s', '%s')", - $node->vid, $tag, $value, audio_clean_tag($value)); - } - } -} - -/** * Parse an array into a valid urlencoded query string. * * This function is a work-around for a drupal_urlencode issue in core. @@ -1298,7 +1276,7 @@ function audio_query_string_encode($quer */ function audio_is_flash_playable($node) { // Flash only supports a limited range of sample rates. - switch ($node->audio_file['sample_rate']) { + switch ($node->audio['sample_rate']) { case '44100': case '22050': case '11025': return TRUE; default: @@ -1332,14 +1310,14 @@ function audio_token_values($type, $obje } // Formatted file info. - $tokens['audio-length'] = theme('audio_format_filelength', $node->audio_file); - $tokens['audio-format'] = theme('audio_format_fileformat', $node->audio_file); + $tokens['audio-length'] = theme('audio_format_filelength', $node->audio); + $tokens['audio-format'] = theme('audio_format_fileformat', $node->audio); // Raw file info. - $keys = array('file_format', 'file_name', 'file_path', 'file_mime', 'file_size', 'sample_rate', 'channel_mode', 'bitrate', 'bitrate_mode', 'playtime'); + $keys = array('format', 'filename', 'filepath', 'filemime', 'file_size', 'sample_rate', 'channel_mode', 'bitrate', 'bitrate_mode', 'playtime'); foreach ($keys as $key) { - if (isset($node->audio_file[$key])) { - $tokens['audio-'. strtr($key, '_', '-')] = check_plain($node->audio_file[$key]); + if (isset($node->audio[$key])) { + $tokens['audio-'. strtr($key, '_', '-')] = check_plain($node->audio[$key]); } } // Play and download links. Index: audio.pages.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/audio/audio.pages.inc,v retrieving revision 1.1 diff -u -p -r1.1 audio.pages.inc --- audio.pages.inc 30 Sep 2008 05:00:52 -0000 1.1 +++ audio.pages.inc 1 Oct 2008 23:46:40 -0000 @@ -75,7 +75,7 @@ function audio_download($node) { // The mime_header_encode function does not (yet) support // quoted-string encoding of ASCII strings with special // characters. See discussion at http://drupal.org/node/82614 - $filename = $node->audio_file['file_name']; + $filename = $node->audio['file']->filename; // If the string contains non-ASCII characters, process it through // the mime_header_encode function. if (preg_match('/[^\x20-\x7E]/', $filename)) { @@ -87,11 +87,11 @@ function audio_download($node) { $filename = '"'. str_replace('"', '\"', $filename) .'"'; } $headers = array( - 'Content-Type: '. mime_header_encode($node->audio_file['file_mime']), - 'Content-Length: '. $node->audio_file['file_size'], + 'Content-Type: '. mime_header_encode($node->audio['file']->filemime), + 'Content-Length: '. $node->audio['file']->filesize, 'Content-Disposition: attachment; filename='. $filename, ); - audio_file_transfer($node->audio_file['file_path'], $headers); + audio_file_transfer($node->audio['file']->filepath, $headers); } /** @@ -114,14 +114,14 @@ function audio_play($node = FALSE) { 'Pragma: public', 'Expires: 0', 'Cache-Control: must-revalidate, post-check=0, pre-check=0, private', - 'Content-Type: '. mime_header_encode($node->audio_file['file_mime']), - 'Content-Length: '. $node->audio_file['file_size'], + 'Content-Type: '. mime_header_encode($node->audio['file']->filemime), + 'Content-Length: '. $node->audio['file']->filesize, 'Content-Disposition: inline;', 'Content-Transfer-Encoding: binary', ); // Required for IE, otherwise Content-disposition is ignored. ini_set('zlib.output_compression', 'Off'); - audio_file_transfer($node->audio_file['file_path'], $headers); + audio_file_transfer($node->audio['file']->filepath, $headers); } /** Index: audio.theme.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/audio/audio.theme.inc,v retrieving revision 1.1 diff -u -p -r1.1 audio.theme.inc --- audio.theme.inc 25 May 2008 23:10:50 -0000 1.1 +++ audio.theme.inc 1 Oct 2008 23:46:40 -0000 @@ -23,8 +23,8 @@ function theme_audio_display($node) { . theme('audio_format_tag', $tag, $node->audio_tags[$tag], $setting); } } - $items[] = ''. t('Length') .': '. theme('audio_format_filelength', $node->audio_file); - $items[] = ''. t('Format') .': '. theme('audio_format_fileformat', $node->audio_file); + $items[] = ''. t('Length') .': '. theme('audio_format_filelength', $node->audio); + $items[] = ''. t('Format') .': '. theme('audio_format_fileformat', $node->audio); $output = "
\n"; // give audio_image.module (or a theme) a chance to display the images. @@ -63,10 +63,10 @@ function theme_audio_format_tag($tag, $v * Return a string describing the node's file size and play time. * * @param $fileinfo - * Audio node's audio_file array. + * Audio node's audio array. */ function theme_audio_format_filelength($fileinfo) { - $args['@filesize'] = format_size(isset($fileinfo['file_size']) ? $fileinfo['file_size'] : 0); + $args['@filesize'] = format_size(isset($fileinfo['file']->filesize) ? $fileinfo['file']->filesize : 0); if (empty($fileinfo['playtime'])) { return t('@filesize', $args); } @@ -80,14 +80,14 @@ function theme_audio_format_filelength($ * Return a string describing the node's file information. * * @param $fileinfo - * Audio node's audio_fileinfo array. + * Audio node's audioinfo array. */ function theme_audio_format_fileformat($fileinfo) { $format = ''; $args = array(); - if (!empty($fileinfo['file_format'])) { - $format .= '@file_format '; - $args['@file_format'] = check_plain(strtoupper($fileinfo['file_format'])); + if (!empty($fileinfo['format'])) { + $format .= '@format '; + $args['@format'] = check_plain(strtoupper($fileinfo['format'])); } if (!empty($fileinfo['channel_mode'])) { $format .= '@channel_mode '; Index: audio_image.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/audio/audio_image.inc,v retrieving revision 1.9 diff -u -p -r1.9 audio_image.inc --- audio_image.inc 26 May 2008 17:30:40 -0000 1.9 +++ audio_image.inc 1 Oct 2008 23:46:40 -0000 @@ -78,42 +78,110 @@ function audio_image_type_dirty_array($i } /** - * Creates an audio image array from a filepath and pic type. + * Creates a temporary audio image from a variable. * * The image is cropped to a square and then resized to the image size setting. * - * @param $filepath - * Full path to the image file. + * @param $basename + * Name of the audio file this image accompanies. + * @param $data + * The raw image data. + * @param $mimetype + * The MIME type of the image. * @param $pictype * Integer pictype indexes from audio_image_type_clean_array() or * audio_image_type_dirty_array(). * @return - * An array with image info. + * A file object with image info or FALSE on error. */ -function audio_image_from_file($filepath, $pictype) { - $size = variable_get('audio_image_size', 170); +function audio_image_save_data($basename, $data, $mimetype, $pictype) { + global $user; + + // Gotta have a name to save to. + $filepath = _audio_image_filename($basename, $mimetype, $pictype, TRUE); + if (!$filepath) { + return FALSE; + } + + // Save the data. + $filepath = file_save_data($data, $filepath, FILE_EXISTS_RENAME); + if (!$filepath) { + return FALSE; + } - if ($image = image_get_info($filepath)) { - image_scale_and_crop($filepath, $filepath, $size, $size); + // Make sure it's a valid image. + $image = image_get_info($filepath); + if (!$image) { + file_delete($filepath); + return FALSE; + } + + // Resize the image + $size = variable_get('audio_image_size', 170); + if (image_scale_and_crop($filepath, $filepath, $size, $size)) { // Changing the image dimensions will affect the file size. Clear out // PHP's cached value so we can find the new size. clearstatcache(); - $image = image_get_info($filepath); - return array( - 'pictype' => $pictype, - 'filepath' => $filepath, - 'filemime' => $image['mime_type'], - 'filesize' => $image['file_size'], - 'extension' => $image['extension'], - 'width' => $image['width'], - 'height' => $image['height'], - ); } - return FALSE; + + // Store the file in the database so it can be removed by cron if it's not + // used. + $file = new stdClass(); + $file->filepath = $filepath; + $file->filename = basename($file->filepath); + $file->filemime = $mimetype; + $file->filesize = $image['file_size']; + $file->uid = $user->uid; + $file->status = FILE_STATUS_TEMPORARY; + $file->timestamp = time(); + + drupal_write_record('files', $file); + + $file->pictype = $pictype; + $file->height = $image['height']; + $file->width = $image['width']; + + return $file; } /** + * If the file is an image it will be resized to meet the audio image size + * guidelines. + * + * @param $file + * A Drupal file object. This function may resize the file affecting its size. + * @return + * An array. If the file is an image and did not meet the requirements, it + * will contain an error message. + */ +function audio_image_validate_size($file) { + $errors = array(); + + // Check first that the file is an image. + if ($info = image_get_info($file->filepath)) { + $size = variable_get('audio_image_size', 170); + if ($info['width'] > $size || $info['height'] > $size) { + // Try to resize the image to fit the dimensions. + if (image_get_toolkit() && image_scale_and_crop($file->filepath, $file->filepath, $size, $size)) { + drupal_set_message(t('The image was resized to fit within the maximum allowed dimensions of %height x %width pixels.', array('%height' => $size, '%width' => $size))); + + // Clear the cached filesize and refresh the image information. + clearstatcache(); + $info = image_get_info($file->filepath); + $file->filesize = $info['file_size']; + } + else { + $errors[] = t('The image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => $maximum_dimensions)); + } + } + } + + return $errors; +} + + +/** * Creates the image's filename in the form directory/prefix_imagetype.ext * * @param $prefix @@ -122,13 +190,13 @@ function audio_image_from_file($filepath * The image's mime type. jpeg, png and gif are the only formats allowed. * @param $pictype * Integer specifying the picture type. - * @param $in_tempdir + * @param $in_tempdir * Boolean indicating if the file be in the temp directory. - * @return + * @return * Full filepath or null in case of an error. */ function _audio_image_filename($prefix, $mimetype, $pictype = 0x03, $in_tempdir = FALSE) { - $directory = audio_get_directory() . (($in_tempdir) ? '/temp' : '/images'); + $directory = $in_tempdir ? file_directory_temp() : audio_get_directory() . '/images'; file_check_directory($directory, TRUE); //get the clean image type Index: getid3/audio_getid3.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/audio/getid3/audio_getid3.module,v retrieving revision 1.8 diff -u -p -r1.8 audio_getid3.module --- getid3/audio_getid3.module 30 Sep 2008 18:43:15 -0000 1.8 +++ getid3/audio_getid3.module 1 Oct 2008 23:46:40 -0000 @@ -21,12 +21,12 @@ function audio_getid3_nodeapi(&$node, $o function audio_getid3_audio($op, &$node) { switch ($op) { case 'upload': - if ($info = audio_read_id3tags($node->audio_file['file_path'], TRUE)) { + if ($info = audio_read_id3tags($node->audio['file']->filepath, TRUE)) { $node->audio_tags = $info['tags']; $node->audio_images = $info['images']; // use array_merge so that the play count and downloadable settings aren't // overwritten. - $node->audio_file = array_merge($node->audio_file, $info['fileinfo']); + $node->audio = array_merge($node->audio, $info['fileinfo']); } break; } @@ -37,54 +37,54 @@ function audio_getid3_audio($op, &$node) */ function audio_getid3_form_alter(&$form, &$form_state, $form_id) { // We only alter audio node edit forms with a file attached. - if ($form_id == 'audio_node_form' && !empty($form['#node']->audio_file['file_path'])) { + if ($form_id == 'audio_node_form' && !empty($form['#node']->audio['file']->filepath)) { $form['#submit'][] = 'audio_getid3_node_submit'; - $form['audio_file']['#description'] = t('This file information was loaded from the file by the getID3 library.'); + $form['audio']['#description'] = t('This file information was loaded from the file by the getID3 library.'); // Refresh the meta data everytime they display the edit form. - $info = audio_read_id3tags($form['#node']->audio_file['file_path'], FALSE); + $info = audio_read_id3tags($form['#node']->audio['file']->filepath, FALSE); // Overwrite the default audio module fields with a hidden value so that // so there's something POSTed back for the preview. - $fields = array('file_format', 'file_size', 'playtime', 'sample_rate', 'channel_mode', 'bitrate', 'bitrate_mode'); + $fields = array('format', 'file_size', 'playtime', 'sample_rate', 'channel_mode', 'bitrate', 'bitrate_mode'); foreach ($fields as $key) { - $form['audio_file'][$key] = array( + $form['audio'][$key] = array( '#type' => 'hidden', '#default_value' => isset($info['fileinfo'][$key]) ? $info['fileinfo'][$key] : '', ); } - $form['audio_file']['display_file_format'] = array( + $form['audio']['display_format'] = array( '#type' => 'item', '#title' => t('Format'), - '#value' => $info['fileinfo']['file_format'], + '#value' => $info['fileinfo']['format'], ); - $form['audio_file']['display_file_size'] = array( + $form['audio']['display_file_size'] = array( '#type' => 'item', '#title' => t('File Size'), '#value' => t('@filesize bytes', array('@filesize' => number_format($info['fileinfo']['file_size']))), ); - $form['audio_file']['display_playtime'] = array( + $form['audio']['display_playtime'] = array( '#type' => 'item', '#title' => t('Length'), '#value' => $info['fileinfo']['playtime'], ); - $form['audio_file']['display_sample_rate'] = array( + $form['audio']['display_sample_rate'] = array( '#type' => 'item', '#title' => t('Sample rate'), '#value' => t('@samplerate Hz', array('@samplerate' => number_format($info['fileinfo']['sample_rate']))), ); - $form['audio_file']['display_channel_mode'] = array( + $form['audio']['display_channel_mode'] = array( '#type' => 'item', '#title' => t('Channel mode'), '#value' => ucfirst($info['fileinfo']['channel_mode']), ); - $form['audio_file']['display_bitrate'] = array( + $form['audio']['display_bitrate'] = array( '#type' => 'item', '#title' => t('Bitrate'), '#value' => t('@bitrate bytes/second', array('@bitrate' => number_format($info['fileinfo']['bitrate']))), ); - $form['audio_file']['display_bitrate_mode'] = array( + $form['audio']['display_bitrate_mode'] = array( '#type' => 'item', '#title' => t('Bitrate mode'), '#value' => strtoupper($info['fileinfo']['bitrate_mode']), @@ -94,7 +94,7 @@ function audio_getid3_form_alter(&$form, // 11, 22, or 44 kHz). Display a warning if it is not. switch ($info['fileinfo']['sample_rate']) { case '44100': case '22050': case '11025': - if ($info['fileinfo']['file_format'] == 'mp3') { + if ($info['fileinfo']['format'] == 'mp3') { break; } default: @@ -154,9 +154,9 @@ function audio_read_id3tags($filepath, $ 'tags' => array(), 'images' => array(), 'fileinfo' => array( - 'file_format' => $info['fileformat'], + 'format' => $info['fileformat'], 'file_size' => $info['filesize'], - 'file_mime' => $info['mime_type'], + 'filemime' => $info['mime_type'], 'playtime' => $info['playtime_string'], 'bitrate' => $info['audio']['bitrate'], 'bitrate_mode' => $info['audio']['bitrate_mode'], @@ -181,7 +181,8 @@ function audio_read_id3tags($filepath, $ if (isset($info['id3v2'][$type])) { foreach ((array)$info['id3v2'][$type] as $image) { // Save it to a temp file - $ret['images'][] = audio_image_save_data(basename($filepath), $image['data'], $image['mime'], $image['picturetypeid']); + $file = audio_image_save_data(basename($filepath), $image['data'], $image['image_mime'], $image['picturetypeid']); + $ret['images'][$file->pictype .'-'. $file->fid] = $file; } } } @@ -288,29 +289,37 @@ function audio_write_id3tags($filepath, function _audio_getid3_save_to_file(&$node) { $settings = audio_get_tag_settings(); - // prepare a list of tags to be written to the file + if (preg_match('/\.ogg$/i', $node->audio['file']->filepath)) { + $tagformats = array('vorbiscomment'); + } + else { + $tagformats = array('id3v1', 'id3v2.3'); + } + + // Determine which tags should be written to the file. $tags = array(); - foreach ($node->audio_tags as $tag => $value) { - if (isset($settings[$tag]) && $settings[$tag]['writetofile']) { - $tags[$tag] = $value; + if (isset($node->audio_tags)) { + foreach ($node->audio_tags as $tag => $value) { + if (isset($settings[$tag]) && $settings[$tag]['writetofile']) { + $tags[$tag] = $value; + } } } - // if there are any tags left, update the tags in the file - if ($tags) { - if (preg_match('/\.ogg$/i', $node->audio_file['file_path'])) { - $tagformats = array('vorbiscomment'); - } - else { - $tagformats = array('id3v1', 'id3v2.3'); - } - audio_write_id3tags($node->audio_file['file_path'], $tags, $node->audio_images, $tagformats); + $images = array(); + if (isset($node->audio_images)) { + $images = $node->audio_images; + } + + // If there are any writable tags or image, update the file. + if ($tags || $images) { + audio_write_id3tags($node->audio['file']->filepath, $tags, $images, $tagformats); } // then reload them so that the node is in sync with the file/database... - $info = audio_read_id3tags($node->audio_file['file_path']); + $info = audio_read_id3tags($node->audio['file']->filepath); // ...merge so that any non-written tags will be preserved... $node->audio_tags = array_merge($node->audio_tags, $info['tags']); // ...merge so that the playcount and downloadable options aren't overwritten. - $node->audio_file = array_merge($node->audio_file, $info['fileinfo']); + $node->audio = array_merge($node->audio, $info['fileinfo']); } Index: images/audio_images.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/audio/images/audio_images.install,v retrieving revision 1.1 diff -u -p -r1.1 audio_images.install --- images/audio_images.install 26 May 2008 17:26:13 -0000 1.1 +++ images/audio_images.install 1 Oct 2008 23:46:41 -0000 @@ -19,17 +19,18 @@ function audio_images_schema() { $schema['audio_image'] = array( 'description' => t('Associates an image (such as album artwork) with an audio file.'), 'fields' => array( - 'pid' => array( - 'type' => 'serial', - 'size' => 'medium', + 'fid' => array( + 'type' => 'int', + 'unsigned' => TRUE, 'not null' => TRUE, + 'description' => t('Primary Key: The {files}.fid.'), ), - 'nid' => array( + 'vid' => array( 'type' => 'int', 'size' => 'medium', 'not null' => TRUE, ), - 'vid' => array( + 'nid' => array( 'type' => 'int', 'size' => 'medium', 'not null' => TRUE, @@ -52,28 +53,10 @@ function audio_images_schema() { 'not null' => TRUE, 'default' => 0, ), - 'filemime' => array( - 'type' => 'varchar', - 'length' => 20, - 'not null' => TRUE, - 'default' => '', - ), - 'filepath' => array( - 'type' => 'varchar', - 'length' => 255, - 'not null' => TRUE, - 'default' => '', - ), - 'filesize' => array( - 'type' => 'int', - 'size' => 'medium', - 'not null' => TRUE, - 'default' => 0, - ), ), - 'primary key' => array('pid'), + 'primary key' => array('vid', 'pictype', 'fid'), 'indexes' => array( - 'audio_image_vid_pictype' => array('vid', 'pictype'), + 'audio_image_fid' => array('fid'), ), ); return $schema; @@ -118,3 +101,37 @@ function audio_images_update_2() { ); return $ret; } + +/** + * Move the majority of our data into the {files} table. + */ +function audio_images_update_6000() { + $ret = array(); + $fid_field = array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => t('Primary Key: The {files}.fid.'), + ); + db_add_field($ret, 'audio_image', 'fid', $fid_field); + db_add_index($ret, 'audio_image', 'audio_image_fid', array('fid')); + + // Load all the distinct filepaths. + $result = db_query("SELECT DISTINCT filepath FROM {audio_image} WHERE fid IS NULL OR fid = 0"); + while ($file = db_fetch_object($result)) { + // Then move the data into the files table. + db_query("INSERT INTO {files} (uid, filename, filepath, filemime, filesize, status, timestamp) SELECT n.uid, '%s', ai.filepath, ai.filemime, ai.filesize, %d, n.created AS timestamp FROM {node} n INNER JOIN {audio_image} ai ON n.vid = ai.vid WHERE ai.filepath = '%s' LIMIT 1", array(basename($file->filepath), FILE_STATUS_PERMANENT, $file->filepath)); + db_query("UPDATE {audio_image} SET fid = %d WHERE filepath = '%s'", db_last_insert_id('files', 'fid'), $file->filepath); + } + + // Remove all the old fields and setup the new indexes. + db_drop_field($ret, 'audio_image', 'pid'); + db_drop_field($ret, 'audio_image', 'filesize'); + db_drop_field($ret, 'audio_image', 'filepath'); + db_drop_field($ret, 'audio_image', 'filemime'); + db_drop_index($ret, 'audio_image', 'audio_image_vid_pictype'); + db_drop_primary_key($ret, 'audio_image'); + db_add_primary_key($ret, 'audio_image', array('vid', 'pictype', 'fid')); + + return $ret; +} Index: images/audio_images.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/audio/images/audio_images.module,v retrieving revision 1.2 diff -u -p -r1.2 audio_images.module --- images/audio_images.module 10 Jun 2008 05:23:28 -0000 1.2 +++ images/audio_images.module 1 Oct 2008 23:46:41 -0000 @@ -65,11 +65,9 @@ function audio_images_file_download($fil * Here we add our image fields to the audio node form. */ function audio_images_form_alter(&$form, &$form_state, $form_id) { - // We only alter audio node edit forms. - if ($form_id == 'audio_node_form') { - $form['#submit'][] = 'audio_images_node_submit'; - - $node = $form['#node']; + // We only alter audio node edit forms with a file attached. + if ($form_id == 'audio_node_form' && !empty($form['#node']->audio['file']->filepath)) { + $form['#validate'][] = 'audio_images_node_form_validate'; $form['audio_images'] = array( '#type' => 'fieldset', '#title' => t('Audio Images'), @@ -79,24 +77,27 @@ function audio_images_form_alter(&$form, '#tree' => TRUE, ); - if (isset($node->audio_images)) { + if (isset($form['#node']->audio_images)) { $form['audio_images']['#theme'] = 'audio_images_form'; - foreach ($node->audio_images as $pid => $image) { - $form['audio_images'][$pid]['pid'] = array('#type' => 'value', '#value' => $pid); - $form['audio_images'][$pid]['pictype'] = array('#type' => 'value', '#value' => $image['pictype']); - $form['audio_images'][$pid]['filepath'] = array('#type' => 'value', '#value' => $image['filepath']); - $form['audio_images'][$pid]['filemime'] = array('#type' => 'value', '#value' => $image['filemime']); - $form['audio_images'][$pid]['filesize'] = array('#type' => 'value', '#value' => $image['filesize']); - $form['audio_images'][$pid]['height'] = array('#type' => 'value', '#value' => $image['height']); - $form['audio_images'][$pid]['width'] = array('#type' => 'value', '#value' => $image['width']); - $form['audio_images'][$pid]['delete'] = array('#type' => 'checkbox', '#default_value' => isset($image['delete']) ? $image['delete'] : FALSE); + foreach ($form['#node']->audio_images as $key => $image) { + if ($key == 'delete' || $key == 'new') continue; + + $image = (array) $image; + $form['audio_images'][$key] = array( + '#type' => 'value', + '#value' => $image, + ); + $form['audio_images']['delete'][$key] = array( + '#type' => 'checkbox', + '#default_value' => isset($image['delete']) ? $image['delete'] : FALSE, + ); } } $form['audio_images']['new']['pictype'] = array( '#type' => 'select', '#title' => t('New image type'), - '#value' => variable_get('audio_image_default_type', 0x03), + '#default_value' => variable_get('audio_image_default_type', 0x03), '#options' => audio_image_type_dirty_array(), ); $form['audio_images']['new']['audio_image_upload'] = array( @@ -113,45 +114,48 @@ function audio_images_form_alter(&$form, */ function theme_audio_images_form(&$form) { $pictypes = audio_image_type_dirty_array(); + $header = array(t('Type'), t('MIME Type'), t('Dimensions'), t('Size'), t('Delete')); $rows = array(); - foreach (element_children($form) as $pid) { - if ($pid != 'new') { + foreach (element_children($form) as $key) { + if ($key != 'new' && $key != 'delete') { + $image = (array) $form[$key]['#value']; $rows[] = array( - l($pictypes[$form[$pid]['pictype']['#value']], $form[$pid]['filepath']['#value']), - $form[$pid]['filemime']['#value'], - $form[$pid]['height']['#value'] .'x'. $form[$pid]['width']['#value'], - $form[$pid]['filesize']['#value'], - drupal_render($form[$pid]['delete']), + l($pictypes[$image['pictype']], $image['filepath']), + $image['filemime'], + format_size($image['filesize']), + $image['height'] .'x'. $image['width'], + drupal_render($form['delete'][$key]), ); } } - $header = array(t('Type'), t('MIME Type'), t('Dimensions'), t('Size'), t('Delete')); return theme('table', $header, $rows) . drupal_render($form); } /** - * Node submit handler + * Node validate handler */ -function audio_images_node_submit($form, &$form_state) { - $node = (object) $form_state['values']; - +function audio_images_node_form_validate($form, &$form_state) { // Check for an uploaded image. - $validators = array('file_validate_is_image' => array()); + $validators = array( + 'file_validate_is_image' => array(), + 'audio_image_validate_size' => array(), + ); if ($file = file_save_upload('audio_image_upload', $validators)) { - $pictype = (integer) $form_state['values']['audio_images']['new']['pictype']; - if ($image = audio_image_from_file($file->filepath, $pictype)) { - $pid = 'new_'. count($form_state['values']['audio_images']); - $image['pid'] = $pid; - $form_state['values']['audio_images'][$pid] = $image; - } + $image = image_get_info($file->filepath); + $file->height = $image['height']; + $file->width = $image['width']; + $file->pictype = (int) $form_state['values']['audio_images']['new']['pictype']; + + $form_state['values']['audio_images'][$file->pictype .'-'. $file->fid] = $file; } - else { - foreach ($form_state['values']['audio_images'] as $key => $image) { - // If no image has been uploaded clear out the "new" image. - if (preg_match('/^new/', $key) && empty($image['filepath'])) { - unset($form_state['values']['audio_images'][$key]); - } + unset($form_state['values']['audio_images']['new']); + + // Move the delete checkbox values to the image + if (isset($form_state['values']['audio_images']['delete'])) { + foreach ($form_state['values']['audio_images']['delete'] as $key => $value) { + $form_state['values']['audio_images'][$key]['delete'] = $value; } + unset($form_state['values']['audio_images']['delete']); } } @@ -165,9 +169,6 @@ function audio_images_nodeapi(&$node, $o case 'insert': return audio_images_nodeapi_insert($node); case 'update': - if ($node->revision) { - return audio_images_nodeapi_insert_revision($node); - } return audio_images_nodeapi_update($node); case 'delete': return audio_images_nodeapi_delete($node); @@ -178,133 +179,94 @@ function audio_images_nodeapi(&$node, $o function audio_images_nodeapi_load($node) { $ret['audio_images'] = array(); - $result = db_query("SELECT pid, pictype, filemime, width, height, filepath, filesize FROM {audio_image} WHERE vid=%d", $node->vid); - while ($img = db_fetch_array($result)) { - $ret['audio_images'][$img['pid']] = $img; + $result = db_query("SELECT f.fid, f.filemime, f.filepath, f.filesize, ai.nid, ai.vid, ai.pictype, ai.width, ai.height FROM {files} f INNER JOIN {audio_image} ai ON f.fid = ai.fid WHERE ai.vid = %d", $node->vid); + while ($img = db_fetch_object($result)) { + $ret['audio_images'][$img->pictype .'-'. $img->fid] = $img; } return $ret; } function audio_images_nodeapi_insert(&$node) { // Add new images. - foreach ((array)$node->audio_images as $pid => $image) { - if (_audio_images_istemp($image['pid'])) { - _audio_images_save_new($node, $image); - } - } -} - -function audio_images_nodeapi_insert_revision(&$node) { - foreach ((array)$node->audio_images as $pid => $image) { - // Deletions. - if ($image['delete']) { - _audio_images_delete($pid, $image['filepath']); - } - // Additions. - else if (_audio_images_istemp($image['pid'])) { - _audio_images_save_new($node, $image); - } - // Make copies of unchanged images. - else { - _audio_images_save_copy($node, $image); + foreach ((array) $node->audio_images as $key => $image) { + $image = (object) $image; + $image->nid = $node->nid; + $image->vid = $node->vid; + + if ($image->status & FILE_STATUS_TEMPORARY == FILE_STATUS_TEMPORARY) { + $newpath = _audio_image_filename($node->vid, $image->filemime, $image->pictype, FALSE); + if (file_move($image, $newpath)) { + $image->status = FILE_STATUS_PERMANENT; + drupal_write_record('files', $file, array('fid')); + } } + drupal_write_record('audio_image', $image); + $node->audio_images[$key] = $image; } } function audio_images_nodeapi_update(&$node) { - foreach ((array)$node->audio_images as $pid => $image) { - // Deletions. - if ($image['delete']) { - _audio_images_delete($pid, $image['filepath']); + foreach ((array) $node->audio_images as $key => $image) { + $image = (object) $image; + $image->nid = $node->nid; + $image->vid = $node->vid; + + if (!empty($image->delete)) { + // Delete the image. + _audio_images_delete($image); + db_query('DELETE FROM {audio_image} WHERE vid = %d AND pictype = %d AND fid = %d', $node->vid, $image->pictype, $image->fid); + unset($node->audio_images[$key]); + } + elseif (($image->status & FILE_STATUS_TEMPORARY) == FILE_STATUS_TEMPORARY) { + // New image. + $newpath = _audio_image_filename($node->vid, $image->filemime, $image->pictype, FALSE); + if (file_move($image, $newpath)) { + $image->status |= FILE_STATUS_PERMANENT; + drupal_write_record('files', $image, array('fid')); + } + drupal_write_record('audio_image', $image); + $node->audio_images[$key] = $image; } - // Additions. - else if (_audio_images_istemp($image['pid'])) { - _audio_images_save_new($node, $image); + elseif ($node->revision) { + // Make copies of unchanged images when creating a new revision. + drupal_write_record('audio_image', $image); + $node->audio_images[$key] = $image; } } } function audio_images_nodeapi_delete(&$node) { - // Delete any associated previews. - _audio_images_delete_previews($node); - // Delete the image files and remove them from the database. - $result = db_query('SELECT filepath FROM {audio_image} WHERE nid = %d', $node->nid); + $result = db_query('SELECT ai.fid, f.filepath FROM {audio_image} ai INNER JOIN {files} f ON ai.fid = f.fid WHERE nid = %d', $node->nid); while ($file = db_fetch_object($result)) { - file_delete($file->filepath); + _audio_images_delete($file); } db_query('DELETE FROM {audio_image} WHERE nid = %d', $node->nid); } function audio_images_nodeapi_delete_revision(&$node) { - // Delete any associated previews. - _audio_images_delete_previews($node); - // Delete the image files and remove them from the database. - $result = db_query('SELECT filepath FROM {audio_image} WHERE vid = %d', $node->vid); + $result = db_query('SELECT ai.fid, f.filepath FROM {audio_image} ai INNER JOIN {files} f ON ai.fid = f.fid WHERE vid = %d', $node->vid); while ($file = db_fetch_object($result)) { - file_delete($file->filepath); + _audio_images_delete($file); } db_query('DELETE FROM {audio_image} WHERE vid = %d', $node->vid); } /** - * Is an image a temporary preview? + * If a file isn't used delete it and remove the {files} table record. The + * caller needs to remove record(s) from the {audio_images} table. * - * @param $pid - * Mixed, string or integer. - * @return - * Boolean indicating if the image is a temporary preview. - */ -function _audio_images_istemp($pid) { - return (strpos($pid, 'new') !== FALSE); -} - -/** - * Adds an image to the audio_image table and moves it to the audio/images - * directory. + * @param $file File object */ -function _audio_images_save_new(&$node, $image) { - $temppath = $image['filepath']; - _audio_images_save_copy($node, $image); - file_delete($temppath); -} - -/** - * Save an image to the audio_image table and copies it to the audio/images - * directory. - * - * The caller needs to delete original image file if it was a temporary. - */ -function _audio_images_save_copy(&$node, $image) { - $newpath = _audio_image_filename($node->vid, $image['filemime'], $image['pictype'], FALSE); - if (file_copy($image['filepath'], $newpath, FILE_EXISTS_REPLACE)) { - $image['nid'] = $node->nid; - $image['vid'] = $node->vid; - $image['filepath'] = $newpath; - $image['filesize'] = filesize($newpath); - drupal_write_record('audio_image', $image); - $node->audio_images[$image['pid']] = $image; - } -} - -function _audio_images_delete($pid, $filepath) { - file_delete($filepath); - // Delete from the database if it's not a preview. - if (!_audio_images_istemp($pid)) { - db_query("DELETE FROM {audio_image} WHERE pid = %d", $pid); - } -} - -/** - * Delete any preview images associated with the node. - */ -function _audio_images_delete_previews(&$node) { - foreach ((array)$node->audio_images as $pid => $image) { - if (_audio_images_istemp($pid)) { - file_delete($image['filepath']); - unset($node->audio_images[$pid]); - } +function _audio_images_delete($file) { + // Check if the file will be used after this revision is deleted + $count = db_result(db_query('SELECT COUNT(fid) FROM {audio_image} WHERE fid = %d', $file->fid)); + + // If the file won't be used, delete it. + if ($count < 2) { + db_query('DELETE FROM {files} WHERE fid = %d', $file->fid); + file_delete($file->filepath); } } @@ -317,9 +279,10 @@ function audio_images_get($audio_images, if (is_null($pictype)) { $pictype = variable_get('audio_default_image_type', 0x03); } - if (is_array($audio_images) && count($audio_images)) { + if (!empty($audio_images)) { foreach ($audio_images as $image) { - if ($image['pictype'] == $pictype) { + $image = (object) $image; + if ($image->pictype == $pictype) { return $image; } } @@ -345,11 +308,10 @@ function theme_audio_images($audio_image * Create an element for an audio image. */ function theme_audio_image($image) { - $url = file_create_url($image['filepath']); - $alt = audio_image_type_dirty_array($image['pictype']); + $image = (object) $image; - list($width, $height) = @getimagesize($image['filepath']); + list($width, $height) = @getimagesize($image->filepath); $attributes = array('width' => $width, 'height' => $height); - return theme('image', $url, $alt, '', $attributes, FALSE); + return theme('image', file_create_url($image->filepath), audio_image_type_dirty_array($image->pictype), '', $attributes, FALSE); }