Download & Extend

Multiple upload, duplicate entry on adding a video to a node

Project:FlashVideo
Version:6.x-1.x-dev
Component:Code
Category:bug report
Priority:normal
Assigned:attheshow
Status:closed (fixed)

Issue Summary

I have a node with video already converted.

When I add a video to this node, the video_index starts from 0 instead to start from n° video +1

hook flashvideo_nodeapi call the following code on insert or update operations

1 function _flashvideo_update_files($node) {

2  // Set the video index to zero.
3  $video_index = 0;

4  if (module_exists('filefield') && flashvideo_variable_get(NULL, 'flashvideo_filefield', 0)) {
5    // Names of the different video fields? Let's find out.
6    $cck_original_video_field = flashvideo_variable_get($node->type, 'cck_original_video_field', '');
7    $cck_finished_video_field = flashvideo_variable_get($node->type, 'cck_finished_video_field', '');
8    $cck_finished_thumbnail_field = flashvideo_variable_get($node->type, 'cck_finished_thumbnail_field', '');
9    // Make sure that they uploaded some files to the "original" field.
10    if (!empty($node->$cck_original_video_field)) {
11      // Iterate through all of the files.
12      foreach ($node->$cck_original_video_field as $file) {
13        // Convert the file to a file object.
14        $file = (object)$file;
15        // If they wanted to remove the file from the node.
16        if (!empty($file->remove)) {
17        ..........
18        }
19        else {
20          // Only continue if it is a video
21          if (_flashvideo_get_mime_type($file->filepath) !== FALSE) {
22            // Is this file already part of the flashvideo table?
23            $found = db_result(db_query("SELECT count(*) FROM {flashvideo} WHERE fid=%d", $file->fid));
24            // Only add if the file is a video and is not already in our flashvideo table.
25            if (!$found) {
26              // Get the size of the video.  Width and Height.
27              $size = flashvideo_get_size($node, $file);
28              // Now insert our flashvideo into our table.
29              db_query("INSERT INTO {flashvideo} (fid, nid, oid, status, video_index, width, height, flags) VALUES (%d, %d, %d, %d, %d, %d, %d, %d)", $file->fid, $node->nid, $file->fid, FLASHVIDEO_STATUS_OK, $video_index, $size['width'], $size['height'], 0);
30               // If we don't want to wait for cron, call it immediately.
31              if (flashvideo_variable_get($node->type, 'convert', 0)) {
32                flashvideo_cron();
33              }
34            }
35            // Increment the video index.
36            $video_index++;
37          }
38        }
39      }

on line 29 a new record is inserted in flashvideo table, but with video_index=0;

My fix is this :
After line 27 I add this code:

// Get the new index of the video.
$video_index = (!empty($node->$cck_finished_video_field) && is_array($node->$cck_finished_video_field)) ?
                        sizeof($node->$cck_finished_video_field)
                        :
                        $video_index;

Comments

#1

Status:active» postponed (maintainer needs more info)

I'm a little unclear on what you're trying to fix here. I just tested uploading multiple videos to a single node in different passes and didn't see any errors.

The primary key on this table should be "fid". Having duplicate entries in the "video_index" column is intentional and fine. This allows for all three three files (original, finished, and thumbnail) to be associated together.

#2

I'm sorry, this issue is bad explained and introduce a new bug for me.

I try to explain again the situation.

I create a node with one video.
I save it and flashvideo convert it.

This hook is executed

function flashvideo_nodeapi(&$node, $op, $teaser) {

  // Only if the node type is enabled.
  if (flashvideo_variable_get($node->type, 'enable', 0)) {
    switch ($op) {
      case 'insert':
      case 'update':
        _flashvideo_update_files($node);

the function _flashvideo_update_files (reported at the top of this issue) is executed.

On line 3 $video_index=0;
On line 29 a record in flashvideo table is inserted, with video_index value=0;
On line 32 flashvideo_cron() is called.
If everything is ok flashvideo_cron calls flashvideo_convert to create the thumbnail (and later to create the converted video) that in turn calls flashvideo_perform_postop

1 function _flashvideo_perform_postop($oldfile, $newfile, $node_type, $create_thumbnail = FALSE) {
2
3   $timestamp = time();
4
5   if ((_flashvideo_get_filetype($oldfile->filepath) == 'flv') && !$create_thumbnail) {
6     db_query("UPDATE {files} SET filepath='%s', filename='%s', filesize=%d WHERE fid=%d", $newfile->filepath, $newfile->filename, $newfile->filesize, $newfile->fid);
7
8     // Insert this video into the flashvideo table if it is not already in there.
9     if (!db_result(db_query("SELECT COUNT(*) FROM {flashvideo} WHERE oid=%d AND fid=%d AND nid=%d", $newfile->fid, $newfile->fid, $newfile->nid))) {
10       // Insert this video into the flashvideo table.
11       db_query("INSERT INTO {flashvideo} (fid, nid, oid, status, video_index, width, height, flags) VALUES (%d, %d, %d, %d, %d, %d, %d, 0)", $newfile->fid, $newfile->nid, $oldfile->fid, FLASHVIDEO_STATUS_CONVERTED, $params->video_index, $params->width, $params->height);
12       db_query("INSERT INTO {ffmpeg_data} (fid, created, input_file, output_file, status) VALUES (%d, %d, '%s', '%s', %d)", $oldfile->fid, $timestamp, $oldfile->filepath, $newfile->filepath, 1);
13     }
14   }
15   else {
16     // Create a temporary file for the new file.
17     db_query("INSERT INTO {files} (uid, filename, filepath, filemime, filesize, status, timestamp) VALUES (%d, '%s', '%s', '%s', %d, %d, %d)", $newfile->uid, $newfile->filename, $newfile->filepath, $newfile->filemime, $newfile->filesize, FILE_STATUS_TEMPORARY, time());
18
19     // Get the new File ID
20     $newfile->fid = db_last_insert_id('files', 'fid');
21
22     // Look to make sure that the File ID doesn't already exists in the files table.
23     $found = db_result(db_query("SELECT COUNT(*) FROM {files} WHERE filepath='%s' AND status=%d", $newfile->filepath, FILE_STATUS_PERMANENT));
24
25     // If the file isn't already in the files table...
26     if ($found == 0) {
27       // Grab the width, height, and video_index from the original video to copy over to the new video, then insert the new video in the flashvideo table.
28       $params = db_fetch_object(db_query("SELECT video_index, width, height FROM {flashvideo} WHERE fid = %d", $oldfile->fid));
29
30       // Create the appropriate database entry for the newly converted video file.
31       if (module_exists('filefield') && flashvideo_variable_get(NULL, 'flashvideo_filefield', 0)) { // Using FileField
32         // Names of the different video fields? Let's find out.
33         $cck_original_video_field = flashvideo_variable_get($node_type, 'cck_original_video_field', '');
34         $cck_finished_video_field = flashvideo_variable_get($node_type, 'cck_finished_video_field', '');
35         $cck_finished_thumbnail_field = flashvideo_variable_get($node_type, 'cck_finished_thumbnail_field', '');
36         $cck_table = 'content_type_'. $node_type;
37         if ($create_thumbnail) { // This is for the finished thumbnail.
38           // For single-upload file fields
39           if (db_column_exists($cck_table, $cck_original_video_field .'_fid')) {
40             db_query("UPDATE {". $cck_table ."} SET ". $cck_finished_thumbnail_field ."_fid = %d, ". $cck_finished_thumbnail_field ."_list = 0 WHERE nid = %d", $newfile->fid, $newfile->nid);
41           }
42           else { 
43             // Get rid of the initial NULL entry.
44             db_query("DELETE FROM {content_". $cck_finished_thumbnail_field ."} WHERE nid = %d AND ". $cck_finished_thumbnail_field ."_fid IS NULL", $newfile->nid);
45             // For multi-upload file fields
46             db_query("INSERT INTO {content_". $cck_finished_thumbnail_field ."} (vid, nid, delta, ". $cck_finished_thumbnail_field ."_fid, ". $cck_finished_thumbnail_field ."_list) VALUES (%d, %d, %d, %d, 0)", $newfile->nid, $newfile->nid, $params->video_index, $newfile->fid);
47           }
48         }
49         else { // This is for the finished video.
50           // For single-upload file fields
51           if (db_column_exists($cck_table, $cck_original_video_field .'_fid')) {
52             db_query("UPDATE {". $cck_table ."} SET ". $cck_finished_video_field ."_fid = %d, ". $cck_finished_video_field ."_list = 0 WHERE nid = %d", $newfile->fid, $newfile->nid);
53           }
54           else { 
55             // Get rid of the initial NULL entry.
56             db_query("DELETE FROM {content_". $cck_finished_video_field ."} WHERE nid = %d AND ". $cck_finished_video_field ."_fid IS NULL", $newfile->nid);
57             // For multi-upload file fields
58             db_query("INSERT INTO {content_". $cck_finished_video_field ."} (vid, nid, delta, ". $cck_finished_video_field ."_fid, ". $cck_finished_video_field ."_list) VALUES (%d, %d, %d, %d, 0)", $newfile->nid, $newfile->nid, $params->video_index, $newfile->fid);
59           }
60         }
61

Thumbnail creation:
On line 17 of _flashvideo_perform_postop() functions a new record is inserted in {files} table
On line 28 we saves in $params some values from original video (video_index, width, height). Video index is 0 as we saved on line 29 of _flashvideo_update_files.
On line 46 a record entry in table {content_". $cck_finished_thumbnail_field ."} is created with these values.
vid = $newfile->nid (5), nid = $newfile->nid (5), delta = $params->video_index (0), field_."$mycckfield_name."_fid = 2, field_."$mycckfield_name."_data = "some value"

Video creation :
On line 17 of _flashvideo_perform_postop() functions a new record is inserted in {files} table
On line 28 we saves in $params some values from original video (video_index, width, height). Video index is 0 as we saved on line 29 of _flashvideo_update_files.
On line 58 a a record entry in table {content_". $cck_finished_video_field ."} is created with these values.
vid = $newfile->nid (5), nid = $newfile->nid (5), delta = $params->video_index (0), field_."$mycckfield_name."_fid = 2, field_."$mycckfield_name."_data = "some value"

I edit the node again.

I add a video.
I save it.

The hook flashvideo_nodeapi is executed again
_flashvideo_update_files is executed again
On line 3 $video_index=0;
On line 29 a record in flashvideo table is inserted, with video_index value=0;
On line 32 flashvideo_cron() is called.
If everything is ok flashvideo_cron calls flashvideo_convert to create the thumbnail (and later to create the converted video) that in turn calls flashvideo_perform_postop

On line 46 (and 58) we INSERT again in {content_". $cck_finished_thumbnail_field ."} and {content_". $cck_finished_video_field ."}
these values vid = $newfile->nid, nid = $newfile->nid, delta=$params->video_index
$newfile->nid is 5 because we are editing the same node as before.
$params->video_index is 0 as we inserted on line 29 of _flashvideo_update_files

Mysql returns a duplicate entry for primary key (vid, delta);

I hope this issue is more exhaustive and clear than before.

#3

Status:postponed (maintainer needs more info)» active

#4

Status:active» postponed (maintainer needs more info)

Since I haven't been able to duplicate the error that you mention, "Mysql returns a duplicate entry for primary key (vid, delta)", can you outline the steps that I would take to duplicate this error on my test system?

#5

Status:postponed (maintainer needs more info)» active

Ok, I think that I found the reason why you're not able to reproduce this bug.

Set flashvideo to convert video immediately and delete source video after conversion.

Create a node inserting a video. Save it.

video and thumbnail are created correctly.

Edit the node you created.

Add a video and save it.

The error appears

#6

Version:6.x-1.5-rc1» 6.x-1.x-dev
Status:active» needs work

After applying your video_index code above, that seems to have fixed that error, but I'm seeing another one related the the CCK tables and the "delta" field in those tables. Looks like the delta needs to be made to match up with an updated index value.

  * user warning: Duplicate entry '16-0' for key 1 query: INSERT INTO content_field_finished_thumb (vid, nid, delta, field_finished_thumb_fid, field_finished_thumb_list) VALUES (16, 16, 0, 73, 0) in /Users/mjarrell/Sites/drupal/sites/all/modules/drupal-contrib/flashvideo/flashvideo.module on line 734.
    * user warning: Duplicate entry '16-0' for key 1 query: INSERT INTO content_field_finished_video (vid, nid, delta, field_finished_video_fid, field_finished_video_list) VALUES (16, 16, 0, 74, 0) in /Users/mjarrell/Sites/drupal/sites/all/modules/drupal-contrib/flashvideo/flashvideo.module on line 745.

#7

Version:6.x-1.x-dev» 6.x-1.5-rc2
Status:needs work» needs review

This patch should works.

AttachmentSize
flashvideo.patch 811 bytes

#8

Version:6.x-1.5-rc2» 6.x-1.x-dev
Assigned to:Anonymous» attheshow
Status:needs review» fixed

That patch wasn't working consistently for me, so I ended up doing a db query in the flashvideo table to see which indexes had already had been used. Committed to dev version of the module.

#9

Status:fixed» closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

nobody click here