Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
42 lines
No EOL
10 KiB
JavaScript
42 lines
No EOL
10 KiB
JavaScript
;'use strict';var BlobView=(function(){function fail(msg){throw Error(msg);}
|
|
var decoderCache={};function getDecoder(encoding){if(encoding in decoderCache){return decoderCache[encoding];}
|
|
var decoder=decoderCache[encoding]=new TextDecoder(encoding);return decoder;}
|
|
function BlobView(blob,sliceOffset,sliceLength,slice,viewOffset,viewLength,littleEndian)
|
|
{this.blob=blob;this.sliceOffset=sliceOffset;this.sliceLength=sliceLength;this.slice=slice;this.viewOffset=viewOffset;this.viewLength=viewLength;this.littleEndian=littleEndian;this.view=new DataView(slice,viewOffset,viewLength);this.buffer=slice;this.byteLength=viewLength;this.byteOffset=viewOffset;this.index=0;}
|
|
BlobView.get=function(blob,offset,length,callback,littleEndian){if(offset<0){fail('negative offset');}
|
|
if(length<0){fail('negative length');}
|
|
if(offset>blob.size){fail('offset larger than blob size');}
|
|
if(offset+length>blob.size){length=blob.size-offset;}
|
|
var slice=blob.slice(offset,offset+length);var reader=new FileReader();reader.readAsArrayBuffer(slice);reader.onloadend=function(){var result=null;if(reader.result){result=new BlobView(blob,offset,length,reader.result,0,length,littleEndian||false);}
|
|
callback(result,reader.error);};};BlobView.getFromArrayBuffer=function(buffer,offset,length,littleEndian){return new BlobView(null,offset,length,buffer,offset,length,littleEndian);};BlobView.prototype={constructor:BlobView,getMore:function(offset,length,callback){if(!this.blob){fail('no blob backing this BlobView');}
|
|
if(offset>=this.sliceOffset&&offset+length<=this.sliceOffset+this.sliceLength){callback(new BlobView(this.blob,this.sliceOffset,this.sliceLength,this.slice,offset-this.sliceOffset,length,this.littleEndian));}
|
|
else{BlobView.get(this.blob,offset,length,callback,this.littleEndian);}},littleEndian:function(){this.littleEndian=true;},bigEndian:function(){this.littleEndian=false;},getUint8:function(offset){return this.view.getUint8(offset);},getInt8:function(offset){return this.view.getInt8(offset);},getUint16:function(offset,le){return this.view.getUint16(offset,le!==undefined?le:this.littleEndian);},getInt16:function(offset,le){return this.view.getInt16(offset,le!==undefined?le:this.littleEndian);},getUint32:function(offset,le){return this.view.getUint32(offset,le!==undefined?le:this.littleEndian);},getInt32:function(offset,le){return this.view.getInt32(offset,le!==undefined?le:this.littleEndian);},getFloat32:function(offset,le){return this.view.getFloat32(offset,le!==undefined?le:this.littleEndian);},getFloat64:function(offset,le){return this.view.getFloat64(offset,le!==undefined?le:this.littleEndian);},readByte:function(){return this.view.getInt8(this.index++);},readUnsignedByte:function(){return this.view.getUint8(this.index++);},readShort:function(le){var val=this.view.getInt16(this.index,le!==undefined?le:this.littleEndian);this.index+=2;return val;},readUnsignedShort:function(le){var val=this.view.getUint16(this.index,le!==undefined?le:this.littleEndian);this.index+=2;return val;},readInt:function(le){var val=this.view.getInt32(this.index,le!==undefined?le:this.littleEndian);this.index+=4;return val;},readUnsignedInt:function(le){var val=this.view.getUint32(this.index,le!==undefined?le:this.littleEndian);this.index+=4;return val;},readFloat:function(le){var val=this.view.getFloat32(this.index,le!==undefined?le:this.littleEndian);this.index+=4;return val;},readDouble:function(le){var val=this.view.getFloat64(this.index,le!==undefined?le:this.littleEndian);this.index+=8;return val;},tell:function(){return this.index;},remaining:function(){return this.byteLength-this.index;},seek:function(index){if(index<0){fail('negative index');}
|
|
if(index>this.byteLength){fail('index greater than buffer size');}
|
|
this.index=index;},advance:function(n){var index=this.index+n;if(index<0){fail('advance past beginning of buffer');}
|
|
if(index>this.byteLength){fail('advance past end of buffer');}
|
|
this.index=index;},getUnsignedByteArray:function(offset,n){return new Uint8Array(this.buffer,offset+this.viewOffset,n);},readUnsignedByteArray:function(n){var val=new Uint8Array(this.buffer,this.index+this.viewOffset,n);this.index+=n;return val;},getBit:function(offset,bit){var byte=this.view.getUint8(offset);return(byte&(1<<bit))!==0;},getUint24:function(offset,le){var b1,b2,b3;if(le!==undefined?le:this.littleEndian){b1=this.view.getUint8(offset);b2=this.view.getUint8(offset+1);b3=this.view.getUint8(offset+2);}
|
|
else{b3=this.view.getUint8(offset);b2=this.view.getUint8(offset+1);b1=this.view.getUint8(offset+2);}
|
|
return(b3<<16)+(b2<<8)+b1;},readUint24:function(le){var value=this.getUint24(this.index,le);this.index+=3;return value;},getBinaryText:function(offset,len){var bytes=new Uint8Array(this.buffer,offset+this.viewOffset,len);return String.fromCharCode.apply(String,bytes);},readBinaryText:function(len){var s=this.getBinaryText(this.index,len);this.index+=len;return s;},getLatin1Text:function(offset,len){var bytes=new Uint8Array(this.buffer,offset+this.viewOffset,len);return getDecoder('latin1').decode(bytes);},readLatin1Text:function(len){var s=this.getLatin1Text(this.index,len);this.index+=len;return s;},getUTF8Text:function(offset,len){var bytes=new Uint8Array(this.buffer,offset+this.viewOffset,len);return getDecoder('utf-8').decode(bytes);},readUTF8Text:function(len){var s=this.getUTF8Text(this.index,len);this.index+=len;return s;},getUTF16Text:function(offset,len,le){if(len%2){fail('len must be a multiple of two');}
|
|
var bytes=new Uint8Array(this.buffer,offset+this.viewOffset,len);if(le===null||le===undefined){var BOM=(bytes[0]<<8)+bytes[1];if(BOM===0xFEFF){bytes=bytes.subarray(2);le=false;}else if(BOM===0xFFFE){bytes=bytes.subarray(2);le=true;}else{le=true;}}
|
|
var encoding=le?'utf-16le':'utf-16be';return getDecoder(encoding).decode(bytes);},readUTF16Text:function(len,le){var s=this.getUTF16Text(this.index,len,le);this.index+=len;return s;},getID3Uint28BE:function(offset){var b1=this.view.getUint8(offset)&0x7f;var b2=this.view.getUint8(offset+1)&0x7f;var b3=this.view.getUint8(offset+2)&0x7f;var b4=this.view.getUint8(offset+3)&0x7f;return(b1<<21)|(b2<<14)|(b3<<7)|b4;},readID3Uint28BE:function(){var value=this.getID3Uint28BE(this.index);this.index+=4;return value;},readNullTerminatedLatin1Text:function(size,advance_by_size=false){var bytes=new Uint8Array(this.buffer,this.viewOffset+this.index,size);var nil=bytes.indexOf(0);if(nil!==-1){bytes=bytes.subarray(0,nil);}
|
|
var s=getDecoder('latin1').decode(bytes);if(nil===-1||advance_by_size){this.index+=size;}else{this.index+=nil+1;}
|
|
return s;},readNullTerminatedUTF8Text:function(size,advance_by_size=false){var bytes=new Uint8Array(this.buffer,this.viewOffset+this.index,size);var nil=bytes.indexOf(0);if(nil!==-1){bytes=bytes.subarray(0,nil);}
|
|
var s=getDecoder('utf-8').decode(bytes);if(nil===-1||advance_by_size){this.index+=size;}else{this.index+=nil+1;}
|
|
return s;},readNullTerminatedUTF16Text:function(size,le,advance_by_size=false){if(size%2){fail('size must be a multiple of two');}
|
|
for(var len=0;len<size;len+=2){if(this.getUint16(this.index+len,le)===0){break;}}
|
|
var s=this.getUTF16Text(this.index,len,le);if(len===size||advance_by_size){this.index+=size;}else{this.index+=len+2;}
|
|
return s;}};return{get:BlobView.get,getFromArrayBuffer:BlobView.getFromArrayBuffer};}());'use strict';var MetadataFormats=(function(){var formats=[{file:'js/metadata/forward_lock.js',get module(){return ForwardLockMetadata;},match:function(header){return header.getBinaryText(0,9)==='LOCKED 1 ';}},{file:'js/metadata/id3v2.js',get module(){return ID3v2Metadata;},match:function(header){return header.getBinaryText(0,3)==='ID3';}},{file:'js/metadata/ogg.js',get module(){return OggMetadata;},match:function(header){return header.getBinaryText(0,4)==='OggS';}},{file:'js/metadata/flac.js',get module(){return FLACMetadata;},match:function(header){return header.getBinaryText(0,4)==='fLaC';}},{file:'js/metadata/mp4.js',get module(){return MP4Metadata;},match:function(header){return header.getBinaryText(4,4)==='ftyp';}},{file:'js/metadata/id3v1.js',get module(){return ID3v1Metadata;},match:function(header){return(header.getUint16(0,false)&0xFFFE)===0xFFFA;}}];function MetadataParser(formatInfo){this._formatInfo=formatInfo;}
|
|
MetadataParser.prototype={parse:function(header){var info=this._formatInfo;return LazyLoader.load(info.file).then(()=>{return info.module.parse(header);});}};function findParser(header){for(var i=0;i<formats.length;i++){if(formats[i].match(header)){return new MetadataParser(formats[i]);}}
|
|
return null;}
|
|
return{findParser:findParser};})();'use strict';var AudioMetadata=(function(){function parse(blob){var filename=blob.name;if(filename){if(filename.slice(0,5)==='DCIM/'&&filename.slice(-4).toLowerCase()==='.3gp'){return Promise.reject('skipping 3gp video file');}}
|
|
if(blob.size<128){return Promise.reject('file is empty or too small');}
|
|
return new Promise(function(resolve,reject){var headersize=Math.min(64*1024,blob.size);BlobView.get(blob,0,headersize,function(header,error){if(error){reject(error);return;}
|
|
try{var parser=MetadataFormats.findParser(header);var promise;if(parser){promise=parser.parse(header);}else{promise=checkPlayability(blob);}
|
|
resolve(promise.then(function(metadata){return addDefaultMetadata(metadata||{},filename);}));}catch(e){console.error('AudioMetadata.parse:',e,e.stack);reject(e);}});});}
|
|
function addDefaultMetadata(metadata,filename){if(!metadata.artist){metadata.artist='';}
|
|
if(!metadata.album){metadata.album='';}
|
|
if(!metadata.title){if(filename){var p1=filename.lastIndexOf('/');var p2=filename.lastIndexOf('.');if(p2<=p1){p2=filename.length;}
|
|
metadata.title=filename.substring(p1+1,p2);}else{metadata.title='';}}
|
|
metadata.rated=metadata.played=0;return metadata;}
|
|
function checkPlayability(blob){var player=new Audio();player.mozAudioChannelType='content';var canplay=blob.type&&player.canPlayType(blob.type);if(canplay==='probably'){return Promise.resolve();}else{return new Promise(function(resolve,reject){var url=URL.createObjectURL(blob);player.src=url;const CANPLAY_TIMEOUT=3000;var timeoutId=setTimeout(()=>{console.error('No oncanplay or error events seen yet.','Assuming file is corrupt:',blob.name);player.onerror();},CANPLAY_TIMEOUT);player.onerror=function(){clearTimeout(timeoutId);URL.revokeObjectURL(url);player.removeAttribute('src');player.load();reject('Unplayable music file');};player.oncanplay=function(){clearTimeout(timeoutId);URL.revokeObjectURL(url);player.removeAttribute('src');player.load();resolve();};});}}
|
|
return{parse:parse};})(); |