Tags removed, when remove_other_tags = false

Post Reply
JunkieVibes
User
Posts: 5
Joined: Fri May 16, 2014 5:04 pm
Are you a spambot?: no

Tags removed, when remove_other_tags = false

Post by JunkieVibes » Fri May 16, 2014 5:10 pm

This looks like a bug, but I'll post it here in case I am missing something obvious or it's a known issue.

The picture tags are removed on editing any other tags. The property remove_other_tags is false. I have tested using the latest code, 1.9.8-20140511. I have reduced it to the following very basic test script:

Code: Select all

$filename = "./test_files/test.mp3";

copy ("./test_files_original/test.mp3", $filename) || die ("Failed to copy file");

require_once('./getid3/getid3.php');

echo ("Calling analyzeFile, first time\n");

analyzeFile($filename);

$tagArray = array ("title" => array("amended title"));

require_once('./getid3/write.php');

$tagWriter = new getid3_writetags();

$tagWriter->filename = $filename;
$tagWriter->tagformats = array ('id3v2.4','id3v2.3');
$tagWriter->remove_other_tags = false;
$tagWriter->overwrite_tags = true;
$tagWriter->tag_encoding   = 'UTF-8'; 
$tagWriter->tag_data = $tagArray;

$tagWriter -> WriteTags();

if (count($tagWriter -> errors)){
    echo ("\$tagWriter -> errors\n");
    print_r($tagWriter -> errors);
}

if (count($tagWriter -> warnings)){
    echo ("\$tagWriter -> warnings\n");
    print_r($tagWriter -> warnings);
}

print ("Calling analyzeFile, second time\n");

analyzeFile($filename);

function analyzeFile ($filename){

    $getID3 = new getID3;
    
    $ThisFileInfo = $getID3->analyze($filename);

    getid3_lib::CopyTagsToComments($ThisFileInfo);

    if (isset($ThisFileInfo['comments']['picture'])){
        foreach ($ThisFileInfo['comments']['picture'] as $picture){
            foreach ($picture as $fieldName => $data){
                echo "$fieldName - (length) " . mb_strlen($data) . "\n";
            }
        }
    } else {
        echo ("No image found");
    }

}

James Heinrich
getID3() v1 developer
Posts: 1475
Joined: Fri May 04, 2001 4:00 pm
Are you a spambot?: no
Location: Northern Ontario, Canada
Contact:

Re: Tags removed, when remove_other_tags = false

Post by James Heinrich » Fri May 16, 2014 5:59 pm

See: $remove_other_tags.
public $remove_other_tags = false;
// if true will erase remove all existing tags and only write those passed in $tagformats; if false will ignore any tags not mentioned in $tagformats
Note that "remove other tags" means tag formats, not tag elements. As in, if you write an ID3v2 tag and say remove_other_tags=true, any other tag formats (e.g. ID3v1, APE, Lyrics3) will be stripped from the file. If false (default) then the other tag formats (if any) are left alone.

What you are looking for is $overwrite_tags which should be set to false to attempt to merge existing tag elements with your new passed data. It becomes very tricky with formats like ID3v2 where multiple values of the same type (artist, title, comment, picture, etc) are allowed, to know whether your newly passed data is an update to existing data or should be added as another set of data. For most predictable results it's recommended to read in the existing tag data, merge in whatever changes you want, and then write it back out with overwrite_tags=true.

JunkieVibes
User
Posts: 5
Joined: Fri May 16, 2014 5:04 pm
Are you a spambot?: no

Re: Tags removed, when remove_other_tags = false

Post by JunkieVibes » Sat May 17, 2014 7:16 pm

Note that "remove other tags" means tag formats, not tag elements.
That was the basic issue here, thanks.

However, I'd appreciate a bit more help. I am following your advice, to
read in the existing tag data, merge in whatever changes you want, and then write it back out with overwrite_tags=true
but am getting an error message and a failed write. The simplest test is to read in the existing tags and write them back, and that fails for me with:
[0] => ID3v2: Skipping "PICTURE" because cannot match it to a known ID3v2 frame type
[1] => ID3v2: Skipping "TRACK_NUMBER" because cannot match it to a known ID3v2 frame type
[2] => WriteID3v2() failed with message(s):<pre><ul><li>Only one COMM tag allowed with the same Language + Description (eng + )</li><li>Frame "COMM" is NOT allowed</li><li>$this->GenerateID3v2FrameData() failed for "COMM"</li><li>$this->GenerateID3v2Tag() failed</li></ul></pre>
Code is as follows:

Code: Select all

$filename = "./test_files/test.mp3";

copy ("./test_files_original/test.mp3", $filename) || die ("Failed to copy file");

require_once('./getid3/getid3.php');

require_once('./getid3/write.php');

$tagFormats = array ('id3v2.4');

$getID3 = new getID3;
    
$ThisFileInfo = $getID3->analyze($filename);

getid3_lib::CopyTagsToComments($ThisFileInfo);
    
$tagData = array();
        
foreach($ThisFileInfo['comments'] AS $field => $value){
    $tagData[$field]   = $value;
}
        
$tagWriter = new getid3_writetags();

$tagWriter->filename = $filename;
$tagWriter->tagformats = array ('id3v2.3');
$tagWriter->remove_other_tags = false;
$tagWriter->overwrite_tags = true;
$tagWriter->tag_encoding   = 'UTF-8'; 
$tagWriter->tag_data = $tagData;

$tagWriter -> WriteTags();

if (count($tagWriter -> errors)){
    echo ("\$tagWriter -> errors\n");
    print_r($tagWriter -> errors);
}

if (count($tagWriter -> warnings)){
    echo ("\$tagWriter -> warnings\n");
    print_r($tagWriter -> warnings);
}

James Heinrich
getID3() v1 developer
Posts: 1475
Joined: Fri May 04, 2001 4:00 pm
Are you a spambot?: no
Location: Northern Ontario, Canada
Contact:

Re: Tags removed, when remove_other_tags = false

Post by James Heinrich » Sat May 17, 2014 9:10 pm

To be honest the tag-writing part of getID3 hasn't been worked on for over 10 years so I'm pretty much guessing as much as you :)

The translation list of comment fieldnames to ID3v2 frame names is found in write.id3v2.php:1897 ID3v2ShortFrameNameLookup(). You'll note that it's expecting "tracknumber" rather than "track_number", one of those regression issues where something was changed and I didn't note the side effect on the writing part of the code. Adding an alias for the field name should fix the "cannot match it to a known ID3v2 frame type" error:
https://github.com/JamesHeinrich/getID3 ... 6611cf159c

As for the only-one-COMM error, my best guess is that getID3 is more pedantic than most tag writers when generating ID3v2 tags. According to the ID3v2 specs, there can be as many COMM (comment) frames as you like in a tag, but there can only be one with the same Language+Description. Many tag writers will leave both these fields blank, many will fill in the language field but leave the description blank. A blank description is valid for one tag, but the second comment frame will be flagged as "not allowed" because that "description" has already been used by a comment. As I said, pedantic, but that's what the ID3v2 specs say.

Unfortunately the tag-writing side of getID3 never received the same level of work as the reading code, so there are some rough edges and it's not as friendly to use as it could be. If you work through the code and find some bugs and fix them, or if you write some wrapper functions to make a task easier (such as merging new and existing tag data) then any patches or code contributions are welcome.

Side note:

Code: Select all

$tagData = array();       
foreach($ThisFileInfo['comments'] AS $field => $value){
    $tagData[$field]   = $value;
}

// can be simplified to:
$tagData = $ThisFileInfo['comments'];

JunkieVibes
User
Posts: 5
Joined: Fri May 16, 2014 5:04 pm
Are you a spambot?: no

Re: Tags removed, when remove_other_tags = false

Post by JunkieVibes » Sun May 18, 2014 9:48 am

Thanks for all the pointers, and for your consistently excellent support. I will look into that and if I can make any useful contributions I will do so.

Post Reply