/** * Write metadata * * @param array $data * * @throws \RuntimeException * * @return $this */ public function write(array $data = null) { $this->tagWriter->filename = $this->filename; if (null === $data) { if (!$this->tagWriter->DeleteTags(array($this->name))) { GetId3::getInstance()->close(); throw new \RuntimeException(sprintf('Error while deleting metadata from "%s": %s.', $this->tagWriter->filename, implode(PHP_EOL, $this->tagWriter->errors))); } } else { $this->tagWriter->tagformats = array($this->name); $this->tagWriter->tag_data = $data; if (!$this->tagWriter->WriteTags()) { GetId3::getInstance()->close(); throw new \RuntimeException(sprintf('Error while writing metadata to "%s": %s.', $this->tagWriter->filename, implode(PHP_EOL, $this->tagWriter->errors))); } } return $this; }
/** * Get ID3 V2 tag * * @throws \RuntimeException * * @return \GravityMedia\Metadata\Tag\Id3v2 */ public function getId3v2Tag() { $factory = GetId3::getInstance()->open($this->file); $properties = $factory->createId3v2TagReader()->read(); $hydrator = new ClassMethods(); $data = array(); unset($properties['comments']); foreach ($properties as $frameName => $values) { if (!in_array($frameName, Id3v2Tag::$FRAMENAMES)) { continue; } /** @var string $name */ $name = GetId3::lookupId3v2FrameName($frameName); switch ($name) { case 'attached_picture': $data['picture'] = $hydrator->hydrate($values[0], new Picture()); break; default: $value = iconv($values[0]['encoding'], 'UTF-8', $values[0]['data']); // map name and/or value switch ($name) { case 'year': $data['year'] = intval($value); break; case 'track_number': $disc = explode('/', $value, 2); $data['track'] = intval(array_shift($disc)); if (count($disc) > 0) { $data['track_count'] = intval(array_shift($disc)); } break; case 'content_group_description': $data['works'] = $value; break; case 'part_of_a_set': $disc = explode('/', $value, 2); $data['disc'] = intval(array_shift($disc)); if (count($disc) > 0) { $data['disc_count'] = intval(array_shift($disc)); } break; default: $data[$name] = $value; break; } break; } } // add audio properties $data['audio_properties'] = $hydrator->hydrate($factory->createAudioFormatReader()->read(), new AudioProperties()); return $hydrator->hydrate($data, new Id3v2Tag($factory->createId3v2TagWriter())); }
/** * Read metadata * * @throws \RuntimeException * * @return array */ public function read() { $this->handler->Analyze(); if (!empty($this->info['error'])) { GetId3::getInstance()->close(); throw new \RuntimeException(sprintf('Error while reading metadata from "%s": %s.', $this->filename, implode(PHP_EOL, $this->info['error']))); } if (isset($this->info[$this->name])) { $data = $this->info[$this->name]; if (in_array($this->name, array('audio', 'video'))) { $data['playtime'] = $this->info['playtime_seconds']; } return $data; } return array(); }
/** * Create audio format reader * * @throws \RuntimeException * * @return \GravityMedia\Metadata\GetId3\Reader */ public function createAudioFormatReader() { // detect data offset $offset = $this->info['avdataoffset']; if (isset($this->info['id3v2']['tag_offset_start'])) { $offset = max($offset, $this->info['id3v2']['tag_offset_end']); } // length of ID3 v2 tag in 10-byte header doesn't include 10-byte header length if (!isset($this->info['id3v2'])) { fseek($this->fp, 0); $header = fread($this->fp, 10); if ('ID3' === substr($header, 0, 3) && 10 == strlen($header)) { $offset += GetId3Lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; } } // read 32 kb file data fseek($this->fp, $offset, SEEK_SET); $data = fread($this->fp, 32774); // detect format $format = GetId3::getInstance()->getGetId3()->GetFileFormat($data, $this->filename); // unable to detect format if (false === $format) { GetId3::getInstance()->close(); throw new \RuntimeException(sprintf('Unable to determine file format of "%s".', $this->filename)); } // check for illegal ID3 tags if ((isset($this->info['tags']['id3v1']) || isset($this->info['tags']['id3v2'])) && isset($format['fail_id3']) && 'ERROR' === $format['fail_id3']) { GetId3::getInstance()->close(); throw new \RuntimeException('ID3 tags not allowed on this file type.'); } // check for illegal APE tags if (isset($this->info['tags']['ape']) && isset($format['fail_ape']) && 'ERROR' === $format['fail_ape']) { GetId3::getInstance()->close(); throw new \RuntimeException('APE tags not allowed on this file type.'); } return $this->createReader($format['group'], $format['module'], 'audio'); }
/** * Set genre * * @param string $genre * * @throws \BadMethodCallException * @return $this */ public function setGenre($genre) { if (!is_array($this->availableGenres)) { $this->availableGenres = array_values(GetId3::getId3v1Genres()); } if (in_array($genre, $this->availableGenres)) { $this->genre = $genre; return $this; } throw new \BadMethodCallException(sprintf('The genre "%s" is not available', $genre)); }
/** * Save tag * * @throws \RuntimeException * * @return $this */ public function save() { $hydrator = new ClassMethods(); $properties = $hydrator->extract($this); $data = array(); unset($properties['audio_properties']); foreach ($properties as $name => $value) { if (null === $value) { continue; } switch ($name) { case 'track': if (null !== $properties['track_count']) { $value .= '/' . $properties['track_count']; } $data['track'] = array($value); break; case 'works': $data['content_group_description'] = array($value); break; case 'disc': if (null !== $properties['disc_count']) { $value .= '/' . $properties['disc_count']; } $data['part_of_a_set'] = array($value); break; case 'picture': /** @var \GravityMedia\Metadata\Feature\Picture $value */ $data['attached_picture'] = array(array('data' => $value->getData(), 'mime' => $value->getMime(), 'picturetypeid' => array_search($value->getPictureType(), GetId3::getId3v2PictureTypes()), 'description' => $value->getDescription())); break; default: $data[$name] = array($value); break; } } return $this->writer->write($data); }
/** * Set picture type * * @param string $pictureType * * @throws \BadMethodCallException * * @return $this */ public function setPictureType($pictureType) { if (!is_array($this->availablePictureTypes)) { $this->availablePictureTypes = array_values(GetId3::getId3v2PictureTypes()); } if (in_array($pictureType, $this->availablePictureTypes)) { $this->pictureType = $pictureType; return $this; } throw new \BadMethodCallException(sprintf('The picture type "%s" is not available', $pictureType)); }