source: extensions/charlies_content/getid3/getid3/module.tag.lyrics3.php

Last change on this file was 3544, checked in by vdigital, 15 years ago

Change: getid3 upgraded to -> 1.7.9

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Author Date Id Revision
File size: 10.2 KB
Line 
1<?php
2/////////////////////////////////////////////////////////////////
3/// getID3() by James Heinrich <info@getid3.org>               //
4//  available at http://getid3.sourceforge.net                 //
5//            or http://www.getid3.org                         //
6/////////////////////////////////////////////////////////////////
7// See readme.txt for more details                             //
8/////////////////////////////////////////////////////////////////
9///                                                            //
10// module.tag.lyrics3.php                                      //
11// module for analyzing Lyrics3 tags                           //
12// dependencies: module.tag.apetag.php (optional)              //
13//                                                            ///
14/////////////////////////////////////////////////////////////////
15
16
17class getid3_lyrics3
18{
19
20        function getid3_lyrics3(&$fd, &$ThisFileInfo) {
21                // http://www.volweb.cz/str/tags.htm
22
23                if ($ThisFileInfo['filesize'] >= pow(2, 31)) {
24                        $ThisFileInfo['warning'][] = 'Unable to check for Lyrics3 because file is larger than 2GB';
25                        return false;
26                }
27
28                fseek($fd, (0 - 128 - 9 - 6), SEEK_END);          // end - ID3v1 - LYRICSEND - [Lyrics3size]
29                $lyrics3_id3v1 = fread($fd, 128 + 9 + 6);
30                $lyrics3lsz    = substr($lyrics3_id3v1,  0,   6); // Lyrics3size
31                $lyrics3end    = substr($lyrics3_id3v1,  6,   9); // LYRICSEND or LYRICS200
32                $id3v1tag      = substr($lyrics3_id3v1, 15, 128); // ID3v1
33
34                if ($lyrics3end == 'LYRICSEND') {
35                        // Lyrics3v1, ID3v1, no APE
36
37                        $lyrics3size    = 5100;
38                        $lyrics3offset  = $ThisFileInfo['filesize'] - 128 - $lyrics3size;
39                        $lyrics3version = 1;
40
41                } elseif ($lyrics3end == 'LYRICS200') {
42                        // Lyrics3v2, ID3v1, no APE
43
44                        // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
45                        $lyrics3size    = $lyrics3lsz + 6 + strlen('LYRICS200');
46                        $lyrics3offset  = $ThisFileInfo['filesize'] - 128 - $lyrics3size;
47                        $lyrics3version = 2;
48
49                } elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICSEND')) {
50                        // Lyrics3v1, no ID3v1, no APE
51
52                        $lyrics3size    = 5100;
53                        $lyrics3offset  = $ThisFileInfo['filesize'] - $lyrics3size;
54                        $lyrics3version = 1;
55                        $lyrics3offset  = $ThisFileInfo['filesize'] - $lyrics3size;
56
57                } elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICS200')) {
58
59                        // Lyrics3v2, no ID3v1, no APE
60
61                        $lyrics3size    = strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
62                        $lyrics3offset  = $ThisFileInfo['filesize'] - $lyrics3size;
63                        $lyrics3version = 2;
64
65                } else {
66
67                        if (isset($ThisFileInfo['ape']['tag_offset_start']) && ($ThisFileInfo['ape']['tag_offset_start'] > 15)) {
68
69                                fseek($fd, $ThisFileInfo['ape']['tag_offset_start'] - 15, SEEK_SET);
70                                $lyrics3lsz = fread($fd, 6);
71                                $lyrics3end = fread($fd, 9);
72
73                                if ($lyrics3end == 'LYRICSEND') {
74                                        // Lyrics3v1, APE, maybe ID3v1
75
76                                        $lyrics3size    = 5100;
77                                        $lyrics3offset  = $ThisFileInfo['ape']['tag_offset_start'] - $lyrics3size;
78                                        $ThisFileInfo['avdataend'] = $lyrics3offset;
79                                        $lyrics3version = 1;
80                                        $ThisFileInfo['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';
81
82                                } elseif ($lyrics3end == 'LYRICS200') {
83                                        // Lyrics3v2, APE, maybe ID3v1
84
85                                        $lyrics3size    = $lyrics3lsz + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
86                                        $lyrics3offset  = $ThisFileInfo['ape']['tag_offset_start'] - $lyrics3size;
87                                        $lyrics3version = 2;
88                                        $ThisFileInfo['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';
89
90                                }
91
92                        }
93
94                }
95
96                if (isset($lyrics3offset)) {
97                        $ThisFileInfo['avdataend'] = $lyrics3offset;
98                        $this->getLyrics3Data($ThisFileInfo, $fd, $lyrics3offset, $lyrics3version, $lyrics3size);
99
100                        if (!isset($ThisFileInfo['ape'])) {
101                                $GETID3_ERRORARRAY = &$ThisFileInfo['warning'];
102                                if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, false)) {
103                                        $tag = new getid3_apetag($fd, $ThisFileInfo, $ThisFileInfo['lyrics3']['tag_offset_start']);
104                                        unset($tag);
105                                }
106                        }
107
108                }
109
110                return true;
111        }
112
113        function getLyrics3Data(&$ThisFileInfo, &$fd, $endoffset, $version, $length) {
114                // http://www.volweb.cz/str/tags.htm
115
116                if ($endoffset >= pow(2, 31)) {
117                        $ThisFileInfo['warning'][] = 'Unable to check for Lyrics3 because file is larger than 2GB';
118                        return false;
119                }
120
121                fseek($fd, $endoffset, SEEK_SET);
122                if ($length <= 0) {
123                        return false;
124                }
125                $rawdata = fread($fd, $length);
126
127                if (substr($rawdata, 0, 11) != 'LYRICSBEGIN') {
128                        if (strpos($rawdata, 'LYRICSBEGIN') !== false) {
129
130                                $ThisFileInfo['warning'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but actually found at '.($endoffset + strpos($rawdata, 'LYRICSBEGIN')).' - this is invalid for Lyrics3 v'.$version;
131                                $ThisFileInfo['avdataend'] = $endoffset + strpos($rawdata, 'LYRICSBEGIN');
132                                $ParsedLyrics3['tag_offset_start'] = $ThisFileInfo['avdataend'];
133                                $rawdata = substr($rawdata, strpos($rawdata, 'LYRICSBEGIN'));
134                                $length = strlen($rawdata);
135
136                        } else {
137
138                                $ThisFileInfo['error'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but found "'.substr($rawdata, 0, 11).'" instead';
139                                return false;
140
141                        }
142
143                }
144
145                $ParsedLyrics3['raw']['lyrics3version'] = $version;
146                $ParsedLyrics3['raw']['lyrics3tagsize'] = $length;
147                $ParsedLyrics3['tag_offset_start']      = $endoffset;
148                $ParsedLyrics3['tag_offset_end']        = $endoffset + $length;
149
150                switch ($version) {
151
152                        case 1:
153                                if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICSEND') {
154                                        $ParsedLyrics3['raw']['LYR'] = trim(substr($rawdata, 11, strlen($rawdata) - 11 - 9));
155                                        $this->Lyrics3LyricsTimestampParse($ParsedLyrics3);
156                                } else {
157                                        $ThisFileInfo['error'][] = '"LYRICSEND" expected at '.(ftell($fd) - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
158                                        return false;
159                                }
160                                break;
161
162                        case 2:
163                                if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICS200') {
164                                        $ParsedLyrics3['raw']['unparsed'] = substr($rawdata, 11, strlen($rawdata) - 11 - 9 - 6); // LYRICSBEGIN + LYRICS200 + LSZ
165                                        $rawdata = $ParsedLyrics3['raw']['unparsed'];
166                                        while (strlen($rawdata) > 0) {
167                                                $fieldname = substr($rawdata, 0, 3);
168                                                $fieldsize = (int) substr($rawdata, 3, 5);
169                                                $ParsedLyrics3['raw'][$fieldname] = substr($rawdata, 8, $fieldsize);
170                                                $rawdata = substr($rawdata, 3 + 5 + $fieldsize);
171                                        }
172
173                                        if (isset($ParsedLyrics3['raw']['IND'])) {
174                                                $i = 0;
175                                                $flagnames = array('lyrics', 'timestamps', 'inhibitrandom');
176                                                foreach ($flagnames as $flagname) {
177                                                        if (strlen($ParsedLyrics3['raw']['IND']) > $i++) {
178                                                                $ParsedLyrics3['flags'][$flagname] = $this->IntString2Bool(substr($ParsedLyrics3['raw']['IND'], $i, 1 - 1));
179                                                        }
180                                                }
181                                        }
182
183                                        $fieldnametranslation = array('ETT'=>'title', 'EAR'=>'artist', 'EAL'=>'album', 'INF'=>'comment', 'AUT'=>'author');
184                                        foreach ($fieldnametranslation as $key => $value) {
185                                                if (isset($ParsedLyrics3['raw'][$key])) {
186                                                        $ParsedLyrics3['comments'][$value][] = trim($ParsedLyrics3['raw'][$key]);
187                                                }
188                                        }
189
190                                        if (isset($ParsedLyrics3['raw']['IMG'])) {
191                                                $imagestrings = explode("\r\n", $ParsedLyrics3['raw']['IMG']);
192                                                foreach ($imagestrings as $key => $imagestring) {
193                                                        if (strpos($imagestring, '||') !== false) {
194                                                                $imagearray = explode('||', $imagestring);
195                                                                $ParsedLyrics3['images'][$key]['filename']     = @$imagearray[0];
196                                                                $ParsedLyrics3['images'][$key]['description']  = @$imagearray[1];
197                                                                $ParsedLyrics3['images'][$key]['timestamp']    = $this->Lyrics3Timestamp2Seconds(@$imagearray[2]);
198                                                        }
199                                                }
200                                        }
201                                        if (isset($ParsedLyrics3['raw']['LYR'])) {
202                                                $this->Lyrics3LyricsTimestampParse($ParsedLyrics3);
203                                        }
204                                } else {
205                                        $ThisFileInfo['error'][] = '"LYRICS200" expected at '.(ftell($fd) - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
206                                        return false;
207                                }
208                                break;
209
210                        default:
211                                $ThisFileInfo['error'][] = 'Cannot process Lyrics3 version '.$version.' (only v1 and v2)';
212                                return false;
213                                break;
214                }
215
216
217                if (isset($ThisFileInfo['id3v1']['tag_offset_start']) && ($ThisFileInfo['id3v1']['tag_offset_start'] < $ParsedLyrics3['tag_offset_end'])) {
218                        $ThisFileInfo['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data';
219                        unset($ThisFileInfo['id3v1']);
220                        foreach ($ThisFileInfo['warning'] as $key => $value) {
221                                if ($value == 'Some ID3v1 fields do not use NULL characters for padding') {
222                                        unset($ThisFileInfo['warning'][$key]);
223                                        sort($ThisFileInfo['warning']);
224                                        break;
225                                }
226                        }
227                }
228
229                $ThisFileInfo['lyrics3'] = $ParsedLyrics3;
230
231                return true;
232        }
233
234        function Lyrics3Timestamp2Seconds($rawtimestamp) {
235                if (ereg('^\\[([0-9]{2}):([0-9]{2})\\]$', $rawtimestamp, $regs)) {
236                        return (int) (($regs[1] * 60) + $regs[2]);
237                }
238                return false;
239        }
240
241        function Lyrics3LyricsTimestampParse(&$Lyrics3data) {
242                $lyricsarray = explode("\r\n", $Lyrics3data['raw']['LYR']);
243                foreach ($lyricsarray as $key => $lyricline) {
244                        $regs = array();
245                        unset($thislinetimestamps);
246                        while (ereg('^(\\[[0-9]{2}:[0-9]{2}\\])', $lyricline, $regs)) {
247                                $thislinetimestamps[] = $this->Lyrics3Timestamp2Seconds($regs[0]);
248                                $lyricline = str_replace($regs[0], '', $lyricline);
249                        }
250                        $notimestamplyricsarray[$key] = $lyricline;
251                        if (isset($thislinetimestamps) && is_array($thislinetimestamps)) {
252                                sort($thislinetimestamps);
253                                foreach ($thislinetimestamps as $timestampkey => $timestamp) {
254                                        if (isset($Lyrics3data['synchedlyrics'][$timestamp])) {
255                                                // timestamps only have a 1-second resolution, it's possible that multiple lines
256                                                // could have the same timestamp, if so, append
257                                                $Lyrics3data['synchedlyrics'][$timestamp] .= "\r\n".$lyricline;
258                                        } else {
259                                                $Lyrics3data['synchedlyrics'][$timestamp] = $lyricline;
260                                        }
261                                }
262                        }
263                }
264                $Lyrics3data['unsynchedlyrics'] = implode("\r\n", $notimestamplyricsarray);
265                if (isset($Lyrics3data['synchedlyrics']) && is_array($Lyrics3data['synchedlyrics'])) {
266                        ksort($Lyrics3data['synchedlyrics']);
267                }
268                return true;
269        }
270
271        function IntString2Bool($char) {
272                if ($char == '1') {
273                        return true;
274                } elseif ($char == '0') {
275                        return false;
276                }
277                return null;
278        }
279}
280
281
282?>
Note: See TracBrowser for help on using the repository browser.