| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 importScripts('function_sequence.js'); | 5 importScripts('function_sequence.js'); |
| 6 importScripts('function_parallel.js'); | 6 importScripts('function_parallel.js'); |
| 7 | 7 |
| 8 function Id3Parser(parent) { | 8 function Id3Parser(parent) { |
| 9 MetadataParser.call(this, parent, 'id3', /\.(mp3)$/i); | 9 MetadataParser.call(this, parent, 'id3', /\.(mp3)$/i); |
| 10 } | 10 } |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 Id3Parser.prototype.readFrame_ = function(reader, majorVersion) { | 160 Id3Parser.prototype.readFrame_ = function(reader, majorVersion) { |
| 161 if (reader.eof()) | 161 if (reader.eof()) |
| 162 return null; | 162 return null; |
| 163 | 163 |
| 164 var frame = {}; | 164 var frame = {}; |
| 165 | 165 |
| 166 reader.pushSeek(reader.tell(), ByteReader.SEEK_BEG); | 166 reader.pushSeek(reader.tell(), ByteReader.SEEK_BEG); |
| 167 | 167 |
| 168 var position = reader.tell(); | 168 var position = reader.tell(); |
| 169 | 169 |
| 170 frame.name = (majorVersion == 2) | 170 frame.name = (majorVersion == 2) ? reader.readNullTerminatedString(3) : |
| 171 ? reader.readNullTerminatedString(3) | 171 reader.readNullTerminatedString(4); |
| 172 : reader.readNullTerminatedString(4); | |
| 173 | 172 |
| 174 if (frame.name == '') | 173 if (frame.name == '') |
| 175 return null; | 174 return null; |
| 176 | 175 |
| 177 this.vlog('Found frame ' + (frame.name) + ' at position ' + position ); | 176 this.vlog('Found frame ' + (frame.name) + ' at position ' + position); |
| 178 | 177 |
| 179 switch (majorVersion) { | 178 switch (majorVersion) { |
| 180 case 2: | 179 case 2: |
| 181 frame.size = Id3Parser.readUInt24_(reader); | 180 frame.size = Id3Parser.readUInt24_(reader); |
| 182 frame.headerSize = 6; | 181 frame.headerSize = 6; |
| 183 break; | 182 break; |
| 184 case 3: | 183 case 3: |
| 185 frame.size = reader.readScalar(4, false); | 184 frame.size = reader.readScalar(4, false); |
| 186 frame.headerSize = 10; | 185 frame.headerSize = 10; |
| 187 frame.flags = reader.readScalar(2, false); | 186 frame.flags = reader.readScalar(2, false); |
| 188 break; | 187 break; |
| 189 case 4: | 188 case 4: |
| 190 frame.size = Id3Parser.readSynchSafe_(reader, 4); | 189 frame.size = Id3Parser.readSynchSafe_(reader, 4); |
| 191 frame.headerSize = 10; | 190 frame.headerSize = 10; |
| 192 frame.flags = reader.readScalar(2, false); | 191 frame.flags = reader.readScalar(2, false); |
| 193 break; | 192 break; |
| 194 } | 193 } |
| 195 | 194 |
| 196 this.vlog('Found frame [' + frame.name + '] with size ['+frame.size+']'); | 195 this.vlog('Found frame [' + frame.name + '] with size [' + frame.size + ']'); |
| 197 | 196 |
| 198 if (Id3Parser.v2.HANDLERS[frame.name]) { | 197 if (Id3Parser.v2.HANDLERS[frame.name]) { |
| 199 Id3Parser.v2.HANDLERS[frame.name].call( | 198 Id3Parser.v2.HANDLERS[frame.name].call( |
| 200 this, | 199 this, |
| 201 reader, | 200 reader, |
| 202 majorVersion, | 201 majorVersion, |
| 203 frame, | 202 frame, |
| 204 reader.tell() + frame.size); | 203 reader.tell() + frame.size); |
| 205 } else if (frame.name.charAt(0) == 'T' || frame.name.charAt(0) == 'W') { | 204 } else if (frame.name.charAt(0) == 'T' || frame.name.charAt(0) == 'W') { |
| 206 this.readTextFrame_( | 205 this.readTextFrame_( |
| 207 reader, | 206 reader, |
| 208 majorVersion, | 207 majorVersion, |
| 209 frame, | 208 frame, |
| 210 reader.tell() + frame.size); | 209 reader.tell() + frame.size); |
| 211 } | 210 } |
| 212 | 211 |
| 213 reader.popSeek(); | 212 reader.popSeek(); |
| 214 | 213 |
| 215 reader.seek(frame.size + frame.headerSize, ByteReader.SEEK_CUR); | 214 reader.seek(frame.size + frame.headerSize, ByteReader.SEEK_CUR); |
| 216 | 215 |
| 217 return frame; | 216 return frame; |
| 218 }; | 217 }; |
| 219 | 218 |
| 220 Id3Parser.prototype.parse = function (file, metadata, callback, onError) { | 219 Id3Parser.prototype.parse = function(file, metadata, callback, onError) { |
| 221 var self = this; | 220 var self = this; |
| 222 | 221 |
| 223 this.log('Starting id3 parser for ' + file.name); | 222 this.log('Starting id3 parser for ' + file.name); |
| 224 | 223 |
| 225 var id3v1Parser = new FunctionSequence( | 224 var id3v1Parser = new FunctionSequence( |
| 226 'id3v1parser', | 225 'id3v1parser', |
| 227 [ | 226 [ |
| 228 /** | 227 /** |
| 229 * Reads last 128 bytes of file in bytebuffer, | 228 * Reads last 128 bytes of file in bytebuffer, |
| 230 * which passes further. | 229 * which passes further. |
| 231 * In last 128 bytes should be placed ID3v1 tag if available. | 230 * In last 128 bytes should be placed ID3v1 tag if available. |
| 232 * @param file - file which bytes to read. | 231 * @param file - file which bytes to read. |
| 233 */ | 232 */ |
| 234 function readTail(file) { | 233 function readTail(file) { |
| 235 util.readFileBytes(file, file.size - 128, file.size, | 234 util.readFileBytes(file, file.size - 128, file.size, |
| 236 this.nextStep, this.onError, this); | 235 this.nextStep, this.onError, this); |
| 237 }, | 236 }, |
| 238 | 237 |
| 239 /** | 238 /** |
| 240 * Attempts to extract ID3v1 tag from 128 bytes long ByteBuffer | 239 * Attempts to extract ID3v1 tag from 128 bytes long ByteBuffer |
| 241 * @param file file which tags are being extracted. | 240 * @param file file which tags are being extracted. |
| 242 * Could be used for logging purposes. | 241 * Could be used for logging purposes. |
| 243 * @param {ByteReader} reader ByteReader of 128 bytes. | 242 * @param {ByteReader} reader ByteReader of 128 bytes. |
| 244 */ | 243 */ |
| 245 function extractId3v1(file, reader) { | 244 function extractId3v1(file, reader) { |
| 246 if ( reader.readString(3) == 'TAG') { | 245 if (reader.readString(3) == 'TAG') { |
| 247 this.logger.vlog('id3v1 found'); | 246 this.logger.vlog('id3v1 found'); |
| 248 var id3v1 = metadata.id3v1 = {}; | 247 var id3v1 = metadata.id3v1 = {}; |
| 249 | 248 |
| 250 var title = reader.readNullTerminatedString(30).trim(); | 249 var title = reader.readNullTerminatedString(30).trim(); |
| 251 | 250 |
| 252 if (title.length > 0) { | 251 if (title.length > 0) { |
| 253 metadata.title = title; | 252 metadata.title = title; |
| 254 } | 253 } |
| 255 | 254 |
| 256 reader.seek(3 + 30, ByteReader.SEEK_BEG); | 255 reader.seek(3 + 30, ByteReader.SEEK_BEG); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 }, | 302 }, |
| 304 | 303 |
| 305 /** | 304 /** |
| 306 * Extracts all ID3v2 frames from given bytebuffer. | 305 * Extracts all ID3v2 frames from given bytebuffer. |
| 307 * @param file being parsed. | 306 * @param file being parsed. |
| 308 * @param {ByteReader} reader to use for metadata extraction. | 307 * @param {ByteReader} reader to use for metadata extraction. |
| 309 */ | 308 */ |
| 310 function extractFrames(file, reader) { | 309 function extractFrames(file, reader) { |
| 311 var id3v2 = metadata.id3v2; | 310 var id3v2 = metadata.id3v2; |
| 312 | 311 |
| 313 if ((id3v2.major > 2) | 312 if ((id3v2.major > 2) && |
| 314 && (id3v2.flags & Id3Parser.v2.FLAG_EXTENDED_HEADER != 0)) { | 313 (id3v2.flags & Id3Parser.v2.FLAG_EXTENDED_HEADER != 0)) { |
| 315 // Skip extended header if found | 314 // Skip extended header if found |
| 316 if (id3v2.major == 3) { | 315 if (id3v2.major == 3) { |
| 317 reader.seek(reader.readScalar(4, false) - 4); | 316 reader.seek(reader.readScalar(4, false) - 4); |
| 318 } else if (id3v2.major == 4) { | 317 } else if (id3v2.major == 4) { |
| 319 reader.seek(Id3Parser.readSynchSafe_(reader, 4) - 4); | 318 reader.seek(Id3Parser.readSynchSafe_(reader, 4) - 4); |
| 320 } | 319 } |
| 321 } | 320 } |
| 322 | 321 |
| 323 var frame; | 322 var frame; |
| 324 | 323 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 break; | 363 break; |
| 365 } | 364 } |
| 366 } | 365 } |
| 367 } | 366 } |
| 368 | 367 |
| 369 extract('album', 'TALB', 'TAL'); | 368 extract('album', 'TALB', 'TAL'); |
| 370 extract('title', 'TIT2', 'TT2'); | 369 extract('title', 'TIT2', 'TT2'); |
| 371 extract('artist', 'TPE1', 'TP1'); | 370 extract('artist', 'TPE1', 'TP1'); |
| 372 | 371 |
| 373 metadata.description.sort(function(a, b) { | 372 metadata.description.sort(function(a, b) { |
| 374 return Id3Parser.METADATA_ORDER.indexOf(a.key)- | 373 return Id3Parser.METADATA_ORDER.indexOf(a.key) - |
| 375 Id3Parser.METADATA_ORDER.indexOf(b.key); | 374 Id3Parser.METADATA_ORDER.indexOf(b.key); |
| 376 }); | 375 }); |
| 377 this.nextStep(); | 376 this.nextStep(); |
| 378 } | 377 } |
| 379 ], | 378 ], |
| 380 this | 379 this |
| 381 ); | 380 ); |
| 382 | 381 |
| 383 var metadataParser = new FunctionParallel( | 382 var metadataParser = new FunctionParallel( |
| 384 'mp3metadataParser', | 383 'mp3metadataParser', |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 /** | 431 /** |
| 433 * id3v1 constants | 432 * id3v1 constants |
| 434 */ | 433 */ |
| 435 Id3Parser.v1 = { | 434 Id3Parser.v1 = { |
| 436 /** | 435 /** |
| 437 * Genres list as described in id3 documentation. We aren't going to | 436 * Genres list as described in id3 documentation. We aren't going to |
| 438 * localize this list, because at least in Russian (and I think most | 437 * localize this list, because at least in Russian (and I think most |
| 439 * other languages), translation exists at least fo 10% and most time | 438 * other languages), translation exists at least fo 10% and most time |
| 440 * translation would degrade to transliteration. | 439 * translation would degrade to transliteration. |
| 441 */ | 440 */ |
| 442 GENRES : [ | 441 GENRES: [ |
| 443 'Blues', | 442 'Blues', |
| 444 'Classic Rock', | 443 'Classic Rock', |
| 445 'Country', | 444 'Country', |
| 446 'Dance', | 445 'Dance', |
| 447 'Disco', | 446 'Disco', |
| 448 'Funk', | 447 'Funk', |
| 449 'Grunge', | 448 'Grunge', |
| 450 'Hip-Hop', | 449 'Hip-Hop', |
| 451 'Jazz', | 450 'Jazz', |
| 452 'Metal', | 451 'Metal', |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 597 Id3Parser.v2 = { | 596 Id3Parser.v2 = { |
| 598 FLAG_EXTENDED_HEADER: 1 << 5, | 597 FLAG_EXTENDED_HEADER: 1 << 5, |
| 599 | 598 |
| 600 ENCODING: { | 599 ENCODING: { |
| 601 /** | 600 /** |
| 602 * ISO-8859-1 [ISO-8859-1]. Terminated with $00. | 601 * ISO-8859-1 [ISO-8859-1]. Terminated with $00. |
| 603 * | 602 * |
| 604 * @const | 603 * @const |
| 605 * @type {int} | 604 * @type {int} |
| 606 */ | 605 */ |
| 607 ISO_8859_1 : 0, | 606 ISO_8859_1: 0, |
| 608 | 607 |
| 609 | 608 |
| 610 /** | 609 /** |
| 611 * [UTF-16] encoded Unicode [UNICODE] with BOM. All | 610 * [UTF-16] encoded Unicode [UNICODE] with BOM. All |
| 612 * strings in the same frame SHALL have the same byteorder. | 611 * strings in the same frame SHALL have the same byteorder. |
| 613 * Terminated with $00 00. | 612 * Terminated with $00 00. |
| 614 * | 613 * |
| 615 * @const | 614 * @const |
| 616 * @type {int} | 615 * @type {int} |
| 617 */ | 616 */ |
| 618 UTF_16 : 1, | 617 UTF_16: 1, |
| 619 | 618 |
| 620 /** | 619 /** |
| 621 * UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM. | 620 * UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM. |
| 622 * Terminated with $00 00. | 621 * Terminated with $00 00. |
| 623 * | 622 * |
| 624 * @const | 623 * @const |
| 625 * @type {int} | 624 * @type {int} |
| 626 */ | 625 */ |
| 627 UTF_16BE : 2, | 626 UTF_16BE: 2, |
| 628 | 627 |
| 629 /** | 628 /** |
| 630 * UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00. | 629 * UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00. |
| 631 * | 630 * |
| 632 * @const | 631 * @const |
| 633 * @type {int} | 632 * @type {int} |
| 634 */ | 633 */ |
| 635 UTF_8 : 3 | 634 UTF_8: 3 |
| 636 }, | 635 }, |
| 637 HANDLERS: { | 636 HANDLERS: { |
| 638 //User defined text information frame | 637 //User defined text information frame |
| 639 TXX: Id3Parser.prototype.readUserDefinedTextFrame_, | 638 TXX: Id3Parser.prototype.readUserDefinedTextFrame_, |
| 640 //User defined URL link frame | 639 //User defined URL link frame |
| 641 WXX: Id3Parser.prototype.readUserDefinedTextFrame_, | 640 WXX: Id3Parser.prototype.readUserDefinedTextFrame_, |
| 642 | 641 |
| 643 //User defined text information frame | 642 //User defined text information frame |
| 644 TXXX: Id3Parser.prototype.readUserDefinedTextFrame_, | 643 TXXX: Id3Parser.prototype.readUserDefinedTextFrame_, |
| 645 | 644 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 670 TYER: 'ID3_YEAR', | 669 TYER: 'ID3_YEAR', |
| 671 WCOP: 'ID3_COPYRIGHT', | 670 WCOP: 'ID3_COPYRIGHT', |
| 672 WOAF: 'ID3_OFFICIAL_AUDIO_FILE_WEBPAGE', | 671 WOAF: 'ID3_OFFICIAL_AUDIO_FILE_WEBPAGE', |
| 673 WOAR: 'ID3_OFFICIAL_ARTIST', | 672 WOAR: 'ID3_OFFICIAL_ARTIST', |
| 674 WOAS: 'ID3_OFFICIAL_AUDIO_SOURCE_WEBPAGE', | 673 WOAS: 'ID3_OFFICIAL_AUDIO_SOURCE_WEBPAGE', |
| 675 WPUB: 'ID3_PUBLISHERS_OFFICIAL_WEBPAGE' | 674 WPUB: 'ID3_PUBLISHERS_OFFICIAL_WEBPAGE' |
| 676 } | 675 } |
| 677 }; | 676 }; |
| 678 | 677 |
| 679 MetadataDispatcher.registerParserClass(Id3Parser); | 678 MetadataDispatcher.registerParserClass(Id3Parser); |
| OLD | NEW |