| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 'use strict'; | |
| 6 | |
| 7 importScripts('function_sequence.js'); | |
| 8 importScripts('function_parallel.js'); | |
| 9 | |
| 10 function Id3Parser(parent) { | |
| 11 MetadataParser.call(this, parent, 'id3', /\.(mp3)$/i); | |
| 12 } | |
| 13 | |
| 14 Id3Parser.prototype = {__proto__: MetadataParser.prototype}; | |
| 15 | |
| 16 /** | |
| 17 * Reads synchsafe integer. | |
| 18 * 'SynchSafe' term is taken from id3 documentation. | |
| 19 * | |
| 20 * @param {ByteReader} reader - reader to use. | |
| 21 * @param {number} length - bytes to read. | |
| 22 * @return {number} // TODO(JSDOC). | |
| 23 * @private | |
| 24 */ | |
| 25 Id3Parser.readSynchSafe_ = function(reader, length) { | |
| 26 var rv = 0; | |
| 27 | |
| 28 switch (length) { | |
| 29 case 4: | |
| 30 rv = reader.readScalar(1, false) << 21; | |
| 31 case 3: | |
| 32 rv |= reader.readScalar(1, false) << 14; | |
| 33 case 2: | |
| 34 rv |= reader.readScalar(1, false) << 7; | |
| 35 case 1: | |
| 36 rv |= reader.readScalar(1, false); | |
| 37 } | |
| 38 | |
| 39 return rv; | |
| 40 }; | |
| 41 | |
| 42 /** | |
| 43 * Reads 3bytes integer. | |
| 44 * | |
| 45 * @param {ByteReader} reader - reader to use. | |
| 46 * @return {number} // TODO(JSDOC). | |
| 47 * @private | |
| 48 */ | |
| 49 Id3Parser.readUInt24_ = function(reader) { | |
| 50 return reader.readScalar(2, false) << 16 | reader.readScalar(1, false); | |
| 51 }; | |
| 52 | |
| 53 /** | |
| 54 * Reads string from reader with specified encoding | |
| 55 * | |
| 56 * @param {ByteReader} reader reader to use. | |
| 57 * @param {number} encoding string encoding. | |
| 58 * @param {number} size maximum string size. Actual result may be shorter. | |
| 59 * @return {string} // TODO(JSDOC). | |
| 60 * @private | |
| 61 */ | |
| 62 Id3Parser.prototype.readString_ = function(reader, encoding, size) { | |
| 63 switch (encoding) { | |
| 64 case Id3Parser.v2.ENCODING.ISO_8859_1: | |
| 65 return reader.readNullTerminatedString(size); | |
| 66 | |
| 67 case Id3Parser.v2.ENCODING.UTF_16: | |
| 68 return reader.readNullTerminatedStringUTF16(true, size); | |
| 69 | |
| 70 case Id3Parser.v2.ENCODING.UTF_16BE: | |
| 71 return reader.readNullTerminatedStringUTF16(false, size); | |
| 72 | |
| 73 case Id3Parser.v2.ENCODING.UTF_8: | |
| 74 // TODO: implement UTF_8. | |
| 75 this.log('UTF8 encoding not supported, used ISO_8859_1 instead'); | |
| 76 return reader.readNullTerminatedString(size); | |
| 77 | |
| 78 default: { | |
| 79 this.log('Unsupported encoding in ID3 tag: ' + encoding); | |
| 80 return ''; | |
| 81 } | |
| 82 } | |
| 83 }; | |
| 84 | |
| 85 /** | |
| 86 * Reads text frame from reader. | |
| 87 * | |
| 88 * @param {ByteReader} reader reader to use. | |
| 89 * @param {number} majorVersion major id3 version to use. | |
| 90 * @param {Object} frame frame so store data at. | |
| 91 * @param {number} end frame end position in reader. | |
| 92 * @private | |
| 93 */ | |
| 94 Id3Parser.prototype.readTextFrame_ = function(reader, | |
| 95 majorVersion, | |
| 96 frame, | |
| 97 end) { | |
| 98 frame.encoding = reader.readScalar(1, false, end); | |
| 99 frame.value = this.readString_(reader, frame.encoding, end - reader.tell()); | |
| 100 }; | |
| 101 | |
| 102 /** | |
| 103 * Reads user defined text frame from reader. | |
| 104 * | |
| 105 * @param {ByteReader} reader reader to use. | |
| 106 * @param {number} majorVersion major id3 version to use. | |
| 107 * @param {Object} frame frame so store data at. | |
| 108 * @param {number} end frame end position in reader. | |
| 109 * @private | |
| 110 */ | |
| 111 Id3Parser.prototype.readUserDefinedTextFrame_ = function(reader, | |
| 112 majorVersion, | |
| 113 frame, | |
| 114 end) { | |
| 115 frame.encoding = reader.readScalar(1, false, end); | |
| 116 | |
| 117 frame.description = this.readString_( | |
| 118 reader, | |
| 119 frame.encoding, | |
| 120 end - reader.tell()); | |
| 121 | |
| 122 frame.value = this.readString_( | |
| 123 reader, | |
| 124 frame.encoding, | |
| 125 end - reader.tell()); | |
| 126 }; | |
| 127 | |
| 128 /** | |
| 129 * @param {ByteReader} reader Reader to use. | |
| 130 * @param {number} majorVersion Major id3 version to use. | |
| 131 * @param {Object} frame Frame so store data at. | |
| 132 * @param {number} end Frame end position in reader. | |
| 133 * @private | |
| 134 */ | |
| 135 Id3Parser.prototype.readPIC_ = function(reader, majorVersion, frame, end) { | |
| 136 frame.encoding = reader.readScalar(1, false, end); | |
| 137 frame.format = reader.readNullTerminatedString(3, end - reader.tell()); | |
| 138 frame.pictureType = reader.readScalar(1, false, end); | |
| 139 frame.description = this.readString_(reader, | |
| 140 frame.encoding, | |
| 141 end - reader.tell()); | |
| 142 | |
| 143 | |
| 144 if (frame.format == '-->') { | |
| 145 frame.imageUrl = reader.readNullTerminatedString(end - reader.tell()); | |
| 146 } else { | |
| 147 frame.imageUrl = reader.readImage(end - reader.tell()); | |
| 148 } | |
| 149 }; | |
| 150 | |
| 151 /** | |
| 152 * @param {ByteReader} reader Reader to use. | |
| 153 * @param {number} majorVersion Major id3 version to use. | |
| 154 * @param {Object} frame Frame so store data at. | |
| 155 * @param {number} end Frame end position in reader. | |
| 156 * @private | |
| 157 */ | |
| 158 Id3Parser.prototype.readAPIC_ = function(reader, majorVersion, frame, end) { | |
| 159 this.vlog('Extracting picture'); | |
| 160 frame.encoding = reader.readScalar(1, false, end); | |
| 161 frame.mime = reader.readNullTerminatedString(end - reader.tell()); | |
| 162 frame.pictureType = reader.readScalar(1, false, end); | |
| 163 frame.description = this.readString_( | |
| 164 reader, | |
| 165 frame.encoding, | |
| 166 end - reader.tell()); | |
| 167 | |
| 168 if (frame.mime == '-->') { | |
| 169 frame.imageUrl = reader.readNullTerminatedString(end - reader.tell()); | |
| 170 } else { | |
| 171 frame.imageUrl = reader.readImage(end - reader.tell()); | |
| 172 } | |
| 173 }; | |
| 174 | |
| 175 /** | |
| 176 * Reads string from reader with specified encoding | |
| 177 * | |
| 178 * @param {ByteReader} reader reader to use. | |
| 179 * @param {number} majorVersion // TODO(JSDOC). | |
| 180 * @return {Object} frame read. | |
| 181 * @private | |
| 182 */ | |
| 183 Id3Parser.prototype.readFrame_ = function(reader, majorVersion) { | |
| 184 if (reader.eof()) | |
| 185 return null; | |
| 186 | |
| 187 var frame = {}; | |
| 188 | |
| 189 reader.pushSeek(reader.tell(), ByteReader.SEEK_BEG); | |
| 190 | |
| 191 var position = reader.tell(); | |
| 192 | |
| 193 frame.name = (majorVersion == 2) ? reader.readNullTerminatedString(3) : | |
| 194 reader.readNullTerminatedString(4); | |
| 195 | |
| 196 if (frame.name == '') | |
| 197 return null; | |
| 198 | |
| 199 this.vlog('Found frame ' + (frame.name) + ' at position ' + position); | |
| 200 | |
| 201 switch (majorVersion) { | |
| 202 case 2: | |
| 203 frame.size = Id3Parser.readUInt24_(reader); | |
| 204 frame.headerSize = 6; | |
| 205 break; | |
| 206 case 3: | |
| 207 frame.size = reader.readScalar(4, false); | |
| 208 frame.headerSize = 10; | |
| 209 frame.flags = reader.readScalar(2, false); | |
| 210 break; | |
| 211 case 4: | |
| 212 frame.size = Id3Parser.readSynchSafe_(reader, 4); | |
| 213 frame.headerSize = 10; | |
| 214 frame.flags = reader.readScalar(2, false); | |
| 215 break; | |
| 216 } | |
| 217 | |
| 218 this.vlog('Found frame [' + frame.name + '] with size [' + frame.size + ']'); | |
| 219 | |
| 220 if (Id3Parser.v2.HANDLERS[frame.name]) { | |
| 221 Id3Parser.v2.HANDLERS[frame.name].call( | |
| 222 this, | |
| 223 reader, | |
| 224 majorVersion, | |
| 225 frame, | |
| 226 reader.tell() + frame.size); | |
| 227 } else if (frame.name.charAt(0) == 'T' || frame.name.charAt(0) == 'W') { | |
| 228 this.readTextFrame_( | |
| 229 reader, | |
| 230 majorVersion, | |
| 231 frame, | |
| 232 reader.tell() + frame.size); | |
| 233 } | |
| 234 | |
| 235 reader.popSeek(); | |
| 236 | |
| 237 reader.seek(frame.size + frame.headerSize, ByteReader.SEEK_CUR); | |
| 238 | |
| 239 return frame; | |
| 240 }; | |
| 241 | |
| 242 /** | |
| 243 * @param {File} file // TODO(JSDOC). | |
| 244 * @param {Object} metadata // TODO(JSDOC). | |
| 245 * @param {function(Object)} callback // TODO(JSDOC). | |
| 246 * @param {function(etring)} onError // TODO(JSDOC). | |
| 247 */ | |
| 248 Id3Parser.prototype.parse = function(file, metadata, callback, onError) { | |
| 249 var self = this; | |
| 250 | |
| 251 this.log('Starting id3 parser for ' + file.name); | |
| 252 | |
| 253 var id3v1Parser = new FunctionSequence( | |
| 254 'id3v1parser', | |
| 255 [ | |
| 256 /** | |
| 257 * Reads last 128 bytes of file in bytebuffer, | |
| 258 * which passes further. | |
| 259 * In last 128 bytes should be placed ID3v1 tag if available. | |
| 260 * @param {File} file File which bytes to read. | |
| 261 */ | |
| 262 function readTail(file) { | |
| 263 util.readFileBytes(file, file.size - 128, file.size, | |
| 264 this.nextStep, this.onError, this); | |
| 265 }, | |
| 266 | |
| 267 /** | |
| 268 * Attempts to extract ID3v1 tag from 128 bytes long ByteBuffer | |
| 269 * @param {File} file File which tags are being extracted. Could be used | |
| 270 * for logging purposes. | |
| 271 * @param {ByteReader} reader ByteReader of 128 bytes. | |
| 272 */ | |
| 273 function extractId3v1(file, reader) { | |
| 274 if (reader.readString(3) == 'TAG') { | |
| 275 this.logger.vlog('id3v1 found'); | |
| 276 var id3v1 = metadata.id3v1 = {}; | |
| 277 | |
| 278 var title = reader.readNullTerminatedString(30).trim(); | |
| 279 | |
| 280 if (title.length > 0) { | |
| 281 metadata.title = title; | |
| 282 } | |
| 283 | |
| 284 reader.seek(3 + 30, ByteReader.SEEK_BEG); | |
| 285 | |
| 286 var artist = reader.readNullTerminatedString(30).trim(); | |
| 287 if (artist.length > 0) { | |
| 288 metadata.artist = artist; | |
| 289 } | |
| 290 | |
| 291 reader.seek(3 + 30 + 30, ByteReader.SEEK_BEG); | |
| 292 | |
| 293 var album = reader.readNullTerminatedString(30).trim(); | |
| 294 if (album.length > 0) { | |
| 295 metadata.album = album; | |
| 296 } | |
| 297 } | |
| 298 this.nextStep(); | |
| 299 } | |
| 300 ], | |
| 301 this | |
| 302 ); | |
| 303 | |
| 304 var id3v2Parser = new FunctionSequence( | |
| 305 'id3v2parser', | |
| 306 [ | |
| 307 function readHead(file) { | |
| 308 util.readFileBytes(file, 0, 10, this.nextStep, this.onError, | |
| 309 this); | |
| 310 }, | |
| 311 | |
| 312 /** | |
| 313 * Check if passed array of 10 bytes contains ID3 header. | |
| 314 * @param {File} file File to check and continue reading if ID3 | |
| 315 * metadata found. | |
| 316 * @param {ByteReader} reader Reader to fill with stream bytes. | |
| 317 */ | |
| 318 function checkId3v2(file, reader) { | |
| 319 if (reader.readString(3) == 'ID3') { | |
| 320 this.logger.vlog('id3v2 found'); | |
| 321 var id3v2 = metadata.id3v2 = {}; | |
| 322 id3v2.major = reader.readScalar(1, false); | |
| 323 id3v2.minor = reader.readScalar(1, false); | |
| 324 id3v2.flags = reader.readScalar(1, false); | |
| 325 id3v2.size = Id3Parser.readSynchSafe_(reader, 4); | |
| 326 | |
| 327 util.readFileBytes(file, 10, 10 + id3v2.size, this.nextStep, | |
| 328 this.onError, this); | |
| 329 } else { | |
| 330 this.finish(); | |
| 331 } | |
| 332 }, | |
| 333 | |
| 334 /** | |
| 335 * Extracts all ID3v2 frames from given bytebuffer. | |
| 336 * @param {File} file File being parsed. | |
| 337 * @param {ByteReader} reader Reader to use for metadata extraction. | |
| 338 */ | |
| 339 function extractFrames(file, reader) { | |
| 340 var id3v2 = metadata.id3v2; | |
| 341 | |
| 342 if ((id3v2.major > 2) && | |
| 343 (id3v2.flags & Id3Parser.v2.FLAG_EXTENDED_HEADER != 0)) { | |
| 344 // Skip extended header if found | |
| 345 if (id3v2.major == 3) { | |
| 346 reader.seek(reader.readScalar(4, false) - 4); | |
| 347 } else if (id3v2.major == 4) { | |
| 348 reader.seek(Id3Parser.readSynchSafe_(reader, 4) - 4); | |
| 349 } | |
| 350 } | |
| 351 | |
| 352 var frame; | |
| 353 | |
| 354 while (frame = self.readFrame_(reader, id3v2.major)) { | |
| 355 metadata.id3v2[frame.name] = frame; | |
| 356 } | |
| 357 | |
| 358 this.nextStep(); | |
| 359 }, | |
| 360 | |
| 361 /** | |
| 362 * Adds 'description' object to metadata. | |
| 363 * 'description' used to unify different parsers and make | |
| 364 * metadata parser-aware. | |
| 365 * Description is array if value-type pairs. Type should be used | |
| 366 * to properly format value before displaying to user. | |
| 367 */ | |
| 368 function prepareDescription() { | |
| 369 var id3v2 = metadata.id3v2; | |
| 370 | |
| 371 if (id3v2['APIC']) | |
| 372 metadata.thumbnailURL = id3v2['APIC'].imageUrl; | |
| 373 else if (id3v2['PIC']) | |
| 374 metadata.thumbnailURL = id3v2['PIC'].imageUrl; | |
| 375 | |
| 376 metadata.description = []; | |
| 377 | |
| 378 for (var key in id3v2) { | |
| 379 if (typeof(Id3Parser.v2.MAPPERS[key]) != 'undefined' && | |
| 380 id3v2[key].value.trim().length > 0) { | |
| 381 metadata.description.push({ | |
| 382 key: Id3Parser.v2.MAPPERS[key], | |
| 383 value: id3v2[key].value.trim() | |
| 384 }); | |
| 385 } | |
| 386 } | |
| 387 | |
| 388 function extract(propName, tags) { | |
| 389 for (var i = 1; i != arguments.length; i++) { | |
| 390 var tag = id3v2[arguments[i]]; | |
| 391 if (tag && tag.value) { | |
| 392 metadata[propName] = tag.value; | |
| 393 break; | |
| 394 } | |
| 395 } | |
| 396 } | |
| 397 | |
| 398 extract('album', 'TALB', 'TAL'); | |
| 399 extract('title', 'TIT2', 'TT2'); | |
| 400 extract('artist', 'TPE1', 'TP1'); | |
| 401 | |
| 402 metadata.description.sort(function(a, b) { | |
| 403 return Id3Parser.METADATA_ORDER.indexOf(a.key) - | |
| 404 Id3Parser.METADATA_ORDER.indexOf(b.key); | |
| 405 }); | |
| 406 this.nextStep(); | |
| 407 } | |
| 408 ], | |
| 409 this | |
| 410 ); | |
| 411 | |
| 412 var metadataParser = new FunctionParallel( | |
| 413 'mp3metadataParser', | |
| 414 [id3v1Parser, id3v2Parser], | |
| 415 this, | |
| 416 function() { | |
| 417 callback.call(null, metadata); | |
| 418 }, | |
| 419 onError | |
| 420 ); | |
| 421 | |
| 422 id3v1Parser.setCallback(metadataParser.nextStep); | |
| 423 id3v2Parser.setCallback(metadataParser.nextStep); | |
| 424 | |
| 425 id3v1Parser.setFailureCallback(metadataParser.onError); | |
| 426 id3v2Parser.setFailureCallback(metadataParser.onError); | |
| 427 | |
| 428 this.vlog('Passed argument : ' + file); | |
| 429 | |
| 430 metadataParser.start(file); | |
| 431 }; | |
| 432 | |
| 433 | |
| 434 /** | |
| 435 * Metadata order to use for metadata generation | |
| 436 */ | |
| 437 Id3Parser.METADATA_ORDER = [ | |
| 438 'ID3_TITLE', | |
| 439 'ID3_LEAD_PERFORMER', | |
| 440 'ID3_YEAR', | |
| 441 'ID3_ALBUM', | |
| 442 'ID3_TRACK_NUMBER', | |
| 443 'ID3_BPM', | |
| 444 'ID3_COMPOSER', | |
| 445 'ID3_DATE', | |
| 446 'ID3_PLAYLIST_DELAY', | |
| 447 'ID3_LYRICIST', | |
| 448 'ID3_FILE_TYPE', | |
| 449 'ID3_TIME', | |
| 450 'ID3_LENGTH', | |
| 451 'ID3_FILE_OWNER', | |
| 452 'ID3_BAND', | |
| 453 'ID3_COPYRIGHT', | |
| 454 'ID3_OFFICIAL_AUDIO_FILE_WEBPAGE', | |
| 455 'ID3_OFFICIAL_ARTIST', | |
| 456 'ID3_OFFICIAL_AUDIO_SOURCE_WEBPAGE', | |
| 457 'ID3_PUBLISHERS_OFFICIAL_WEBPAGE' | |
| 458 ]; | |
| 459 | |
| 460 | |
| 461 /** | |
| 462 * id3v1 constants | |
| 463 */ | |
| 464 Id3Parser.v1 = { | |
| 465 /** | |
| 466 * Genres list as described in id3 documentation. We aren't going to | |
| 467 * localize this list, because at least in Russian (and I think most | |
| 468 * other languages), translation exists at least for 10% and most time | |
| 469 * translation would degrade to transliteration. | |
| 470 */ | |
| 471 GENRES: [ | |
| 472 'Blues', | |
| 473 'Classic Rock', | |
| 474 'Country', | |
| 475 'Dance', | |
| 476 'Disco', | |
| 477 'Funk', | |
| 478 'Grunge', | |
| 479 'Hip-Hop', | |
| 480 'Jazz', | |
| 481 'Metal', | |
| 482 'New Age', | |
| 483 'Oldies', | |
| 484 'Other', | |
| 485 'Pop', | |
| 486 'R&B', | |
| 487 'Rap', | |
| 488 'Reggae', | |
| 489 'Rock', | |
| 490 'Techno', | |
| 491 'Industrial', | |
| 492 'Alternative', | |
| 493 'Ska', | |
| 494 'Death Metal', | |
| 495 'Pranks', | |
| 496 'Soundtrack', | |
| 497 'Euro-Techno', | |
| 498 'Ambient', | |
| 499 'Trip-Hop', | |
| 500 'Vocal', | |
| 501 'Jazz+Funk', | |
| 502 'Fusion', | |
| 503 'Trance', | |
| 504 'Classical', | |
| 505 'Instrumental', | |
| 506 'Acid', | |
| 507 'House', | |
| 508 'Game', | |
| 509 'Sound Clip', | |
| 510 'Gospel', | |
| 511 'Noise', | |
| 512 'AlternRock', | |
| 513 'Bass', | |
| 514 'Soul', | |
| 515 'Punk', | |
| 516 'Space', | |
| 517 'Meditative', | |
| 518 'Instrumental Pop', | |
| 519 'Instrumental Rock', | |
| 520 'Ethnic', | |
| 521 'Gothic', | |
| 522 'Darkwave', | |
| 523 'Techno-Industrial', | |
| 524 'Electronic', | |
| 525 'Pop-Folk', | |
| 526 'Eurodance', | |
| 527 'Dream', | |
| 528 'Southern Rock', | |
| 529 'Comedy', | |
| 530 'Cult', | |
| 531 'Gangsta', | |
| 532 'Top 40', | |
| 533 'Christian Rap', | |
| 534 'Pop/Funk', | |
| 535 'Jungle', | |
| 536 'Native American', | |
| 537 'Cabaret', | |
| 538 'New Wave', | |
| 539 'Psychadelic', | |
| 540 'Rave', | |
| 541 'Showtunes', | |
| 542 'Trailer', | |
| 543 'Lo-Fi', | |
| 544 'Tribal', | |
| 545 'Acid Punk', | |
| 546 'Acid Jazz', | |
| 547 'Polka', | |
| 548 'Retro', | |
| 549 'Musical', | |
| 550 'Rock & Roll', | |
| 551 'Hard Rock', | |
| 552 'Folk', | |
| 553 'Folk-Rock', | |
| 554 'National Folk', | |
| 555 'Swing', | |
| 556 'Fast Fusion', | |
| 557 'Bebob', | |
| 558 'Latin', | |
| 559 'Revival', | |
| 560 'Celtic', | |
| 561 'Bluegrass', | |
| 562 'Avantgarde', | |
| 563 'Gothic Rock', | |
| 564 'Progressive Rock', | |
| 565 'Psychedelic Rock', | |
| 566 'Symphonic Rock', | |
| 567 'Slow Rock', | |
| 568 'Big Band', | |
| 569 'Chorus', | |
| 570 'Easy Listening', | |
| 571 'Acoustic', | |
| 572 'Humour', | |
| 573 'Speech', | |
| 574 'Chanson', | |
| 575 'Opera', | |
| 576 'Chamber Music', | |
| 577 'Sonata', | |
| 578 'Symphony', | |
| 579 'Booty Bass', | |
| 580 'Primus', | |
| 581 'Porn Groove', | |
| 582 'Satire', | |
| 583 'Slow Jam', | |
| 584 'Club', | |
| 585 'Tango', | |
| 586 'Samba', | |
| 587 'Folklore', | |
| 588 'Ballad', | |
| 589 'Power Ballad', | |
| 590 'Rhythmic Soul', | |
| 591 'Freestyle', | |
| 592 'Duet', | |
| 593 'Punk Rock', | |
| 594 'Drum Solo', | |
| 595 'A capella', | |
| 596 'Euro-House', | |
| 597 'Dance Hall', | |
| 598 'Goa', | |
| 599 'Drum & Bass', | |
| 600 'Club-House', | |
| 601 'Hardcore', | |
| 602 'Terror', | |
| 603 'Indie', | |
| 604 'BritPop', | |
| 605 'Negerpunk', | |
| 606 'Polsk Punk', | |
| 607 'Beat', | |
| 608 'Christian Gangsta Rap', | |
| 609 'Heavy Metal', | |
| 610 'Black Metal', | |
| 611 'Crossover', | |
| 612 'Contemporary Christian', | |
| 613 'Christian Rock', | |
| 614 'Merengue', | |
| 615 'Salsa', | |
| 616 'Thrash Metal', | |
| 617 'Anime', | |
| 618 'Jpop', | |
| 619 'Synthpop' | |
| 620 ] | |
| 621 }; | |
| 622 | |
| 623 /** | |
| 624 * id3v2 constants | |
| 625 */ | |
| 626 Id3Parser.v2 = { | |
| 627 FLAG_EXTENDED_HEADER: 1 << 5, | |
| 628 | |
| 629 ENCODING: { | |
| 630 /** | |
| 631 * ISO-8859-1 [ISO-8859-1]. Terminated with $00. | |
| 632 * | |
| 633 * @const | |
| 634 * @type {number} | |
| 635 */ | |
| 636 ISO_8859_1: 0, | |
| 637 | |
| 638 | |
| 639 /** | |
| 640 * [UTF-16] encoded Unicode [UNICODE] with BOM. All | |
| 641 * strings in the same frame SHALL have the same byteorder. | |
| 642 * Terminated with $00 00. | |
| 643 * | |
| 644 * @const | |
| 645 * @type {number} | |
| 646 */ | |
| 647 UTF_16: 1, | |
| 648 | |
| 649 /** | |
| 650 * UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM. | |
| 651 * Terminated with $00 00. | |
| 652 * | |
| 653 * @const | |
| 654 * @type {number} | |
| 655 */ | |
| 656 UTF_16BE: 2, | |
| 657 | |
| 658 /** | |
| 659 * UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00. | |
| 660 * | |
| 661 * @const | |
| 662 * @type {number} | |
| 663 */ | |
| 664 UTF_8: 3 | |
| 665 }, | |
| 666 HANDLERS: { | |
| 667 //User defined text information frame | |
| 668 TXX: Id3Parser.prototype.readUserDefinedTextFrame_, | |
| 669 //User defined URL link frame | |
| 670 WXX: Id3Parser.prototype.readUserDefinedTextFrame_, | |
| 671 | |
| 672 //User defined text information frame | |
| 673 TXXX: Id3Parser.prototype.readUserDefinedTextFrame_, | |
| 674 | |
| 675 //User defined URL link frame | |
| 676 WXXX: Id3Parser.prototype.readUserDefinedTextFrame_, | |
| 677 | |
| 678 //User attached image | |
| 679 PIC: Id3Parser.prototype.readPIC_, | |
| 680 | |
| 681 //User attached image | |
| 682 APIC: Id3Parser.prototype.readAPIC_ | |
| 683 }, | |
| 684 MAPPERS: { | |
| 685 TALB: 'ID3_ALBUM', | |
| 686 TBPM: 'ID3_BPM', | |
| 687 TCOM: 'ID3_COMPOSER', | |
| 688 TDAT: 'ID3_DATE', | |
| 689 TDLY: 'ID3_PLAYLIST_DELAY', | |
| 690 TEXT: 'ID3_LYRICIST', | |
| 691 TFLT: 'ID3_FILE_TYPE', | |
| 692 TIME: 'ID3_TIME', | |
| 693 TIT2: 'ID3_TITLE', | |
| 694 TLEN: 'ID3_LENGTH', | |
| 695 TOWN: 'ID3_FILE_OWNER', | |
| 696 TPE1: 'ID3_LEAD_PERFORMER', | |
| 697 TPE2: 'ID3_BAND', | |
| 698 TRCK: 'ID3_TRACK_NUMBER', | |
| 699 TYER: 'ID3_YEAR', | |
| 700 WCOP: 'ID3_COPYRIGHT', | |
| 701 WOAF: 'ID3_OFFICIAL_AUDIO_FILE_WEBPAGE', | |
| 702 WOAR: 'ID3_OFFICIAL_ARTIST', | |
| 703 WOAS: 'ID3_OFFICIAL_AUDIO_SOURCE_WEBPAGE', | |
| 704 WPUB: 'ID3_PUBLISHERS_OFFICIAL_WEBPAGE' | |
| 705 } | |
| 706 }; | |
| 707 | |
| 708 MetadataDispatcher.registerParserClass(Id3Parser); | |
| OLD | NEW |