Recientemente he creado un podcast para la página de Música Vermella con el inconveniente añadido de que se suben mp3 independientes para cada publicación.
Para solucionarlo he utilizado la librería getid3 para unir los ficheros mp3 de cada publicación en un único fichero mp3.
Para verlo podéis agregar el Podcast de Música Vermella a vuestro cliente de Podcast (iTunes, Rythmbox, Banshee, Miro…).
Quería hacer un tutorial sobre cómo crear un podcast con CakePHP pero lo dejaré para otro tutorial por tal de no complicar este.
Puedes ver la segunda parte aquí: Crear un Podcast en CakePHP
Para empezar necesitaréis descargar la librería Getid3. Descargad la versión estable por si acaso ya que la versión beta falla con las etiquetas id3 (que no utilizaremos) así que si queréis utilizarla es bajo vuestra propia responsabilidad.
Getid3 versión 1.8.2 (estable)
Descomprimid el contenido del fichero que descarguéis en Getid3 y ponedlo en la carpeta /app/vendors, de manera que quede así:
1 2 3 4 | /app/vendors/getid3/demos/ /app/vendors/getid3/getid3/ /app/vendors/getid3/helperapps/ /app/vendors/getid3/demás ficheros |
Ahora necesitaremos el método para unir los mp3. Lo podéis encontrar en la carpeta de demos de getid3. De todos modos os dejo aquí un pequeño componente que tengo yo para utilizar getid3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | <?php // /app/controllers/components/getid3.php class Getid3Component extends Object { public $errors = array(); function __construct() { set_time_limit(20*3600); ignore_user_abort(false); } function error($text) { array_push($this->errors, $text); } function extract($filename) { App::import('vendor','getid3/getid3',array('file'=>'getid3.php')); // Initialize getID3 engine $getID3 = new getID3; $getID3->setOption(array('encoding' => Configure::read('App.encoding'))); // Analyze file and store returned data in $ThisFileInfo $ThisFileInfo = $getID3->analyze($filename); return $ThisFileInfo; } function read($filename) { return $this->extract($filename); } function getId3Clean($filename) { $info = $this->read($filename); $id3 = array(); foreach ($info['tags'] as $tag) { foreach ($tag as $key => $val) { if (empty($id3[$key])) { $id3[$key] = $val[0]; } else { if (strlen($val[0]) > strlen($id3[$key])) { $id3[$key] = $val[0]; } } } } return $id3; } function getCustomTags($filename) { $id3 = $this->getId3Clean($filename); $vars = array( 'description' => 'content_group_description', 'set' => 'part_of_a_set' ); foreach ($vars as $k => $v) { if (!empty($id3[$v])) { $id3[$k] = $id3[$v]; unset($id3[$v]); } } return $id3; } function write($filename, $data) { App::import('vendor', 'getid3/getid3/getid3'); // Initialize getID3 engine $getID3 = new getID3; $getID3->setOption(array('encoding' => Configure::read('App.encoding'))); App::import('vendor','getid3/getid3', array('file' => 'write.php')); // Initialize getID3 tag-writing module $tagwriter = new getid3_writetags; //$tagwriter->filename = '/path/to/file.mp3'; $tagwriter->filename = $filename; $tagwriter->tagformats = array('id3v1', 'id3v2.3'); // set various options (optional) $tagwriter->overwrite_tags = true; $tagwriter->tag_encoding = Configure::read('App.encoding'); $tagwriter->remove_other_tags = true; // populate data array $TagData['title'][] = !empty($data['title'])?$data['title']:null; $TagData['artist'][] = !empty($data['artist'])?$data['artist']:null; $TagData['album'][] = !empty($data['album'])?$data['album']:null;; $TagData['year'][] = !empty($data['year'])?$data['year']:null;; $TagData['genre'][] = !empty($data['genre'])?$data['genre']:null;; $TagData['comment'][] = 'from www.underave.net'; $TagData['track'][] = !empty($data['track'])?$data['track']:null;; $tagwriter->tag_data = $TagData; // write tags if ($tagwriter->WriteTags()) { if (!empty($tagwriter->warnings)) { return $tagwriter->warnings; } return true; } else { return $tagwriter->errors; } } function joinMp3($file_out, $files_in) { foreach ($files_in as $nextinputfilename) { if (!is_readable($nextinputfilename)) { $this->error('Cannot read "' . $nextinputfilename . '"'); } } if (!empty($this->errors)) return false; if (!is_writeable(dirname($file_out))) { $this->error('Cannot write "' . $file_out . '"'); return false; } App::import('vendor', 'getid3/getid3', array('file' => 'getid3.php')); if ($fp_output = @fopen($file_out, 'wb')) { // Initialize getID3 engine $getID3 = new getID3; foreach ($files_in as $nextinputfilename) { $current_file_info = $getID3->analyze($nextinputfilename); if ($current_file_info['fileformat'] == 'mp3') { if ($fp_source = @fopen($nextinputfilename, 'rb')) { $current_output_position = ftell($fp_output); // copy audio data from first file fseek($fp_source, $current_file_info['avdataoffset'], SEEK_SET); while (!feof($fp_source) && (ftell($fp_source) < $current_file_info['avdataend'])) { fwrite($fp_output, fread($fp_source, 32768)); } fclose($fp_source); // trim post-audio data (if any) copied from first file that we don't need or want $end_offset = $current_output_position + ($current_file_info['avdataend'] - $current_file_info['avdataoffset']); fseek($fp_output, $end_offset, SEEK_SET); ftruncate($fp_output, $end_offset); } else { $this->error('failed to open ''.$nextinputfilename.'' for reading'); fclose($fp_output); return false; } } else { $this->error('''.$nextinputfilename.'' is not MP3 format'); fclose($fp_output); return false; } } } else { $this->error('failed to open ''.$file_out.'' for writing'); return false; } fclose($fp_output); return true; } } |
Con este componente podéis tanto unir mp3 como leer y escribir etiquetas id3.
Evidentemente, antes de poder utilizar el componente debéis declararlo en el array de componentes de vuestro controlador:
1 2 3 | class FooController extends AppController { $components = array('Getid3'); } |
Para unir mp3 en un solo fichero no tenéis más que pasarle como primer parámetro la ruta del fichero de salida y como segundo parámetro pasarle un array con las ubicaciones de los ficheros mp3:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $destino = WWW_ROOT . 'files' . DS . 'podcasts' . DS . 'fichero_destino.mp3'; $mp3 = array( WWW_ROOT . 'files' . DS . 'mp3' . DS . 'fichero1.mp3', WWW_ROOT . 'files' . DS . 'mp3' . DS . 'fichero2.mp3', WWW_ROOT . 'files' . DS . 'mp3' . DS . 'fichero3.mp3', WWW_ROOT . 'files' . DS . 'mp3' . DS . 'fichero4.mp3', WWW_ROOT . 'files' . DS . 'mp3' . DS . 'fichero5.mp3' ); if ($this->Getid3->joinMp3($destino, $mp3)) { // fichero creado correctamente } else { pr($this->Getid3->errors); } |
Y con esto termina este sencillo tutorial sobre cómo crear un podcast a partir de varios mp3.
Como he dicho al inicio, pronto explicaré cómo crear el XML de dicho Podcast para que podáis agregarlo a iTunes o cualquier otro podcatcher.