function tagFlacFile($file, $tagData, $allowBlank = FALSE, $coverFile = NULL) { if (!file_exists($file)) { $error = 'The input file appears not to exist'; return array('result' => FALSE, 'error' => $error); } //Instantiate the getID3 object. $gid3 = new getID3(); if (!is_object($gid3)) { $error = 'The getID3 object could not be instantiated'; return array('result' => FALSE, 'error' => $error); } //Attempt to acquire the audio file's properties. $fileDetails = $gid3->analyze($file); if (!is_array($fileDetails)) { $error = 'getID3\'s analyze() method did not return a usable array'; return array('result' => FALSE, 'error' => $error); } //Ensure that the file on which we're attempting to operate is indeed //a FLAC file. // //Note: we could use the self::validateAudioFile() method, but there's //no reason to waste the time/memory required to call that function //when we have to call getID3's analyze() method again. if (!isset($fileDetails['fileformat']) || $fileDetails['fileformat'] != 'flac') { $error = 'The audio file does not validate as a FLAC file'; return array('result' => FALSE, 'error' => $error); } //A counter to store the number of tags that we attempted to write. $numWritesAttempted = 0; //Attempt to remove any existing tags before writing new tags. //IMPORTANT: The --remove-vc-all option is deprecated in favor of the //--remove-all-tags option; using the deprecated option will cause the //command to fail on systems on which the option is not supported. //Changed to --remove-all because cover art was not being removed. -CBJ 2011.01.18 $cmd = 'metaflac --remove-all "' . $file . '"'; //XXX This call should be updated to use GlobalMethods::openProcess(). $output = shell_exec($cmd); //Attempt to acquire the audio file's properties, again, now that //we've attempted to remove any existing tags. $fileDetails = $gid3->analyze($file); if (!is_array($fileDetails)) { $error = 'getID3\'s analyze() method did not return a usable array'; return array('result' => FALSE, 'error' => $error); } //We attempted to remove all tags from the FLAC file; we can //determine whether or not we were successful in that effort by //checking to see if the vorbiscomment block is present in the file. if (isset($fileDetails['tags']['vorbiscomment'])) { $error = 'The vorbiscomment block was not removed for some reason'; return array('result' => FALSE, 'error' => $error); } if (empty($tagData['date'][0]) || $tagData['date'][0] === 'Unknown') { unset($tagData['date']); } if (!empty($coverFile)) { $res = $this->embedFlacArt($coverFile, $file); if ($res['result'] !== FALSE) { } else { $error = 'Embedding cover art in FLAC file "' . $file . '" failed; ' . $res['error']; \GlobalMethods::logCriticalError($error); } } //Attempt to add each tag to the FLAC file, and keep track of the number //of write attempts. Given that the shell_exec() exit status is not a //reliable means by which to determine the success/failure of the //operation, we must compare the number of write attempts to the number //of tags that exist once we're done attempting to write. foreach ($tagData as $fieldName => $fieldDataArray) { foreach ($fieldDataArray as $numericIndex => $fieldValue) { //IMPORTANT: The --set-vc-field option is deprecated in favor of the //--set-tag option; using the deprecated option will cause the command to //fail on systems on which the option is not supported. $cmd = 'metaflac --set-tag=' . ucfirst($fieldName) . '="' . $fieldValue . '" "' . $file . '"'; //XXX This call should be updated to use GlobalMethods::openProcess(). $output = shell_exec($cmd); $numWritesAttempted++; } } //Attempt to acquire the audio file's properties, again, now that we've //attempted to write new tags. $fileDetails = $gid3->analyze($file); $prefix = 'getID3\'s analyze() method'; if (!is_array($fileDetails)) { $error = $prefix . ' did not return a usable array'; return array('result' => FALSE, 'error' => $error); } if ($allowBlank !== TRUE) { if (!isset($fileDetails['tags']['vorbiscomment'])) { $error = $prefix . ' determined that the tags were not written for some reason'; if (!empty($fileDetails['error'])) { for ($i = 0; $i < count($fileDetails['error']); $i++) { if ($i == 0) { $error .= ": "; } else { $error .= '; '; } $error .= $fileDetails['error'][$i]; } } return array('result' => FALSE, 'error' => $error); } else { //If at least one tag was written, we'll end-up here. $vorbiscomment = $fileDetails['tags']['vorbiscomment']; $numWritesSucceeded = 0; //Now, we'll compare each tag on the file with the tag data that //we attempted to apply earlier, in order to determine whether //or not each tag was written successfully. foreach ($tagData as $fieldName => $fieldDataArray) { foreach ($fieldDataArray as $numericIndex => $fieldValue) { if ($vorbiscomment[$fieldName][0] == $fieldValue) { $numWritesSucceeded++; } } } //We're able to compare how many tags were written versus how //many write attempts were made in order to determine our //success rate. if ($numWritesAttempted == $numWritesSucceeded) { return array('result' => TRUE, 'error' => NULL); } else { $error = 'The number of tag writes that succeeded (' . $numWritesSucceeded . ') is less than the number attempted (' . $numWritesAttempted . ')'; return array('result' => FALSE, 'error' => $error); } } } else { return array('result' => TRUE, 'error' => NULL); } }
/** * Important: NEVER call this function on a "master" file, as it removes the * artwork from THAT file (and not a copy)! * @param string $file * @param array $tagData * @param boolean $allowBlank * @param string $coverFile * @return multitype:boolean string |multitype:boolean NULL */ function transcodeFlacToAlac($file, $tagData = array(), $allowBlank = FALSE, $coverFile = NULL) { //In avconv version 9.16 (and possibly earlier), embedded artwork with a //width or height that is not divisible by 2 will cause a failure, e.g.: //"width not divisible by 2 (1419x1419)". So, we must strip any "odd" artwork. //It's entirely possible that artwork was not copied in earlier versions, so //this error did not occur. $r = $this->tagger->removeArtwork($file); $cmd1 = 'avconv -i'; //Tag data is copied automatically. Nice!!! $pathParts = pathinfo($file); $outfile = $pathParts['dirname'] . DIRECTORY_SEPARATOR . $pathParts['filename'] . '.m4a'; $cmd1 .= ' "' . $file . '" -acodec alac "' . $outfile . '"'; $r1 = \GlobalMethods::openProcess($cmd1); if ($r1['exitCode'] == 0) { //Write the cover artwork into the file, and fail gracefully. //Note the unconventional letter-case of the executable name and its options //(which are indeed case-sensitive). if (is_string($coverFile) && strlen($coverFile) > 0) { $cmd2 = 'AtomicParsley "' . $outfile . '" --artwork "' . $coverFile . '" --overWrite'; $r2 = \GlobalMethods::openProcess($cmd2); if ($r2['exitCode'] != 0) { $e = 'The FLAC file was transcoded to an ALAC file successfully, but the album artwork could not be embedded; the command was: "' . $cmd2 . '"'; \GlobalMethods::logCriticalError($e); } } } else { $error = 'The FLAC file could not be transcoded to an ALAC file; the command was: "' . $cmd1 . '"'; return array('result' => FALSE, 'error' => $error); } return array('result' => TRUE, 'error' => NULL); }