rlm@3
|
1 <?php
|
rlm@3
|
2 // +----------------------------------------------------------------------+
|
rlm@3
|
3 // | PHP version 5 |
|
rlm@3
|
4 // +----------------------------------------------------------------------+
|
rlm@3
|
5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen |
|
rlm@3
|
6 // +----------------------------------------------------------------------+
|
rlm@3
|
7 // | This source file is subject to version 2 of the GPL license, |
|
rlm@3
|
8 // | that is bundled with this package in the file license.txt and is |
|
rlm@3
|
9 // | available through the world-wide-web at the following url: |
|
rlm@3
|
10 // | http://www.gnu.org/copyleft/gpl.html |
|
rlm@3
|
11 // +----------------------------------------------------------------------+
|
rlm@3
|
12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org |
|
rlm@3
|
13 // +----------------------------------------------------------------------+
|
rlm@3
|
14 // | Authors: James Heinrich <infoØgetid3*org> |
|
rlm@3
|
15 // | Allan Hansen <ahØartemis*dk> |
|
rlm@3
|
16 // +----------------------------------------------------------------------+
|
rlm@3
|
17 // | module.tag.lyrics3.php |
|
rlm@3
|
18 // | module for analyzing Lyrics3 tags |
|
rlm@3
|
19 // | dependencies: module.tag.apetag.php (optional) |
|
rlm@3
|
20 // +----------------------------------------------------------------------+
|
rlm@3
|
21 //
|
rlm@3
|
22 // $Id: module.tag.lyrics3.php,v 1.5 2006/11/16 22:04:23 ah Exp $
|
rlm@3
|
23
|
rlm@3
|
24
|
rlm@3
|
25 class getid3_lyrics3 extends getid3_handler
|
rlm@3
|
26 {
|
rlm@3
|
27
|
rlm@3
|
28 public function Analyze() {
|
rlm@3
|
29
|
rlm@3
|
30 $getid3 = $this->getid3;
|
rlm@3
|
31
|
rlm@3
|
32 fseek($getid3->fp, (0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - LYRICSEND - [Lyrics3size]
|
rlm@3
|
33 $lyrics3_id3v1 = fread($getid3->fp, 128 + 9 + 6);
|
rlm@3
|
34 $lyrics3_lsz = substr($lyrics3_id3v1, 0, 6); // Lyrics3size
|
rlm@3
|
35 $lyrics3_end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200
|
rlm@3
|
36 $id3v1_tag = substr($lyrics3_id3v1, 15, 128); // ID3v1
|
rlm@3
|
37
|
rlm@3
|
38 // Lyrics3v1, ID3v1, no APE
|
rlm@3
|
39 if ($lyrics3_end == 'LYRICSEND') {
|
rlm@3
|
40
|
rlm@3
|
41 $lyrics3_size = 5100;
|
rlm@3
|
42 $lyrics3_offset = filesize($getid3->filename) - 128 - $lyrics3_size;
|
rlm@3
|
43 $lyrics3_version = 1;
|
rlm@3
|
44 }
|
rlm@3
|
45
|
rlm@3
|
46 // Lyrics3v2, ID3v1, no APE
|
rlm@3
|
47 elseif ($lyrics3_end == 'LYRICS200') {
|
rlm@3
|
48
|
rlm@3
|
49 // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
|
rlm@3
|
50 $lyrics3_size = $lyrics3_lsz + 6 + strlen('LYRICS200');
|
rlm@3
|
51 $lyrics3_offset = filesize($getid3->filename) - 128 - $lyrics3_size;
|
rlm@3
|
52 $lyrics3_version = 2;
|
rlm@3
|
53 }
|
rlm@3
|
54
|
rlm@3
|
55 // Lyrics3v1, no ID3v1, no APE
|
rlm@3
|
56 elseif (substr(strrev($lyrics3_id3v1), 0, 9) == 'DNESCIRYL') { // strrev('LYRICSEND') = 'DNESCIRYL'
|
rlm@3
|
57
|
rlm@3
|
58 $lyrics3_size = 5100;
|
rlm@3
|
59 $lyrics3_offset = filesize($getid3->filename) - $lyrics3_size;
|
rlm@3
|
60 $lyrics3_version = 1;
|
rlm@3
|
61 $lyrics3_offset = filesize($getid3->filename) - $lyrics3_size;
|
rlm@3
|
62 }
|
rlm@3
|
63
|
rlm@3
|
64 // Lyrics3v2, no ID3v1, no APE
|
rlm@3
|
65 elseif (substr(strrev($lyrics3_id3v1), 0, 9) == '002SCIRYL') { // strrev('LYRICS200') = '002SCIRYL'
|
rlm@3
|
66
|
rlm@3
|
67 $lyrics3_size = strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 15; // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' // 15 = 6 + strlen('LYRICS200')
|
rlm@3
|
68 $lyrics3_offset = filesize($getid3->filename) - $lyrics3_size;
|
rlm@3
|
69 $lyrics3_version = 2;
|
rlm@3
|
70 }
|
rlm@3
|
71
|
rlm@3
|
72 elseif (isset($getid3->info['ape']['tag_offset_start']) && ($getid3->info['ape']['tag_offset_start'] > 15)) {
|
rlm@3
|
73
|
rlm@3
|
74 fseek($getid3->fp, $getid3->info['ape']['tag_offset_start'] - 15, SEEK_SET);
|
rlm@3
|
75 $lyrics3_lsz = fread($getid3->fp, 6);
|
rlm@3
|
76 $lyrics3_end = fread($getid3->fp, 9);
|
rlm@3
|
77
|
rlm@3
|
78
|
rlm@3
|
79 // Lyrics3v1, APE, maybe ID3v1
|
rlm@3
|
80 if ($lyrics3_end == 'LYRICSEND') {
|
rlm@3
|
81
|
rlm@3
|
82 $lyrics3_size = 5100;
|
rlm@3
|
83 $lyrics3_offset = $getid3->info['ape']['tag_offset_start'] - $lyrics3_size;
|
rlm@3
|
84 $getid3->info['avdataend'] = $lyrics3_offset;
|
rlm@3
|
85 $lyrics3_version = 1;
|
rlm@3
|
86 $getid3->warning('APE tag located after Lyrics3, will probably break Lyrics3 compatability');
|
rlm@3
|
87 }
|
rlm@3
|
88
|
rlm@3
|
89
|
rlm@3
|
90 // Lyrics3v2, APE, maybe ID3v1
|
rlm@3
|
91 elseif ($lyrics3_end == 'LYRICS200') {
|
rlm@3
|
92
|
rlm@3
|
93 $lyrics3_size = $lyrics3_lsz + 15; // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
|
rlm@3
|
94 $lyrics3_offset = $getid3->info['ape']['tag_offset_start'] - $lyrics3_size;
|
rlm@3
|
95 $lyrics3_version = 2;
|
rlm@3
|
96 $getid3->warning('APE tag located after Lyrics3, will probably break Lyrics3 compatability');
|
rlm@3
|
97
|
rlm@3
|
98 }
|
rlm@3
|
99 }
|
rlm@3
|
100
|
rlm@3
|
101
|
rlm@3
|
102 //// GetLyrics3Data()
|
rlm@3
|
103
|
rlm@3
|
104
|
rlm@3
|
105 if (isset($lyrics3_offset)) {
|
rlm@3
|
106
|
rlm@3
|
107 $getid3->info['avdataend'] = $lyrics3_offset;
|
rlm@3
|
108
|
rlm@3
|
109 if ($lyrics3_size <= 0) {
|
rlm@3
|
110 return false;
|
rlm@3
|
111 }
|
rlm@3
|
112
|
rlm@3
|
113 fseek($getid3->fp, $lyrics3_offset, SEEK_SET);
|
rlm@3
|
114 $raw_data = fread($getid3->fp, $lyrics3_size);
|
rlm@3
|
115
|
rlm@3
|
116 if (substr($raw_data, 0, 11) != 'LYRICSBEGIN') {
|
rlm@3
|
117 if (strpos($raw_data, 'LYRICSBEGIN') !== false) {
|
rlm@3
|
118
|
rlm@3
|
119 $getid3->warning('"LYRICSBEGIN" expected at '.$lyrics3_offset.' but actually found at '.($lyrics3_offset + strpos($raw_data, 'LYRICSBEGIN')).' - this is invalid for Lyrics3 v'.$lyrics3_version);
|
rlm@3
|
120 $getid3->info['avdataend'] = $lyrics3_offset + strpos($raw_data, 'LYRICSBEGIN');
|
rlm@3
|
121 $parsed_lyrics3['tag_offset_start'] = $getid3->info['avdataend'];
|
rlm@3
|
122 $raw_data = substr($raw_data, strpos($raw_data, 'LYRICSBEGIN'));
|
rlm@3
|
123 $lyrics3_size = strlen($raw_data);
|
rlm@3
|
124 }
|
rlm@3
|
125 else {
|
rlm@3
|
126 throw new getid3_exception('"LYRICSBEGIN" expected at '.$lyrics3_offset.' but found "'.substr($raw_data, 0, 11).'" instead.');
|
rlm@3
|
127 }
|
rlm@3
|
128
|
rlm@3
|
129 }
|
rlm@3
|
130
|
rlm@3
|
131 $parsed_lyrics3['raw']['lyrics3version'] = $lyrics3_version;
|
rlm@3
|
132 $parsed_lyrics3['raw']['lyrics3tagsize'] = $lyrics3_size;
|
rlm@3
|
133 $parsed_lyrics3['tag_offset_start'] = $lyrics3_offset;
|
rlm@3
|
134 $parsed_lyrics3['tag_offset_end'] = $lyrics3_offset + $lyrics3_size;
|
rlm@3
|
135
|
rlm@3
|
136 switch ($lyrics3_version) {
|
rlm@3
|
137
|
rlm@3
|
138 case 1:
|
rlm@3
|
139 if (substr($raw_data, strlen($raw_data) - 9, 9) == 'LYRICSEND') {
|
rlm@3
|
140 $parsed_lyrics3['raw']['LYR'] = trim(substr($raw_data, 11, strlen($raw_data) - 11 - 9));
|
rlm@3
|
141 getid3_lyrics3::Lyrics3LyricsTimestampParse($parsed_lyrics3);
|
rlm@3
|
142 }
|
rlm@3
|
143 else {
|
rlm@3
|
144 throw new getid3_exception('"LYRICSEND" expected at '.(ftell($getid3->fp) - 11 + $lyrics3_size - 9).' but found "'.substr($raw_data, strlen($raw_data) - 9, 9).'" instead.');
|
rlm@3
|
145 }
|
rlm@3
|
146 break;
|
rlm@3
|
147
|
rlm@3
|
148 case 2:
|
rlm@3
|
149 if (substr($raw_data, strlen($raw_data) - 9, 9) == 'LYRICS200') {
|
rlm@3
|
150 $parsed_lyrics3['raw']['unparsed'] = substr($raw_data, 11, strlen($raw_data) - 11 - 9 - 6); // LYRICSBEGIN + LYRICS200 + LSZ
|
rlm@3
|
151 $raw_data = $parsed_lyrics3['raw']['unparsed'];
|
rlm@3
|
152 while (strlen($raw_data) > 0) {
|
rlm@3
|
153 $fieldname = substr($raw_data, 0, 3);
|
rlm@3
|
154 $fieldsize = (int)substr($raw_data, 3, 5);
|
rlm@3
|
155 $parsed_lyrics3['raw'][$fieldname] = substr($raw_data, 8, $fieldsize);
|
rlm@3
|
156 $raw_data = substr($raw_data, 3 + 5 + $fieldsize);
|
rlm@3
|
157 }
|
rlm@3
|
158
|
rlm@3
|
159 if (isset($parsed_lyrics3['raw']['IND'])) {
|
rlm@3
|
160 $i = 0;
|
rlm@3
|
161 foreach (array ('lyrics', 'timestamps', 'inhibitrandom') as $flagname) {
|
rlm@3
|
162 if (strlen($parsed_lyrics3['raw']['IND']) > ++$i) {
|
rlm@3
|
163 $parsed_lyrics3['flags'][$flagname] = getid3_lyrics3::IntString2Bool(substr($parsed_lyrics3['raw']['IND'], $i, 1));
|
rlm@3
|
164 }
|
rlm@3
|
165 }
|
rlm@3
|
166 }
|
rlm@3
|
167
|
rlm@3
|
168 foreach (array ('ETT'=>'title', 'EAR'=>'artist', 'EAL'=>'album', 'INF'=>'comment', 'AUT'=>'author') as $key => $value) {
|
rlm@3
|
169 if (isset($parsed_lyrics3['raw'][$key])) {
|
rlm@3
|
170 $parsed_lyrics3['comments'][$value][] = trim($parsed_lyrics3['raw'][$key]);
|
rlm@3
|
171 }
|
rlm@3
|
172 }
|
rlm@3
|
173
|
rlm@3
|
174 if (isset($parsed_lyrics3['raw']['IMG'])) {
|
rlm@3
|
175 foreach (explode("\r\n", $parsed_lyrics3['raw']['IMG']) as $key => $image_string) {
|
rlm@3
|
176 if (strpos($image_string, '||') !== false) {
|
rlm@3
|
177 $imagearray = explode('||', $image_string);
|
rlm@3
|
178 $parsed_lyrics3['images'][$key]['filename'] = @$imagearray[0];
|
rlm@3
|
179 $parsed_lyrics3['images'][$key]['description'] = @$imagearray[1];
|
rlm@3
|
180 $parsed_lyrics3['images'][$key]['timestamp'] = getid3_lyrics3::Lyrics3Timestamp2Seconds(@$imagearray[2]);
|
rlm@3
|
181 }
|
rlm@3
|
182 }
|
rlm@3
|
183 }
|
rlm@3
|
184
|
rlm@3
|
185 if (isset($parsed_lyrics3['raw']['LYR'])) {
|
rlm@3
|
186 getid3_lyrics3::Lyrics3LyricsTimestampParse($parsed_lyrics3);
|
rlm@3
|
187 }
|
rlm@3
|
188 }
|
rlm@3
|
189 else {
|
rlm@3
|
190 throw new getid3_exception('"LYRICS200" expected at '.(ftell($getid3->fp) - 11 + $lyrics3_size - 9).' but found "'.substr($raw_data, strlen($raw_data) - 9, 9).'" instead.');
|
rlm@3
|
191 }
|
rlm@3
|
192 break;
|
rlm@3
|
193
|
rlm@3
|
194 default:
|
rlm@3
|
195 throw new getid3_exception('Cannot process Lyrics3 version '.$lyrics3_version.' (only v1 and v2)');
|
rlm@3
|
196 }
|
rlm@3
|
197
|
rlm@3
|
198 if (isset($getid3->info['id3v1']['tag_offset_start']) && ($getid3->info['id3v1']['tag_offset_start'] < $parsed_lyrics3['tag_offset_end'])) {
|
rlm@3
|
199 $getid3->warning('ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data');
|
rlm@3
|
200 unset($getid3->info['id3v1']);
|
rlm@3
|
201 }
|
rlm@3
|
202
|
rlm@3
|
203 $getid3->info['lyrics3'] = $parsed_lyrics3;
|
rlm@3
|
204
|
rlm@3
|
205
|
rlm@3
|
206 // Check for APE tag after lyrics3
|
rlm@3
|
207 if (!@$getid3->info['ape'] && $getid3->option_tag_apetag && class_exists('getid3_apetag')) {
|
rlm@3
|
208 $apetag = new getid3_apetag($getid3);
|
rlm@3
|
209 $apetag->option_override_end_offset = $getid3->info['lyrics3']['tag_offset_start'];
|
rlm@3
|
210 $apetag->Analyze();
|
rlm@3
|
211 }
|
rlm@3
|
212 }
|
rlm@3
|
213
|
rlm@3
|
214 return true;
|
rlm@3
|
215 }
|
rlm@3
|
216
|
rlm@3
|
217
|
rlm@3
|
218
|
rlm@3
|
219
|
rlm@3
|
220 public static function Lyrics3Timestamp2Seconds($rawtimestamp) {
|
rlm@3
|
221 if (ereg('^\\[([0-9]{2}):([0-9]{2})\\]$', $rawtimestamp, $regs)) {
|
rlm@3
|
222 return (int)(($regs[1] * 60) + $regs[2]);
|
rlm@3
|
223 }
|
rlm@3
|
224 return false;
|
rlm@3
|
225 }
|
rlm@3
|
226
|
rlm@3
|
227
|
rlm@3
|
228
|
rlm@3
|
229 public static function Lyrics3LyricsTimestampParse(&$lyrics3_data) {
|
rlm@3
|
230
|
rlm@3
|
231 $lyrics_array = explode("\r\n", $lyrics3_data['raw']['LYR']);
|
rlm@3
|
232 foreach ($lyrics_array as $key => $lyric_line) {
|
rlm@3
|
233
|
rlm@3
|
234 while (ereg('^(\\[[0-9]{2}:[0-9]{2}\\])', $lyric_line, $regs)) {
|
rlm@3
|
235 $this_line_timestamps[] = getid3_lyrics3::Lyrics3Timestamp2Seconds($regs[0]);
|
rlm@3
|
236 $lyric_line = str_replace($regs[0], '', $lyric_line);
|
rlm@3
|
237 }
|
rlm@3
|
238 $no_timestamp_lyrics_array[$key] = $lyric_line;
|
rlm@3
|
239 if (@is_array($this_line_timestamps)) {
|
rlm@3
|
240 sort($this_line_timestamps);
|
rlm@3
|
241 foreach ($this_line_timestamps as $timestampkey => $timestamp) {
|
rlm@3
|
242 if (isset($lyrics3_data['synchedlyrics'][$timestamp])) {
|
rlm@3
|
243 // timestamps only have a 1-second resolution, it's possible that multiple lines
|
rlm@3
|
244 // could have the same timestamp, if so, append
|
rlm@3
|
245 $lyrics3_data['synchedlyrics'][$timestamp] .= "\r\n".$lyric_line;
|
rlm@3
|
246 } else {
|
rlm@3
|
247 $lyrics3_data['synchedlyrics'][$timestamp] = $lyric_line;
|
rlm@3
|
248 }
|
rlm@3
|
249 }
|
rlm@3
|
250 }
|
rlm@3
|
251 unset($this_line_timestamps);
|
rlm@3
|
252 $regs = array ();
|
rlm@3
|
253 }
|
rlm@3
|
254 $lyrics3_data['unsynchedlyrics'] = implode("\r\n", $no_timestamp_lyrics_array);
|
rlm@3
|
255 if (isset($lyrics3_data['synchedlyrics']) && is_array($lyrics3_data['synchedlyrics'])) {
|
rlm@3
|
256 ksort($lyrics3_data['synchedlyrics']);
|
rlm@3
|
257 }
|
rlm@3
|
258 return true;
|
rlm@3
|
259 }
|
rlm@3
|
260
|
rlm@3
|
261
|
rlm@3
|
262
|
rlm@3
|
263 public static function IntString2Bool($char) {
|
rlm@3
|
264
|
rlm@3
|
265 return $char == '1' ? true : ($char == '0' ? false : null);
|
rlm@3
|
266 }
|
rlm@3
|
267 }
|
rlm@3
|
268
|
rlm@3
|
269
|
rlm@3
|
270 ?> |