├── .eslintrc.js ├── .gitignore ├── .idea ├── inspectionProfiles │ └── Project_Default.xml └── runConfigurations │ └── Tests__Unit.xml ├── .mocharc.json ├── .npmignore ├── .nycrc ├── LICENSE ├── README.md ├── appveyor.yml ├── docs ├── .nojekyll ├── README.md ├── classes │ ├── AacFile.md │ ├── AacFileSettings.md │ ├── AiffFile.md │ ├── ApeFile.md │ ├── ApeFileSettings.md │ ├── ApeTag.md │ ├── ApeTagItem.md │ ├── AsfBaseObject.md │ ├── AsfContentDescriptionObject.md │ ├── AsfContentDescriptor.md │ ├── AsfExtendedContentDescriptionObject.md │ ├── AsfFile.md │ ├── AsfFilePropertiesObject.md │ ├── AsfHeaderExtensionObject.md │ ├── AsfHeaderObject.md │ ├── AsfMetadataDescriptor.md │ ├── AsfMetadataLibraryObject.md │ ├── AsfPaddingObject.md │ ├── AsfStreamPropertiesObject.md │ ├── AsfTag.md │ ├── AsfUnknownObject.md │ ├── AviFileSettings.md │ ├── AviStream.md │ ├── ByteVector.md │ ├── CombinedTag.md │ ├── CorruptFileError.md │ ├── DivxTag.md │ ├── EndTag.md │ ├── File.md │ ├── FlacBlock.md │ ├── FlacFile.md │ ├── FlacFileSettings.md │ ├── FlacTag.md │ ├── Genres.md │ ├── Id3v1Tag.md │ ├── Id3v2AttachmentFrame.md │ ├── Id3v2CommentsFrame.md │ ├── Id3v2EventTimeCode.md │ ├── Id3v2EventTimeCodeFrame.md │ ├── Id3v2ExtendedHeader.md │ ├── Id3v2Frame.md │ ├── Id3v2FrameFactory.md │ ├── Id3v2FrameHeader.md │ ├── Id3v2FrameIdentifier.md │ ├── Id3v2MusicCdIdentifierFrame.md │ ├── Id3v2PlayCountFrame.md │ ├── Id3v2PopularimeterFrame.md │ ├── Id3v2PrivateFrame.md │ ├── Id3v2RelativeVolumeFrame.md │ ├── Id3v2RelativeVolumeFrameChannelData.md │ ├── Id3v2Settings.md │ ├── Id3v2Synchronized.md │ ├── Id3v2SynchronizedLyricsFrame.md │ ├── Id3v2Tag.md │ ├── Id3v2TagFooter.md │ ├── Id3v2TagHeader.md │ ├── Id3v2TermsOfUseFrame.md │ ├── Id3v2TextInformationFrame.md │ ├── Id3v2UniqueFileIdentifierFrame.md │ ├── Id3v2UnknownFrame.md │ ├── Id3v2UnsynchronizedLyricsFrame.md │ ├── Id3v2UrlLinkFrame.md │ ├── Id3v2UserTextInformationFrame.md │ ├── Id3v2UserUrlLinkFrame.md │ ├── InfoTag.md │ ├── LocalFileAbstraction.md │ ├── MatroskaFile.md │ ├── MovieIdTag.md │ ├── Mpeg4AppleAdditionalInfoBox.md │ ├── Mpeg4AppleAnnotationBox.md │ ├── Mpeg4AppleDataBox.md │ ├── Mpeg4AppleElementaryStreamDescriptor.md │ ├── Mpeg4AppleItemListBox.md │ ├── Mpeg4AppleTag.md │ ├── Mpeg4Box.md │ ├── Mpeg4BoxHeader.md │ ├── Mpeg4BoxType.md │ ├── Mpeg4File.md │ ├── Mpeg4FullBox.md │ ├── Mpeg4IsoAudioSampleEntry.md │ ├── Mpeg4IsoChunkLargeOffset.md │ ├── Mpeg4IsoChunkOffsetBox.md │ ├── Mpeg4IsoFreeSpaceBox.md │ ├── Mpeg4IsoHandlerBox.md │ ├── Mpeg4IsoMetaBox.md │ ├── Mpeg4IsoMovieHeaderBox.md │ ├── Mpeg4IsoSampleDescriptionBox.md │ ├── Mpeg4IsoSampleEntry.md │ ├── Mpeg4IsoSampleTableBox.md │ ├── Mpeg4IsoUnknownSampleEntry.md │ ├── Mpeg4IsoUserDataBox.md │ ├── Mpeg4IsoVisualSampleEntry.md │ ├── Mpeg4TextBox.md │ ├── Mpeg4UnknownBox.md │ ├── Mpeg4UrlBox.md │ ├── MpegAudioFile.md │ ├── MpegAudioFileSettings.md │ ├── MpegAudioHeader.md │ ├── MpegContainerFile.md │ ├── MpegVbriHeader.md │ ├── MpegVideoHeader.md │ ├── MpegXingHeader.md │ ├── NotImplementedError.md │ ├── OggCodecFactory.md │ ├── OggFile.md │ ├── OggFileSettings.md │ ├── OggOpusCodec.md │ ├── OggTag.md │ ├── OggTheoraCodec.md │ ├── OggVorbisCodec.md │ ├── Picture.md │ ├── PictureLazy.md │ ├── Properties.md │ ├── RiffBitmapInfoHeader.md │ ├── RiffFile.md │ ├── RiffList.md │ ├── RiffListTag.md │ ├── RiffWaveFormatEx.md │ ├── SandwichFile.md │ ├── SandwichTag.md │ ├── StartTag.md │ ├── Tag.md │ ├── UuidWrapper.md │ ├── WaveFileSettings.md │ ├── XiphComment.md │ └── XiphPicture.md ├── enums │ ├── ApeTagItemType.md │ ├── AsfObjectDataType.md │ ├── AsfObjectType.md │ ├── AviStreamType.md │ ├── FileAccessMode.md │ ├── FlacBlockType.md │ ├── Id3v2EventType.md │ ├── Id3v2FrameClassType.md │ ├── Id3v2FrameFlags.md │ ├── Id3v2RelativeVolumeFrameChannelType.md │ ├── Id3v2SynchronizedTextType.md │ ├── Id3v2TagHeaderFlags.md │ ├── Id3v2TimestampFormat.md │ ├── MediaTypes.md │ ├── Mpeg4AppleDataBoxFlagType.md │ ├── MpegAudioChannelMode.md │ ├── MpegVersion.md │ ├── PictureType.md │ ├── ReadStyle.md │ ├── SeekOrigin.md │ ├── StringType.md │ └── TagTypes.md ├── interfaces │ ├── IAudioCodec.md │ ├── ICodec.md │ ├── IDisposable.md │ ├── IFileAbstraction.md │ ├── ILazy.md │ ├── ILosslessAudioCodec.md │ ├── IOggCodec.md │ ├── IPhotoCodec.md │ ├── IPicture.md │ ├── IRiffChunk.md │ ├── ISandwichFile.md │ ├── IStream.md │ └── IVideoCodec.md └── modules.md ├── package-lock.json ├── package.json ├── src ├── aac │ ├── aacAudioHeader.ts │ ├── aacFile.ts │ └── aacFileSettings.ts ├── aiff │ ├── aiffFile.ts │ ├── aiffFileSettings.ts │ └── aiffStreamHeader.ts ├── ape │ ├── apeFile.ts │ ├── apeFileSettings.ts │ ├── apeStreamHeader.ts │ ├── apeTag.ts │ ├── apeTagFooter.ts │ └── apeTagItem.ts ├── asf │ ├── asfFile.ts │ ├── asfTag.ts │ ├── constants.ts │ ├── objects │ │ ├── baseObject.ts │ │ ├── contentDescriptionObject.ts │ │ ├── descriptorBase.ts │ │ ├── extendedContentDescriptionObject.ts │ │ ├── filePropertiesObject.ts │ │ ├── headerExtensionObject.ts │ │ ├── headerObject.ts │ │ ├── metadataLibraryObject.ts │ │ ├── paddingObject.ts │ │ ├── streamPropertiesObject.ts │ │ └── unknownObject.ts │ └── readWriteUtils.ts ├── byteVector.ts ├── combinedTag.ts ├── ebml │ ├── ebmlElement.ts │ ├── ebmlParser.ts │ ├── ebmlParserOptions.ts │ └── ids.ts ├── errors.ts ├── file.ts ├── fileAbstraction.ts ├── flac │ ├── flacBlock.ts │ ├── flacFile.ts │ ├── flacFileSettings.ts │ ├── flacStreamHeader.ts │ └── flacTag.ts ├── genres.ts ├── id3v1 │ └── id3v1Tag.ts ├── id3v2 │ ├── frameIdentifiers.ts │ ├── frames │ │ ├── attachmentFrame.ts │ │ ├── commentsFrame.ts │ │ ├── eventTimeCodeFrame.ts │ │ ├── frame.ts │ │ ├── frameFactory.ts │ │ ├── frameHeader.ts │ │ ├── musicCdIdentifierFrame.ts │ │ ├── playCountFrame.ts │ │ ├── popularimeterFrame.ts │ │ ├── privateFrame.ts │ │ ├── relativeVolumeFrame.ts │ │ ├── synchronizedLyricsFrame.ts │ │ ├── termsOfUseFrame.ts │ │ ├── textInformationFrame.ts │ │ ├── uniqueFileIdentifierFrame.ts │ │ ├── unknownFrame.ts │ │ ├── unsynchronizedLyricsFrame.ts │ │ └── urlLinkFrame.ts │ ├── id3v2ExtendedHeader.ts │ ├── id3v2Settings.ts │ ├── id3v2Tag.ts │ ├── id3v2TagFooter.ts │ ├── id3v2TagHeader.ts │ ├── syncData.ts │ └── utilTypes.ts ├── index.ts ├── interfaces.ts ├── matroska │ ├── matroskaAttachment.ts │ ├── matroskaFile.ts │ ├── matroskaIds.ts │ ├── matroskaTag.ts │ ├── matroskaTagCollection.ts │ ├── matroskaTagTarget.ts │ ├── matroskaTagValue.ts │ └── tracks │ │ ├── audioTrack.ts │ │ ├── track.ts │ │ ├── trackFactory.ts │ │ └── videoTrack.ts ├── mpeg │ ├── mpegAudioFile.ts │ ├── mpegAudioFileSettings.ts │ ├── mpegAudioHeader.ts │ ├── mpegContainerFile.ts │ ├── mpegContainerFileSettings.ts │ ├── mpegEnums.ts │ ├── mpegVideoHeader.ts │ ├── vbrHeader.ts │ ├── vbriHeader.ts │ └── xingHeader.ts ├── mpeg4 │ ├── appleTag.ts │ ├── boxes │ │ ├── appleAdditionalInfoBox.ts │ │ ├── appleAnnotationBox.ts │ │ ├── appleDataBox.ts │ │ ├── appleElementaryStreamDescriptor.ts │ │ ├── appleItemListBox.ts │ │ ├── fullBox.ts │ │ ├── isoAudioSampleEntry.ts │ │ ├── isoChunkLargeOffsetBox.ts │ │ ├── isoChunkOffsetBox.ts │ │ ├── isoFreeSpaceBox.ts │ │ ├── isoHandlerBox.ts │ │ ├── isoMetaBox.ts │ │ ├── isoMovieHeaderBox.ts │ │ ├── isoSampleDescriptionBox.ts │ │ ├── isoSampleEntry.ts │ │ ├── isoSampleTableBox.ts │ │ ├── isoUnknownSampleEntry.ts │ │ ├── isoUserDataBox.ts │ │ ├── isoVisualSampleEntry.ts │ │ ├── mpeg4Box.ts │ │ ├── textBox.ts │ │ ├── unknownBox.ts │ │ └── urlBox.ts │ ├── descriptorTag.ts │ ├── descriptorTagReader.ts │ ├── mpeg4AudioTypes.ts │ ├── mpeg4BoxFactory.ts │ ├── mpeg4BoxHeader.ts │ ├── mpeg4BoxRenderer.ts │ ├── mpeg4BoxType.ts │ ├── mpeg4File.ts │ ├── mpeg4FileParser.ts │ ├── mpeg4HandlerType.ts │ └── mpeg4Utils.ts ├── ogg │ ├── codecs │ │ ├── codecFactory.ts │ │ ├── iOggCodec.ts │ │ ├── opus.ts │ │ ├── theora.ts │ │ └── vorbis.ts │ ├── oggBitStream.ts │ ├── oggFile.ts │ ├── oggFileSettings.ts │ ├── oggPage.ts │ ├── oggPageHeader.ts │ ├── oggPaginator.ts │ └── oggTag.ts ├── picture.ts ├── properties.ts ├── riff │ ├── avi │ │ ├── aviHeader.ts │ │ └── aviStream.ts │ ├── aviFileSettings.ts │ ├── divxTag.ts │ ├── iRiffChunk.ts │ ├── infoTag.ts │ ├── movieIdTag.ts │ ├── riffBitmapInfoHeader.ts │ ├── riffChunk.ts │ ├── riffFile.ts │ ├── riffList.ts │ ├── riffListTag.ts │ ├── riffTags.ts │ ├── riffWaveFormatEx.ts │ └── waveFileSettings.ts ├── sandwich │ ├── endTag.ts │ ├── sandwichFile.ts │ ├── sandwichTag.ts │ ├── startTag.ts │ └── tagParsers.ts ├── settings.ts ├── stream.ts ├── tag.ts ├── utils.ts ├── uuidWrapper.ts └── xiph │ ├── xiphComment.ts │ ├── xiphPicture.ts │ └── xiphSettings.ts ├── test-integration ├── .eslintrc.js ├── aac_fileTests.ts ├── aiff_fileTests.ts ├── ape_fileTests.ts ├── asf_fileTests.ts ├── avi_fileTests.ts ├── flac_fileTests.ts ├── matroska_fileTests.ts ├── mp3_id3v1_fileTests.ts ├── mp3_id3v24_fileTests.ts ├── mp3_id3v2_fileTests.ts ├── mp3_propertiesTest.ts ├── mpeg4_m4a_fileTests.ts ├── mpeg4_m4v_fileTests.ts ├── mpeg_fileTest.ts ├── ogg_opus_fileTests.ts ├── ogg_theora_fileTests.ts ├── ogg_vorbis_fileTests.ts ├── resources │ ├── corruptSamples │ │ ├── corrupt.aac │ │ ├── corrupt.aif │ │ ├── corrupt.avi │ │ ├── corrupt.flac │ │ ├── corrupt.m4a │ │ ├── corrupt.mpg │ │ ├── corrupt.ogg │ │ ├── corrupt.wav │ │ ├── corrupt.wma │ │ ├── corruptMissingFlag.ogg │ │ └── corruptNullTitleId3v2.mp3 │ └── samples │ │ ├── apple_tags.m4a │ │ ├── bgo_658920.m4a │ │ ├── bgo_676934.m4a │ │ ├── bgo_701689.m4a │ │ ├── sample.aac │ │ ├── sample.aif │ │ ├── sample.ape │ │ ├── sample.avi │ │ ├── sample.flac │ │ ├── sample.m4a │ │ ├── sample.m4v │ │ ├── sample.mkv │ │ ├── sample.mp3 │ │ ├── sample.mpg │ │ ├── sample.ogg │ │ ├── sample.ogv │ │ ├── sample.opus │ │ ├── sample.wav │ │ ├── sample.wma │ │ ├── sample_gimp.gif │ │ ├── sample_props_cbr.mp3 │ │ ├── sample_props_vbri.mp3 │ │ ├── sample_props_xingabr.mp3 │ │ ├── sample_props_xingcbr.mp3 │ │ ├── sample_props_xingvbr.mp3 │ │ ├── sample_replaygain.m4a │ │ ├── sample_replaygain.mp3 │ │ ├── sample_teenytiny.gif │ │ ├── sample_v1_only.mp3 │ │ ├── sample_v2_3_ext_header.mp3 │ │ ├── sample_v2_4_unsynch.mp3 │ │ └── sample_v2_only.mp3 ├── tsconfig.json ├── utilities │ ├── extendedFileTests.ts │ ├── standardFileTests.ts │ ├── testConstants.ts │ └── utilities.ts └── wav_fileTest.ts ├── test-unit ├── .eslintrc.js ├── aac │ ├── aacAudioHeaderTests.ts │ └── aacFileTests.ts ├── aiff │ └── aiffStreamHeaderTests.ts ├── ape │ ├── apeFileTests.ts │ ├── apeStreamHeaderTests.ts │ ├── apeTagFooterTests.ts │ ├── apeTagItemTests.ts │ └── apeTagTests.ts ├── asf │ ├── asfTagTests.ts │ ├── contentDescriptionObjectTests.ts │ ├── descriptorBaseTests.ts │ ├── extendedContentDescriptionObjectTests.ts │ ├── filePropertiesObjectTests.ts │ ├── headerExtensionObjectTests.ts │ ├── headerObjectTests.ts │ ├── metadataLibraryObjectTests.ts │ ├── objectTests.ts │ ├── paddingObjectTests.ts │ ├── streamPropertiesObjectTests.ts │ └── unknownObjectTests.ts ├── byteVectorConstructorTests.ts ├── byteVectorConversionTests.ts ├── byteVectorMethodTests.ts ├── combinedTagTests.ts ├── ebml │ ├── ebmlElementTests.ts │ └── ebmlParserTests.ts ├── fileAbstractionTests.ts ├── fileTests.ts ├── flac │ ├── flacBlockTests.ts │ ├── flacFileTests.ts │ ├── flacStreamHeaderTests.ts │ └── flacTagTests.ts ├── id3v1 │ └── id3v1TagTests.ts ├── id3v2 │ ├── attachmentsFrameTests.ts │ ├── commentsFrameTests.ts │ ├── eventTimeCodeFrameTests.ts │ ├── frameConstructorTests.ts │ ├── frameFactoryTests.ts │ ├── frameHeaderTests.ts │ ├── frameIdentifiersTests.ts │ ├── frameTests.ts │ ├── id3v2TagTests.ts │ ├── musicCdIdentifierFrameTests.ts │ ├── playCountFrameTests.ts │ ├── popularimeterFrameTests.ts │ ├── privateFrameTests.ts │ ├── relativeVolumeFrameTests.ts │ ├── syncDataTests.ts │ ├── synchronizedLyricsFrameTests.ts │ ├── tagExtendedHeaderTests.ts │ ├── tagFooterTests.ts │ ├── tagHeaderTests.ts │ ├── termsOfUseFrameTests.ts │ ├── textInformationFrameTests.ts │ ├── uniqueFileIdentifierFrameTests.ts │ ├── unknownFrameTests.ts │ ├── unsynchronizedLyricsFrameTests.ts │ ├── urlLinkFrameTests.ts │ ├── userTextInformationFrameTests.ts │ └── userUrlLinkFrameTests.ts ├── matroska │ ├── audioTrackTests.ts │ ├── matroskaAttachmentTests.ts │ ├── matroskaTagCollectionTests.ts │ ├── matroskaTagTargetTests.ts │ ├── matroskaTagTests.ts │ ├── matroskaTagValueTests.ts │ ├── trackFactoryTests.ts │ ├── utils.ts │ └── videoTrackTests.ts ├── mpeg │ ├── mpegAudioFileTests.ts │ ├── mpegAudioHeaderTests.ts │ ├── mpegContainerFileTests.ts │ ├── mpegVideoHeaderTests.ts │ ├── vbriHeaderTests.ts │ └── xingHeaderTests.ts ├── mpeg4 │ ├── appleTagTests.ts │ ├── mpeg4Tests.ts │ └── mpeg4UtilsTests.ts ├── ogg │ ├── codecFactoryTests.ts │ ├── codecPackets.ts │ ├── groupedCommentTests.ts │ ├── oggPageHeaderTests.ts │ ├── opusCodecTests.ts │ ├── theoraCodecTests.ts │ └── vorbisCodecTests.ts ├── pictureLazyTests.ts ├── pictureTests.ts ├── resources │ └── testFile.txt ├── riff │ ├── aviHeaderTests.ts │ ├── aviStreamTests.ts │ ├── divxTagTests.ts │ ├── infoTagTests.ts │ ├── movieIdTagTests.ts │ ├── resources.ts │ ├── riffBitmapInfoHeaderTests.ts │ ├── riffFileTests.ts │ ├── riffListTagTests.ts │ ├── riffListTests.ts │ └── riffWaveFormatExTests.ts ├── sandwich │ ├── endTagTests.ts │ ├── sandwichFileTests.ts │ ├── sandwichTagTests.ts │ └── startTagTests.ts ├── streamTest.ts ├── testConstants.ts ├── tsconfig.json ├── utilities │ ├── propertyTests.ts │ ├── testFile.ts │ ├── testStream.ts │ └── testers.ts └── xiph │ ├── resources.ts │ ├── xiphCommentTests.ts │ └── xiphPictureTests.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 64 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 65 | .idea/** 66 | 67 | # CMake 68 | cmake-build-*/ 69 | 70 | # File-based project format 71 | *.iws 72 | 73 | # mpeltonen/sbt-idea plugin 74 | .idea_modules/ 75 | 76 | # JIRA plugin 77 | atlassian-ide-plugin.xml 78 | 79 | # Crashlytics plugin (for Android Studio and IntelliJ) 80 | com_crashlytics_export_strings.xml 81 | crashlytics.properties 82 | crashlytics-build.properties 83 | fabric.properties 84 | 85 | # Ignore build output 86 | dist/** 87 | 88 | # Files created during test 89 | test*/resources/**/testFile_* -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | -------------------------------------------------------------------------------- /.idea/runConfigurations/Tests__Unit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | project 4 | 5 | $PROJECT_DIR$/node_modules/mocha 6 | $PROJECT_DIR$ 7 | true 8 | bdd 9 | 10 | DIRECTORY 11 | $PROJECT_DIR$/test-unit 12 | true 13 | 14 | 15 | -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extension": ["ts"], 3 | "recursive": true, 4 | "require": [ 5 | "ts-node/register", 6 | "source-map-support/register" 7 | ], 8 | "slow": 1000, 9 | "timout": 3000, 10 | "ui": "mocha-typescript" 11 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | ## Override the .gitignore to make sure dist 2 | 3 | # Ignore test files 4 | test-* 5 | 6 | # Ignore idea stuff 7 | .idea 8 | 9 | # Ignore NYC coverage output files 10 | .nyc_output/** 11 | 12 | # Output of 'npm pack' 13 | *.tgz 14 | 15 | # Doc output 16 | docs/** -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@istanbuljs/nyc-config-typescript" 3 | } -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 5.1.0-{branch}.{build} 2 | 3 | environment: 4 | nodejs_version: "14.21" 5 | 6 | install: 7 | - ps: Install-Product node $env:nodejs_version 8 | - npm install 9 | 10 | build_script: 11 | - npm run build 12 | - npm pack 13 | 14 | test_script: 15 | - npm run test-unit-with-coverage 16 | 17 | after_test: 18 | - npm run publish-coverage 19 | 20 | artifacts: 21 | - path: '*.tgz' 22 | name: NPM Package 23 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/classes/AviFileSettings.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / AviFileSettings 2 | 3 | # Class: AviFileSettings 4 | 5 | This class contains settings related to AVI file operations. Open files will need to be re-read 6 | in order for changes to take effect. 7 | 8 | ## Table of contents 9 | 10 | ### Constructors 11 | 12 | - [constructor](AviFileSettings.md#constructor) 13 | 14 | ### Properties 15 | 16 | - [SUPPORTED\_TAG\_TYPES](AviFileSettings.md#supported_tag_types) 17 | 18 | ### Accessors 19 | 20 | - [defaultTagTypes](AviFileSettings.md#defaulttagtypes) 21 | 22 | ## Constructors 23 | 24 | ### constructor 25 | 26 | • **new AviFileSettings**() 27 | 28 | ## Properties 29 | 30 | ### SUPPORTED\_TAG\_TYPES 31 | 32 | ▪ `Static` `Readonly` **SUPPORTED\_TAG\_TYPES**: `number` 33 | 34 | The types of tags that are supported by AVI files. 35 | 36 | ## Accessors 37 | 38 | ### defaultTagTypes 39 | 40 | • `Static` `get` **defaultTagTypes**(): [`TagTypes`](../enums/TagTypes.md) 41 | 42 | Gets the default types of tags for an AVI file. When opening a file, if these tag types do 43 | not exist on the file, they will be created. 44 | 45 | #### Returns 46 | 47 | [`TagTypes`](../enums/TagTypes.md) 48 | 49 | • `Static` `set` **defaultTagTypes**(`value`): `void` 50 | 51 | Sets the default types of tags for an AVI file. When opening a file, if these tag types do 52 | not exist on the file, they will be created. See [SUPPORTED_TAG_TYPES](AviFileSettings.md#supported_tag_types) for a list of tag 53 | types that are supported by node-taglib-sharp for AVI files. 54 | 55 | #### Parameters 56 | 57 | | Name | Type | 58 | | :------ | :------ | 59 | | `value` | [`TagTypes`](../enums/TagTypes.md) | 60 | 61 | #### Returns 62 | 63 | `void` 64 | -------------------------------------------------------------------------------- /docs/classes/CorruptFileError.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / CorruptFileError 2 | 3 | # Class: CorruptFileError 4 | 5 | Error class that indicates the file is likely corrupt. 6 | 7 | ## Hierarchy 8 | 9 | - `Error` 10 | 11 | ↳ **`CorruptFileError`** 12 | 13 | ## Table of contents 14 | 15 | ### Constructors 16 | 17 | - [constructor](CorruptFileError.md#constructor) 18 | 19 | ### Properties 20 | 21 | - [message](CorruptFileError.md#message) 22 | - [name](CorruptFileError.md#name) 23 | - [stack](CorruptFileError.md#stack) 24 | - [prepareStackTrace](CorruptFileError.md#preparestacktrace) 25 | - [stackTraceLimit](CorruptFileError.md#stacktracelimit) 26 | 27 | ### Methods 28 | 29 | - [captureStackTrace](CorruptFileError.md#capturestacktrace) 30 | 31 | ## Constructors 32 | 33 | ### constructor 34 | 35 | • **new CorruptFileError**(`msg?`) 36 | 37 | #### Parameters 38 | 39 | | Name | Type | 40 | | :------ | :------ | 41 | | `msg?` | `string` | 42 | 43 | #### Overrides 44 | 45 | Error.constructor 46 | 47 | ## Properties 48 | 49 | ### message 50 | 51 | • **message**: `string` 52 | 53 | #### Inherited from 54 | 55 | Error.message 56 | 57 | ___ 58 | 59 | ### name 60 | 61 | • **name**: `string` 62 | 63 | #### Inherited from 64 | 65 | Error.name 66 | 67 | ___ 68 | 69 | ### stack 70 | 71 | • `Optional` **stack**: `string` 72 | 73 | #### Inherited from 74 | 75 | Error.stack 76 | 77 | ___ 78 | 79 | ### prepareStackTrace 80 | 81 | ▪ `Static` `Optional` **prepareStackTrace**: (`err`: `Error`, `stackTraces`: `CallSite`[]) => `any` 82 | 83 | #### Type declaration 84 | 85 | ▸ (`err`, `stackTraces`): `any` 86 | 87 | Optional override for formatting stack traces 88 | 89 | **`See`** 90 | 91 | https://v8.dev/docs/stack-trace-api#customizing-stack-traces 92 | 93 | ##### Parameters 94 | 95 | | Name | Type | 96 | | :------ | :------ | 97 | | `err` | `Error` | 98 | | `stackTraces` | `CallSite`[] | 99 | 100 | ##### Returns 101 | 102 | `any` 103 | 104 | #### Inherited from 105 | 106 | Error.prepareStackTrace 107 | 108 | ___ 109 | 110 | ### stackTraceLimit 111 | 112 | ▪ `Static` **stackTraceLimit**: `number` 113 | 114 | #### Inherited from 115 | 116 | Error.stackTraceLimit 117 | 118 | ## Methods 119 | 120 | ### captureStackTrace 121 | 122 | ▸ `Static` **captureStackTrace**(`targetObject`, `constructorOpt?`): `void` 123 | 124 | Create .stack property on a target object 125 | 126 | #### Parameters 127 | 128 | | Name | Type | 129 | | :------ | :------ | 130 | | `targetObject` | `object` | 131 | | `constructorOpt?` | `Function` | 132 | 133 | #### Returns 134 | 135 | `void` 136 | 137 | #### Inherited from 138 | 139 | Error.captureStackTrace 140 | -------------------------------------------------------------------------------- /docs/classes/Id3v2ExtendedHeader.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / Id3v2ExtendedHeader 2 | 3 | # Class: Id3v2ExtendedHeader 4 | 5 | This class is a filler until support for reading and writing the ID3v2 extended header is 6 | implemented. 7 | 8 | ## Table of contents 9 | 10 | ### Accessors 11 | 12 | - [size](Id3v2ExtendedHeader.md#size) 13 | 14 | ### Methods 15 | 16 | - [fromData](Id3v2ExtendedHeader.md#fromdata) 17 | - [fromEmpty](Id3v2ExtendedHeader.md#fromempty) 18 | 19 | ## Accessors 20 | 21 | ### size 22 | 23 | • `get` **size**(): `number` 24 | 25 | Gets the size of the data on disk in bytes. 26 | 27 | #### Returns 28 | 29 | `number` 30 | 31 | ## Methods 32 | 33 | ### fromData 34 | 35 | ▸ `Static` **fromData**(`data`, `version`): [`Id3v2ExtendedHeader`](Id3v2ExtendedHeader.md) 36 | 37 | Constructs and initializes a new instance by reading the raw contents. 38 | 39 | #### Parameters 40 | 41 | | Name | Type | Description | 42 | | :------ | :------ | :------ | 43 | | `data` | [`ByteVector`](ByteVector.md) | Raw extended header structure | 44 | | `version` | `number` | ID3v2 version. Must be an unsigned 8-bit integer. | 45 | 46 | #### Returns 47 | 48 | [`Id3v2ExtendedHeader`](Id3v2ExtendedHeader.md) 49 | 50 | ___ 51 | 52 | ### fromEmpty 53 | 54 | ▸ `Static` **fromEmpty**(): [`Id3v2ExtendedHeader`](Id3v2ExtendedHeader.md) 55 | 56 | Constructs and initializes a new instance with no contents. 57 | 58 | #### Returns 59 | 60 | [`Id3v2ExtendedHeader`](Id3v2ExtendedHeader.md) 61 | -------------------------------------------------------------------------------- /docs/classes/Id3v2SynchronizedLyricsFrame.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / Id3v2SynchronizedLyricsFrame 2 | 3 | # Class: Id3v2SynchronizedLyricsFrame 4 | 5 | This structure contains a single entry in a SynchronizedLyricsFrame object. 6 | 7 | ## Table of contents 8 | 9 | ### Constructors 10 | 11 | - [constructor](Id3v2SynchronizedLyricsFrame.md#constructor) 12 | 13 | ### Properties 14 | 15 | - [text](Id3v2SynchronizedLyricsFrame.md#text) 16 | 17 | ### Accessors 18 | 19 | - [time](Id3v2SynchronizedLyricsFrame.md#time) 20 | 21 | ### Methods 22 | 23 | - [clone](Id3v2SynchronizedLyricsFrame.md#clone) 24 | - [render](Id3v2SynchronizedLyricsFrame.md#render) 25 | 26 | ## Constructors 27 | 28 | ### constructor 29 | 30 | • **new Id3v2SynchronizedLyricsFrame**(`time`, `text`) 31 | 32 | Constructs and initializes a new instance with a specified time and text. 33 | 34 | #### Parameters 35 | 36 | | Name | Type | Description | 37 | | :------ | :------ | :------ | 38 | | `time` | `number` | Offset into the media that owns this element when this element should be displayed. See TimestampFormat for possible values. | 39 | | `text` | `string` | Text for the point in time | 40 | 41 | ## Properties 42 | 43 | ### text 44 | 45 | • **text**: `string` 46 | 47 | Text for the point in time represented by the current instance. 48 | 49 | ## Accessors 50 | 51 | ### time 52 | 53 | • `get` **time**(): `number` 54 | 55 | Gets time offset of the current instance. The specific format this text element is defined 56 | in SynchronizedLyricsFrame.format of the frame that owns this element. 57 | 58 | #### Returns 59 | 60 | `number` 61 | 62 | • `set` **time**(`value`): `void` 63 | 64 | Sets time offset of the current instance. The specific format this text element is defined 65 | in SynchronizedLyricsFrame.format of the frame that owns this element. 66 | 67 | #### Parameters 68 | 69 | | Name | Type | Description | 70 | | :------ | :------ | :------ | 71 | | `value` | `number` | Offset of the current instance, must be a safe | 72 | 73 | #### Returns 74 | 75 | `void` 76 | 77 | ## Methods 78 | 79 | ### clone 80 | 81 | ▸ **clone**(): [`Id3v2SynchronizedLyricsFrame`](Id3v2SynchronizedLyricsFrame.md) 82 | 83 | Creates a copy of this instance. 84 | 85 | #### Returns 86 | 87 | [`Id3v2SynchronizedLyricsFrame`](Id3v2SynchronizedLyricsFrame.md) 88 | 89 | ___ 90 | 91 | ### render 92 | 93 | ▸ **render**(`encoding`): [`ByteVector`](ByteVector.md) 94 | 95 | Generates a raw byte representation of the frame for writing to a file. 96 | 97 | #### Parameters 98 | 99 | | Name | Type | Description | 100 | | :------ | :------ | :------ | 101 | | `encoding` | [`StringType`](../enums/StringType.md) | Encoding to use for encoding the text of the frame. | 102 | 103 | #### Returns 104 | 105 | [`ByteVector`](ByteVector.md) 106 | -------------------------------------------------------------------------------- /docs/classes/MpegVbriHeader.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / MpegVbriHeader 2 | 3 | # Class: MpegVbriHeader 4 | 5 | Information about a variable bitrate MPEG audio stream encoded by the Fraunhofer encoder 6 | 7 | ## Hierarchy 8 | 9 | - `default` 10 | 11 | ↳ **`MpegVbriHeader`** 12 | 13 | ## Table of contents 14 | 15 | ### Accessors 16 | 17 | - [bitrateKilobytes](MpegVbriHeader.md#bitratekilobytes) 18 | - [durationMilliseconds](MpegVbriHeader.md#durationmilliseconds) 19 | - [totalBytes](MpegVbriHeader.md#totalbytes) 20 | - [totalFrames](MpegVbriHeader.md#totalframes) 21 | 22 | ### Methods 23 | 24 | - [fromFile](MpegVbriHeader.md#fromfile) 25 | 26 | ## Accessors 27 | 28 | ### bitrateKilobytes 29 | 30 | • `get` **bitrateKilobytes**(): `number` 31 | 32 | Gets the bitrate of the ile in kilobytes per second, if it could be calculated using the 33 | current instance. `undefined`, otherwise. 34 | 35 | #### Returns 36 | 37 | `number` 38 | 39 | #### Inherited from 40 | 41 | VbrHeader.bitrateKilobytes 42 | 43 | ___ 44 | 45 | ### durationMilliseconds 46 | 47 | • `get` **durationMilliseconds**(): `number` 48 | 49 | Gets the duration of the file in milliseconds, if it could be calculated using the current 50 | instance. `undefined`, otherwise. 51 | 52 | #### Returns 53 | 54 | `number` 55 | 56 | #### Inherited from 57 | 58 | VbrHeader.durationMilliseconds 59 | 60 | ___ 61 | 62 | ### totalBytes 63 | 64 | • `get` **totalBytes**(): `number` 65 | 66 | Gets the total size of the file in bytes, as indicated by the current instance. 67 | 68 | #### Returns 69 | 70 | `number` 71 | 72 | #### Inherited from 73 | 74 | VbrHeader.totalBytes 75 | 76 | ___ 77 | 78 | ### totalFrames 79 | 80 | • `get` **totalFrames**(): `number` 81 | 82 | Gets the total number of frames in the file, as indicated by the current instance. 83 | 84 | #### Returns 85 | 86 | `number` 87 | 88 | #### Inherited from 89 | 90 | VbrHeader.totalFrames 91 | 92 | ## Methods 93 | 94 | ### fromFile 95 | 96 | ▸ `Static` **fromFile**(`file`, `mpegHeaderPosition`, `samplesPerFrame`, `samplesPerSecond`): [`MpegVbriHeader`](MpegVbriHeader.md) 97 | 98 | #### Parameters 99 | 100 | | Name | Type | 101 | | :------ | :------ | 102 | | `file` | [`File`](File.md) | 103 | | `mpegHeaderPosition` | `number` | 104 | | `samplesPerFrame` | `number` | 105 | | `samplesPerSecond` | `number` | 106 | 107 | #### Returns 108 | 109 | [`MpegVbriHeader`](MpegVbriHeader.md) 110 | -------------------------------------------------------------------------------- /docs/classes/NotImplementedError.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / NotImplementedError 2 | 3 | # Class: NotImplementedError 4 | 5 | Error class that indicates a piece of functionality is not implemented in the current version. 6 | 7 | ## Hierarchy 8 | 9 | - `Error` 10 | 11 | ↳ **`NotImplementedError`** 12 | 13 | ## Table of contents 14 | 15 | ### Constructors 16 | 17 | - [constructor](NotImplementedError.md#constructor) 18 | 19 | ### Properties 20 | 21 | - [message](NotImplementedError.md#message) 22 | - [name](NotImplementedError.md#name) 23 | - [stack](NotImplementedError.md#stack) 24 | - [prepareStackTrace](NotImplementedError.md#preparestacktrace) 25 | - [stackTraceLimit](NotImplementedError.md#stacktracelimit) 26 | 27 | ### Methods 28 | 29 | - [captureStackTrace](NotImplementedError.md#capturestacktrace) 30 | 31 | ## Constructors 32 | 33 | ### constructor 34 | 35 | • **new NotImplementedError**(`message?`) 36 | 37 | #### Parameters 38 | 39 | | Name | Type | 40 | | :------ | :------ | 41 | | `message?` | `string` | 42 | 43 | #### Overrides 44 | 45 | Error.constructor 46 | 47 | ## Properties 48 | 49 | ### message 50 | 51 | • **message**: `string` 52 | 53 | #### Inherited from 54 | 55 | Error.message 56 | 57 | ___ 58 | 59 | ### name 60 | 61 | • **name**: `string` 62 | 63 | #### Inherited from 64 | 65 | Error.name 66 | 67 | ___ 68 | 69 | ### stack 70 | 71 | • `Optional` **stack**: `string` 72 | 73 | #### Inherited from 74 | 75 | Error.stack 76 | 77 | ___ 78 | 79 | ### prepareStackTrace 80 | 81 | ▪ `Static` `Optional` **prepareStackTrace**: (`err`: `Error`, `stackTraces`: `CallSite`[]) => `any` 82 | 83 | #### Type declaration 84 | 85 | ▸ (`err`, `stackTraces`): `any` 86 | 87 | Optional override for formatting stack traces 88 | 89 | **`See`** 90 | 91 | https://v8.dev/docs/stack-trace-api#customizing-stack-traces 92 | 93 | ##### Parameters 94 | 95 | | Name | Type | 96 | | :------ | :------ | 97 | | `err` | `Error` | 98 | | `stackTraces` | `CallSite`[] | 99 | 100 | ##### Returns 101 | 102 | `any` 103 | 104 | #### Inherited from 105 | 106 | Error.prepareStackTrace 107 | 108 | ___ 109 | 110 | ### stackTraceLimit 111 | 112 | ▪ `Static` **stackTraceLimit**: `number` 113 | 114 | #### Inherited from 115 | 116 | Error.stackTraceLimit 117 | 118 | ## Methods 119 | 120 | ### captureStackTrace 121 | 122 | ▸ `Static` **captureStackTrace**(`targetObject`, `constructorOpt?`): `void` 123 | 124 | Create .stack property on a target object 125 | 126 | #### Parameters 127 | 128 | | Name | Type | 129 | | :------ | :------ | 130 | | `targetObject` | `object` | 131 | | `constructorOpt?` | `Function` | 132 | 133 | #### Returns 134 | 135 | `void` 136 | 137 | #### Inherited from 138 | 139 | Error.captureStackTrace 140 | -------------------------------------------------------------------------------- /docs/classes/OggCodecFactory.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / OggCodecFactory 2 | 3 | # Class: OggCodecFactory 4 | 5 | Factory for creating codecs from the first packet of the Ogg bitstream. 6 | 7 | **`Remarks`** 8 | 9 | By default, only codecs provided by the library will be matched. However, custom codec 10 | support can be added by using [addCodecProvider](OggCodecFactory.md#addcodecprovider). 11 | 12 | ## Table of contents 13 | 14 | ### Constructors 15 | 16 | - [constructor](OggCodecFactory.md#constructor) 17 | 18 | ### Methods 19 | 20 | - [addCodecProvider](OggCodecFactory.md#addcodecprovider) 21 | - [clearCustomProviders](OggCodecFactory.md#clearcustomproviders) 22 | - [getCodec](OggCodecFactory.md#getcodec) 23 | 24 | ## Constructors 25 | 26 | ### constructor 27 | 28 | • **new OggCodecFactory**() 29 | 30 | ## Methods 31 | 32 | ### addCodecProvider 33 | 34 | ▸ `Static` **addCodecProvider**(`provider`): `void` 35 | 36 | Adds a custom codec provider to try before using standard codec creation methods. 37 | Codec providers are used before standard methods so custom checking can be used and new 38 | formats can be added. They are executed in reverse order in which they are added. 39 | 40 | #### Parameters 41 | 42 | | Name | Type | Description | 43 | | :------ | :------ | :------ | 44 | | `provider` | [`OggCodecProvider`](../modules.md#oggcodecprovider) | Codec provider function * firstPacket: ByteVector First packet of the bitstream * returns IOggCodec if method was able to match the packet, falsy otherwise | 45 | 46 | #### Returns 47 | 48 | `void` 49 | 50 | ___ 51 | 52 | ### clearCustomProviders 53 | 54 | ▸ `Static` **clearCustomProviders**(): `void` 55 | 56 | Clears the custom providers from the factory. 57 | 58 | #### Returns 59 | 60 | `void` 61 | 62 | ___ 63 | 64 | ### getCodec 65 | 66 | ▸ `Static` **getCodec**(`packet`): [`IOggCodec`](../interfaces/IOggCodec.md) 67 | 68 | Determines the correc codec to use for a stream header packet. 69 | 70 | #### Parameters 71 | 72 | | Name | Type | Description | 73 | | :------ | :------ | :------ | 74 | | `packet` | [`ByteVector`](ByteVector.md) | First packet of an Ogg logical bitstream. | 75 | 76 | #### Returns 77 | 78 | [`IOggCodec`](../interfaces/IOggCodec.md) 79 | -------------------------------------------------------------------------------- /docs/classes/OggFileSettings.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / OggFileSettings 2 | 3 | # Class: OggFileSettings 4 | 5 | This class contains settings related to Ogg file operations. Open files will need to be re-read 6 | in order for changes to take effect. 7 | 8 | ## Table of contents 9 | 10 | ### Constructors 11 | 12 | - [constructor](OggFileSettings.md#constructor) 13 | 14 | ### Accessors 15 | 16 | - [writeToAllComments](OggFileSettings.md#writetoallcomments) 17 | 18 | ## Constructors 19 | 20 | ### constructor 21 | 22 | • **new OggFileSettings**() 23 | 24 | ## Accessors 25 | 26 | ### writeToAllComments 27 | 28 | • `Static` `get` **writeToAllComments**(): `boolean` 29 | 30 | Gets whether changes to Ogg tag fields should be written to all Xiph comments or just the 31 | first Xiph comment in the file. 32 | 33 | **`Remarks`** 34 | 35 | Ogg files are required to have one Xiph comment per stream. In files with multiple 36 | streams, this means there are multiple Xiph comments per file. 37 | 38 | #### Returns 39 | 40 | `boolean` 41 | 42 | • `Static` `set` **writeToAllComments**(`value`): `void` 43 | 44 | Sets whether changes to Ogg tag fields should be written to all Xiph comments or just the 45 | first Xiph comment in the file. 46 | 47 | **`Remarks`** 48 | 49 | Ogg files are required to have one Xiph comment per stream. In files with multiple 50 | streams, this means there are multiple Xiph comments per file. 51 | 52 | #### Parameters 53 | 54 | | Name | Type | 55 | | :------ | :------ | 56 | | `value` | `boolean` | 57 | 58 | #### Returns 59 | 60 | `void` 61 | -------------------------------------------------------------------------------- /docs/classes/UuidWrapper.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / UuidWrapper 2 | 3 | # Class: UuidWrapper 4 | 5 | Wrapper around the UUID package to make it easier to handle UUIDs. 6 | 7 | ## Table of contents 8 | 9 | ### Constructors 10 | 11 | - [constructor](UuidWrapper.md#constructor) 12 | 13 | ### Methods 14 | 15 | - [equals](UuidWrapper.md#equals) 16 | - [toBytes](UuidWrapper.md#tobytes) 17 | - [toString](UuidWrapper.md#tostring) 18 | 19 | ## Constructors 20 | 21 | ### constructor 22 | 23 | • **new UuidWrapper**(`source?`) 24 | 25 | Constructs an instance using either the supplied UUID or generating a new, random one. 26 | 27 | #### Parameters 28 | 29 | | Name | Type | Description | 30 | | :------ | :------ | :------ | 31 | | `source?` | `string` \| [`ByteVector`](ByteVector.md) | If provided, it is used as the bytes of the instance. If a falsy value is provided, a new v4 UUID will be generated. | 32 | 33 | ## Methods 34 | 35 | ### equals 36 | 37 | ▸ **equals**(`b`): `boolean` 38 | 39 | Determines whether this instance and another instance represent the same UUID. 40 | 41 | #### Parameters 42 | 43 | | Name | Type | Description | 44 | | :------ | :------ | :------ | 45 | | `b` | [`UuidWrapper`](UuidWrapper.md) | The other UUID to compare this one to. | 46 | 47 | #### Returns 48 | 49 | `boolean` 50 | 51 | ___ 52 | 53 | ### toBytes 54 | 55 | ▸ **toBytes**(): [`ByteVector`](ByteVector.md) 56 | 57 | Gets the bytes that make up the UUID. 58 | 59 | #### Returns 60 | 61 | [`ByteVector`](ByteVector.md) 62 | 63 | ___ 64 | 65 | ### toString 66 | 67 | ▸ **toString**(): `string` 68 | 69 | Gets a string representation of the UUID. 70 | 71 | #### Returns 72 | 73 | `string` 74 | -------------------------------------------------------------------------------- /docs/classes/WaveFileSettings.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / WaveFileSettings 2 | 3 | # Class: WaveFileSettings 4 | 5 | This class contains settings related to WAV file operations. Open files will need to be re-read 6 | in order for changes to take effect. 7 | 8 | ## Table of contents 9 | 10 | ### Constructors 11 | 12 | - [constructor](WaveFileSettings.md#constructor) 13 | 14 | ### Properties 15 | 16 | - [SUPPORTED\_TAG\_TYPES](WaveFileSettings.md#supported_tag_types) 17 | 18 | ### Accessors 19 | 20 | - [defaultTagTypes](WaveFileSettings.md#defaulttagtypes) 21 | 22 | ## Constructors 23 | 24 | ### constructor 25 | 26 | • **new WaveFileSettings**() 27 | 28 | ## Properties 29 | 30 | ### SUPPORTED\_TAG\_TYPES 31 | 32 | ▪ `Static` `Readonly` **SUPPORTED\_TAG\_TYPES**: `number` 33 | 34 | The types of tags that are supported by WAV files. 35 | 36 | ## Accessors 37 | 38 | ### defaultTagTypes 39 | 40 | • `Static` `get` **defaultTagTypes**(): [`TagTypes`](../enums/TagTypes.md) 41 | 42 | Gets the default types of tags for an WAV file. When opening a file, if these tag types do 43 | not exist on the file, they will be created. 44 | 45 | #### Returns 46 | 47 | [`TagTypes`](../enums/TagTypes.md) 48 | 49 | • `Static` `set` **defaultTagTypes**(`value`): `void` 50 | 51 | Sets the default types of tags for an WAV file. When opening a file, if these tag types do 52 | not exist on the file, they will be created. See [SUPPORTED_TAG_TYPES](WaveFileSettings.md#supported_tag_types) for a list of tag 53 | types that are supported by node-taglib-sharp for WAV files. 54 | 55 | #### Parameters 56 | 57 | | Name | Type | 58 | | :------ | :------ | 59 | | `value` | [`TagTypes`](../enums/TagTypes.md) | 60 | 61 | #### Returns 62 | 63 | `void` 64 | -------------------------------------------------------------------------------- /docs/enums/ApeTagItemType.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / ApeTagItemType 2 | 3 | # Enumeration: ApeTagItemType 4 | 5 | Indicates the type of data stored in a [ApeTagItem](../classes/ApeTagItem.md) object. 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [Binary](ApeTagItemType.md#binary) 12 | - [Locator](ApeTagItemType.md#locator) 13 | - [Text](ApeTagItemType.md#text) 14 | 15 | ## Enumeration Members 16 | 17 | ### Binary 18 | 19 | • **Binary** = ``1`` 20 | 21 | Item contains binary data 22 | 23 | ___ 24 | 25 | ### Locator 26 | 27 | • **Locator** = ``2`` 28 | 29 | Item contains a locator (file path/URL) for external information 30 | 31 | ___ 32 | 33 | ### Text 34 | 35 | • **Text** = ``0`` 36 | 37 | Item contains unicode text 38 | -------------------------------------------------------------------------------- /docs/enums/AsfObjectDataType.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / AsfObjectDataType 2 | 3 | # Enumeration: AsfObjectDataType 4 | 5 | Indicates the type of data stored in a ContentDescriptor or MetadataDescriptor object. 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [Bool](AsfObjectDataType.md#bool) 12 | - [Bytes](AsfObjectDataType.md#bytes) 13 | - [DWord](AsfObjectDataType.md#dword) 14 | - [Guid](AsfObjectDataType.md#guid) 15 | - [QWord](AsfObjectDataType.md#qword) 16 | - [Unicode](AsfObjectDataType.md#unicode) 17 | - [Word](AsfObjectDataType.md#word) 18 | 19 | ## Enumeration Members 20 | 21 | ### Bool 22 | 23 | • **Bool** = ``2`` 24 | 25 | The descriptor contains a boolean value. 26 | 27 | ___ 28 | 29 | ### Bytes 30 | 31 | • **Bytes** = ``1`` 32 | 33 | The descriptor contains binary data. 34 | 35 | ___ 36 | 37 | ### DWord 38 | 39 | • **DWord** = ``3`` 40 | 41 | The descriptor contains a 4-byte DWORD value. 42 | 43 | ___ 44 | 45 | ### Guid 46 | 47 | • **Guid** = ``6`` 48 | 49 | The descriptor contains a 16-byte GUID value. 50 | 51 | ___ 52 | 53 | ### QWord 54 | 55 | • **QWord** = ``4`` 56 | 57 | The descriptor contains an 8-byte QWORD value. 58 | 59 | ___ 60 | 61 | ### Unicode 62 | 63 | • **Unicode** = ``0`` 64 | 65 | The descriptor contains Unicode (UTF-16LE) text. 66 | 67 | ___ 68 | 69 | ### Word 70 | 71 | • **Word** = ``5`` 72 | 73 | The descriptor contains a 2-byte WORD value. 74 | -------------------------------------------------------------------------------- /docs/enums/AviStreamType.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / AviStreamType 2 | 3 | # Enumeration: AviStreamType 4 | 5 | IDs for an AVI stream types. 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [AudioStream](AviStreamType.md#audiostream) 12 | - [MidiStream](AviStreamType.md#midistream) 13 | - [TextStream](AviStreamType.md#textstream) 14 | - [VideoStream](AviStreamType.md#videostream) 15 | 16 | ## Enumeration Members 17 | 18 | ### AudioStream 19 | 20 | • **AudioStream** = ``1935963489`` 21 | 22 | Audio Stream 23 | 24 | ___ 25 | 26 | ### MidiStream 27 | 28 | • **MidiStream** = ``1919183213`` 29 | 30 | MIDI Stream 31 | 32 | ___ 33 | 34 | ### TextStream 35 | 36 | • **TextStream** = ``1937012852`` 37 | 38 | Text stream 39 | 40 | ___ 41 | 42 | ### VideoStream 43 | 44 | • **VideoStream** = ``1935960438`` 45 | 46 | Video stream 47 | -------------------------------------------------------------------------------- /docs/enums/FileAccessMode.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / FileAccessMode 2 | 3 | # Enumeration: FileAccessMode 4 | 5 | Specifies the type of file access operations currently permitted on an instance of [File](../classes/File.md) 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [Closed](FileAccessMode.md#closed) 12 | - [Read](FileAccessMode.md#read) 13 | - [Write](FileAccessMode.md#write) 14 | 15 | ## Enumeration Members 16 | 17 | ### Closed 18 | 19 | • **Closed** = ``2`` 20 | 21 | The file is closed for both read and write operations 22 | 23 | ___ 24 | 25 | ### Read 26 | 27 | • **Read** = ``0`` 28 | 29 | Read operations can be performed. 30 | 31 | ___ 32 | 33 | ### Write 34 | 35 | • **Write** = ``1`` 36 | 37 | Read and write operations can be performed 38 | -------------------------------------------------------------------------------- /docs/enums/FlacBlockType.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / FlacBlockType 2 | 3 | # Enumeration: FlacBlockType 4 | 5 | Specifies the contents of a FLAC block. 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [Application](FlacBlockType.md#application) 12 | - [CueSheet](FlacBlockType.md#cuesheet) 13 | - [Padding](FlacBlockType.md#padding) 14 | - [Picture](FlacBlockType.md#picture) 15 | - [SeekTable](FlacBlockType.md#seektable) 16 | - [StreamInfo](FlacBlockType.md#streaminfo) 17 | - [XiphComment](FlacBlockType.md#xiphcomment) 18 | 19 | ## Enumeration Members 20 | 21 | ### Application 22 | 23 | • **Application** = ``2`` 24 | 25 | Block contains application data. 26 | 27 | ___ 28 | 29 | ### CueSheet 30 | 31 | • **CueSheet** = ``5`` 32 | 33 | Block contains a cue sheet. 34 | 35 | ___ 36 | 37 | ### Padding 38 | 39 | • **Padding** = ``1`` 40 | 41 | Block contains padding. 42 | 43 | ___ 44 | 45 | ### Picture 46 | 47 | • **Picture** = ``6`` 48 | 49 | Block contains a picture. 50 | 51 | ___ 52 | 53 | ### SeekTable 54 | 55 | • **SeekTable** = ``3`` 56 | 57 | Block contains a seek table. 58 | 59 | ___ 60 | 61 | ### StreamInfo 62 | 63 | • **StreamInfo** = ``0`` 64 | 65 | Block contains stream information. 66 | 67 | ___ 68 | 69 | ### XiphComment 70 | 71 | • **XiphComment** = ``4`` 72 | 73 | Block contains a Xiph comment. 74 | -------------------------------------------------------------------------------- /docs/enums/Id3v2FrameFlags.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / Id3v2FrameFlags 2 | 3 | # Enumeration: Id3v2FrameFlags 4 | 5 | Indicates the flags applied to a [Id3v2FrameHeader](../classes/Id3v2FrameHeader.md) object. 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [Compression](Id3v2FrameFlags.md#compression) 12 | - [DataLengthIndicator](Id3v2FrameFlags.md#datalengthindicator) 13 | - [Encryption](Id3v2FrameFlags.md#encryption) 14 | - [FileAlterPreservation](Id3v2FrameFlags.md#filealterpreservation) 15 | - [GroupingIdentity](Id3v2FrameFlags.md#groupingidentity) 16 | - [None](Id3v2FrameFlags.md#none) 17 | - [ReadOnly](Id3v2FrameFlags.md#readonly) 18 | - [TagAlterPreservation](Id3v2FrameFlags.md#tagalterpreservation) 19 | - [Unsynchronized](Id3v2FrameFlags.md#unsynchronized) 20 | 21 | ## Enumeration Members 22 | 23 | ### Compression 24 | 25 | • **Compression** = ``8`` 26 | 27 | Frame data is compressed. 28 | 29 | ___ 30 | 31 | ### DataLengthIndicator 32 | 33 | • **DataLengthIndicator** = ``1`` 34 | 35 | Frame has a data length indicator. 36 | 37 | ___ 38 | 39 | ### Encryption 40 | 41 | • **Encryption** = ``4`` 42 | 43 | Frame data is encrypted. 44 | 45 | ___ 46 | 47 | ### FileAlterPreservation 48 | 49 | • **FileAlterPreservation** = ``8192`` 50 | 51 | Frame is to be deleted if the file is altered. 52 | 53 | ___ 54 | 55 | ### GroupingIdentity 56 | 57 | • **GroupingIdentity** = ``64`` 58 | 59 | Frame has a grouping identity. 60 | 61 | ___ 62 | 63 | ### None 64 | 65 | • **None** = ``0`` 66 | 67 | Header contains no flags. 68 | 69 | ___ 70 | 71 | ### ReadOnly 72 | 73 | • **ReadOnly** = ``4096`` 74 | 75 | Frame is read-only and should not be altered. 76 | 77 | ___ 78 | 79 | ### TagAlterPreservation 80 | 81 | • **TagAlterPreservation** = ``16384`` 82 | 83 | Frame is to be deleted if the tag is altered. 84 | 85 | ___ 86 | 87 | ### Unsynchronized 88 | 89 | • **Unsynchronized** = ``2`` 90 | 91 | Frame data has been unsynchronized using the ID3v2 unsynchronization scheme. 92 | -------------------------------------------------------------------------------- /docs/enums/Id3v2RelativeVolumeFrameChannelType.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / Id3v2RelativeVolumeFrameChannelType 2 | 3 | # Enumeration: Id3v2RelativeVolumeFrameChannelType 4 | 5 | Type of channel data to get from or set to a RelativeVolumeFrame object 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [BackCenter](Id3v2RelativeVolumeFrameChannelType.md#backcenter) 12 | - [BackLeft](Id3v2RelativeVolumeFrameChannelType.md#backleft) 13 | - [BackRight](Id3v2RelativeVolumeFrameChannelType.md#backright) 14 | - [FrontCentre](Id3v2RelativeVolumeFrameChannelType.md#frontcentre) 15 | - [FrontLeft](Id3v2RelativeVolumeFrameChannelType.md#frontleft) 16 | - [FrontRight](Id3v2RelativeVolumeFrameChannelType.md#frontright) 17 | - [MasterVolume](Id3v2RelativeVolumeFrameChannelType.md#mastervolume) 18 | - [Other](Id3v2RelativeVolumeFrameChannelType.md#other) 19 | - [Subwoofer](Id3v2RelativeVolumeFrameChannelType.md#subwoofer) 20 | 21 | ## Enumeration Members 22 | 23 | ### BackCenter 24 | 25 | • **BackCenter** = ``7`` 26 | 27 | Channel data for back center speaker 28 | 29 | ___ 30 | 31 | ### BackLeft 32 | 33 | • **BackLeft** = ``5`` 34 | 35 | Channel data for back left speaker 36 | 37 | ___ 38 | 39 | ### BackRight 40 | 41 | • **BackRight** = ``4`` 42 | 43 | Channel data for center right speaker 44 | 45 | ___ 46 | 47 | ### FrontCentre 48 | 49 | • **FrontCentre** = ``6`` 50 | 51 | Channel data for front center speaker 52 | 53 | ___ 54 | 55 | ### FrontLeft 56 | 57 | • **FrontLeft** = ``3`` 58 | 59 | Channel data for front left speaker 60 | 61 | ___ 62 | 63 | ### FrontRight 64 | 65 | • **FrontRight** = ``2`` 66 | 67 | Channel data for the front right speaker 68 | 69 | ___ 70 | 71 | ### MasterVolume 72 | 73 | • **MasterVolume** = ``1`` 74 | 75 | Channel data for the master volume 76 | 77 | ___ 78 | 79 | ### Other 80 | 81 | • **Other** = ``0`` 82 | 83 | Channel data for some other speaker 84 | 85 | ___ 86 | 87 | ### Subwoofer 88 | 89 | • **Subwoofer** = ``8`` 90 | 91 | Channel data for subwoofer 92 | -------------------------------------------------------------------------------- /docs/enums/Id3v2SynchronizedTextType.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / Id3v2SynchronizedTextType 2 | 3 | # Enumeration: Id3v2SynchronizedTextType 4 | 5 | Specifies the type of text contained in a synchronized lyrics frame 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [Chord](Id3v2SynchronizedTextType.md#chord) 12 | - [Events](Id3v2SynchronizedTextType.md#events) 13 | - [ImageUrls](Id3v2SynchronizedTextType.md#imageurls) 14 | - [Lyrics](Id3v2SynchronizedTextType.md#lyrics) 15 | - [Movement](Id3v2SynchronizedTextType.md#movement) 16 | - [Other](Id3v2SynchronizedTextType.md#other) 17 | - [TextTranscription](Id3v2SynchronizedTextType.md#texttranscription) 18 | - [Trivia](Id3v2SynchronizedTextType.md#trivia) 19 | - [WebpageUrls](Id3v2SynchronizedTextType.md#webpageurls) 20 | 21 | ## Enumeration Members 22 | 23 | ### Chord 24 | 25 | • **Chord** = ``5`` 26 | 27 | Text contains chord changes that occur in the music 28 | 29 | ___ 30 | 31 | ### Events 32 | 33 | • **Events** = ``4`` 34 | 35 | Text describes events that occur 36 | 37 | ___ 38 | 39 | ### ImageUrls 40 | 41 | • **ImageUrls** = ``8`` 42 | 43 | Text contains URLs for relevant images 44 | 45 | ___ 46 | 47 | ### Lyrics 48 | 49 | • **Lyrics** = ``1`` 50 | 51 | Text contains lyrical data 52 | 53 | ___ 54 | 55 | ### Movement 56 | 57 | • **Movement** = ``3`` 58 | 59 | Text lists the movements in the piece 60 | 61 | ___ 62 | 63 | ### Other 64 | 65 | • **Other** = ``0`` 66 | 67 | Text is some other type of text 68 | 69 | ___ 70 | 71 | ### TextTranscription 72 | 73 | • **TextTranscription** = ``2`` 74 | 75 | Text contains a transcription 76 | 77 | ___ 78 | 79 | ### Trivia 80 | 81 | • **Trivia** = ``6`` 82 | 83 | Text contains trivia or "pop up" information about the media 84 | 85 | ___ 86 | 87 | ### WebpageUrls 88 | 89 | • **WebpageUrls** = ``7`` 90 | 91 | Text contains URLs for relevant webpages 92 | -------------------------------------------------------------------------------- /docs/enums/Id3v2TagHeaderFlags.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / Id3v2TagHeaderFlags 2 | 3 | # Enumeration: Id3v2TagHeaderFlags 4 | 5 | Indicates the flags applied to a [Id3v2TagHeader](../classes/Id3v2TagHeader.md) object. 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [ExperimentalIndicator](Id3v2TagHeaderFlags.md#experimentalindicator) 12 | - [ExtendedHeader](Id3v2TagHeaderFlags.md#extendedheader) 13 | - [FooterPresent](Id3v2TagHeaderFlags.md#footerpresent) 14 | - [None](Id3v2TagHeaderFlags.md#none) 15 | - [Unsynchronization](Id3v2TagHeaderFlags.md#unsynchronization) 16 | 17 | ## Enumeration Members 18 | 19 | ### ExperimentalIndicator 20 | 21 | • **ExperimentalIndicator** = ``32`` 22 | 23 | The tag described by the header is experimental. 24 | 25 | ___ 26 | 27 | ### ExtendedHeader 28 | 29 | • **ExtendedHeader** = ``64`` 30 | 31 | The tag described by the header contains an extended header. 32 | 33 | ___ 34 | 35 | ### FooterPresent 36 | 37 | • **FooterPresent** = ``16`` 38 | 39 | The tag described by the header contains a footer. 40 | 41 | ___ 42 | 43 | ### None 44 | 45 | • **None** = ``0`` 46 | 47 | The header contains no flags. 48 | 49 | ___ 50 | 51 | ### Unsynchronization 52 | 53 | • **Unsynchronization** = ``128`` 54 | 55 | The tag described by the header has been unsynchronized using the ID3v2 unsynchronization 56 | scheme. 57 | -------------------------------------------------------------------------------- /docs/enums/Id3v2TimestampFormat.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / Id3v2TimestampFormat 2 | 3 | # Enumeration: Id3v2TimestampFormat 4 | 5 | Specifies the timestamp format used by a few frame types. 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [AbsoluteMilliseconds](Id3v2TimestampFormat.md#absolutemilliseconds) 12 | - [AbsoluteMpegFrames](Id3v2TimestampFormat.md#absolutempegframes) 13 | - [Unknown](Id3v2TimestampFormat.md#unknown) 14 | 15 | ## Enumeration Members 16 | 17 | ### AbsoluteMilliseconds 18 | 19 | • **AbsoluteMilliseconds** = ``2`` 20 | 21 | Timestamp represents the number of milliseconds since the beginning of the audio stream 22 | 23 | ___ 24 | 25 | ### AbsoluteMpegFrames 26 | 27 | • **AbsoluteMpegFrames** = ``1`` 28 | 29 | Timestamp represents the number of MPEG frames since the beginning of the audio stream 30 | 31 | ___ 32 | 33 | ### Unknown 34 | 35 | • **Unknown** = ``0`` 36 | 37 | Timestamp is of unknown format 38 | -------------------------------------------------------------------------------- /docs/enums/MediaTypes.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / MediaTypes 2 | 3 | # Enumeration: MediaTypes 4 | 5 | Indicates the types o media represented by a [ICodec](../interfaces/ICodec.md) or [Properties](../classes/Properties.md). These values 6 | can be combined to represent multiple media types. 7 | 8 | ## Table of contents 9 | 10 | ### Enumeration Members 11 | 12 | - [Audio](MediaTypes.md#audio) 13 | - [LosslessAudio](MediaTypes.md#losslessaudio) 14 | - [None](MediaTypes.md#none) 15 | - [Photo](MediaTypes.md#photo) 16 | - [Text](MediaTypes.md#text) 17 | - [Video](MediaTypes.md#video) 18 | 19 | ## Enumeration Members 20 | 21 | ### Audio 22 | 23 | • **Audio** = ``1`` 24 | 25 | Audio is present 26 | 27 | ___ 28 | 29 | ### LosslessAudio 30 | 31 | • **LosslessAudio** = ``17`` 32 | 33 | Lossless audio is present. This also implies audio is present. 34 | 35 | ___ 36 | 37 | ### None 38 | 39 | • **None** = ``0`` 40 | 41 | No media is present 42 | 43 | ___ 44 | 45 | ### Photo 46 | 47 | • **Photo** = ``4`` 48 | 49 | A photo is present 50 | 51 | ___ 52 | 53 | ### Text 54 | 55 | • **Text** = ``8`` 56 | 57 | Text is present 58 | 59 | ___ 60 | 61 | ### Video 62 | 63 | • **Video** = ``2`` 64 | 65 | Video is present 66 | -------------------------------------------------------------------------------- /docs/enums/Mpeg4AppleDataBoxFlagType.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / Mpeg4AppleDataBoxFlagType 2 | 3 | # Enumeration: Mpeg4AppleDataBoxFlagType 4 | 5 | Specifies the type of data contained in a box. 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [ContainsBmpData](Mpeg4AppleDataBoxFlagType.md#containsbmpdata) 12 | - [ContainsData](Mpeg4AppleDataBoxFlagType.md#containsdata) 13 | - [ContainsJpegData](Mpeg4AppleDataBoxFlagType.md#containsjpegdata) 14 | - [ContainsPngData](Mpeg4AppleDataBoxFlagType.md#containspngdata) 15 | - [ContainsText](Mpeg4AppleDataBoxFlagType.md#containstext) 16 | - [ForTempo](Mpeg4AppleDataBoxFlagType.md#fortempo) 17 | 18 | ## Enumeration Members 19 | 20 | ### ContainsBmpData 21 | 22 | • **ContainsBmpData** = ``27`` 23 | 24 | The box contains a raw BMP image. 25 | 26 | ___ 27 | 28 | ### ContainsData 29 | 30 | • **ContainsData** = ``0`` 31 | 32 | The box contains binary data. 33 | 34 | ___ 35 | 36 | ### ContainsJpegData 37 | 38 | • **ContainsJpegData** = ``13`` 39 | 40 | The box contains a raw JPEG image. 41 | 42 | ___ 43 | 44 | ### ContainsPngData 45 | 46 | • **ContainsPngData** = ``14`` 47 | 48 | The box contains a raw PNG image. 49 | 50 | ___ 51 | 52 | ### ContainsText 53 | 54 | • **ContainsText** = ``1`` 55 | 56 | The box contains UTF-8 text. 57 | 58 | ___ 59 | 60 | ### ForTempo 61 | 62 | • **ForTempo** = ``21`` 63 | 64 | The box contains data for a tempo box. 65 | -------------------------------------------------------------------------------- /docs/enums/MpegAudioChannelMode.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / MpegAudioChannelMode 2 | 3 | # Enumeration: MpegAudioChannelMode 4 | 5 | Indicates the MPEG audio channel mode of a file or stream. 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [DualChannel](MpegAudioChannelMode.md#dualchannel) 12 | - [JointStereo](MpegAudioChannelMode.md#jointstereo) 13 | - [SingleChannel](MpegAudioChannelMode.md#singlechannel) 14 | - [Stereo](MpegAudioChannelMode.md#stereo) 15 | 16 | ## Enumeration Members 17 | 18 | ### DualChannel 19 | 20 | • **DualChannel** = ``2`` 21 | 22 | Dual Channel Mono 23 | 24 | ___ 25 | 26 | ### JointStereo 27 | 28 | • **JointStereo** = ``1`` 29 | 30 | Joint Stereo 31 | 32 | ___ 33 | 34 | ### SingleChannel 35 | 36 | • **SingleChannel** = ``3`` 37 | 38 | Single Channel Mono 39 | 40 | ___ 41 | 42 | ### Stereo 43 | 44 | • **Stereo** = ``0`` 45 | 46 | Stereo 47 | -------------------------------------------------------------------------------- /docs/enums/MpegVersion.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / MpegVersion 2 | 3 | # Enumeration: MpegVersion 4 | 5 | Indicates the MPEG version of a file or stream. 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [Unknown](MpegVersion.md#unknown) 12 | - [Version1](MpegVersion.md#version1) 13 | - [Version2](MpegVersion.md#version2) 14 | - [Version25](MpegVersion.md#version25) 15 | 16 | ## Enumeration Members 17 | 18 | ### Unknown 19 | 20 | • **Unknown** = ``-1`` 21 | 22 | Unknown version 23 | 24 | ___ 25 | 26 | ### Version1 27 | 28 | • **Version1** = ``0`` 29 | 30 | MPEG-1 31 | 32 | ___ 33 | 34 | ### Version2 35 | 36 | • **Version2** = ``1`` 37 | 38 | MPEG-2 39 | 40 | ___ 41 | 42 | ### Version25 43 | 44 | • **Version25** = ``2`` 45 | 46 | MPEG-2.5 47 | -------------------------------------------------------------------------------- /docs/enums/ReadStyle.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / ReadStyle 2 | 3 | # Enumeration: ReadStyle 4 | 5 | Specifies the options to use when reading the media. Can be treated as flags. 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [Average](ReadStyle.md#average) 12 | - [None](ReadStyle.md#none) 13 | - [PictureLazy](ReadStyle.md#picturelazy) 14 | 15 | ## Enumeration Members 16 | 17 | ### Average 18 | 19 | • **Average** = ``2`` 20 | 21 | The media properties will be read with average accuracy. 22 | 23 | ___ 24 | 25 | ### None 26 | 27 | • **None** = ``0`` 28 | 29 | The media properties will not be read. 30 | 31 | ___ 32 | 33 | ### PictureLazy 34 | 35 | • **PictureLazy** = ``4`` 36 | 37 | Use the [PictureLazy](../classes/PictureLazy.md) class in the property [pictures](../classes/Tag.md#pictures). This will avoid 38 | loading picture content when reading the tag. Picture will be read lazily, when the picture 39 | content is accessed. 40 | -------------------------------------------------------------------------------- /docs/enums/SeekOrigin.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / SeekOrigin 2 | 3 | # Enumeration: SeekOrigin 4 | 5 | Indicates there the seek operation should begin. 6 | 7 | ## Table of contents 8 | 9 | ### Enumeration Members 10 | 11 | - [Begin](SeekOrigin.md#begin) 12 | - [Current](SeekOrigin.md#current) 13 | - [End](SeekOrigin.md#end) 14 | 15 | ## Enumeration Members 16 | 17 | ### Begin 18 | 19 | • **Begin** = ``0`` 20 | 21 | Seek should begin at the start of the file. 22 | 23 | ___ 24 | 25 | ### Current 26 | 27 | • **Current** = ``1`` 28 | 29 | Seek should begin at the current position in the file. 30 | 31 | ___ 32 | 33 | ### End 34 | 35 | • **End** = ``2`` 36 | 37 | Seek should begin at the end of the file. 38 | -------------------------------------------------------------------------------- /docs/enums/StringType.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / StringType 2 | 3 | # Enumeration: StringType 4 | 5 | **`Summary`** 6 | 7 | Specifies the text encoding used when converting betweenInclusive a string and a 8 | [ByteVector](../classes/ByteVector.md). 9 | 10 | **`Remarks`** 11 | 12 | This enumeration is used by [fromString](../classes/ByteVector.md#fromstring) and 13 | [toString](../classes/ByteVector.md#tostring) 14 | 15 | ## Table of contents 16 | 17 | ### Enumeration Members 18 | 19 | - [Hex](StringType.md#hex) 20 | - [Latin1](StringType.md#latin1) 21 | - [UTF16](StringType.md#utf16) 22 | - [UTF16BE](StringType.md#utf16be) 23 | - [UTF16LE](StringType.md#utf16le) 24 | - [UTF8](StringType.md#utf8) 25 | 26 | ## Enumeration Members 27 | 28 | ### Hex 29 | 30 | • **Hex** = ``5`` 31 | 32 | **`Summary`** 33 | 34 | The string is to be encoded as a hex string for each byte (eg, 0x00, 0x12, 0xAF). 35 | Intended to be used for debugging purposes, only. 36 | 37 | ___ 38 | 39 | ### Latin1 40 | 41 | • **Latin1** = ``0`` 42 | 43 | **`Summary`** 44 | 45 | The string is to be Latin-1 encoded. 46 | 47 | ___ 48 | 49 | ### UTF16 50 | 51 | • **UTF16** = ``1`` 52 | 53 | **`Summary`** 54 | 55 | The string is to be UTF-16 encoded. 56 | 57 | ___ 58 | 59 | ### UTF16BE 60 | 61 | • **UTF16BE** = ``2`` 62 | 63 | **`Summary`** 64 | 65 | The string is to be UTF-16BE encoded. 66 | 67 | ___ 68 | 69 | ### UTF16LE 70 | 71 | • **UTF16LE** = ``4`` 72 | 73 | **`Summary`** 74 | 75 | The string is to be UTF-16LE encoded. 76 | 77 | ___ 78 | 79 | ### UTF8 80 | 81 | • **UTF8** = ``3`` 82 | 83 | **`Summary`** 84 | 85 | The string is to be UTF-8 encoded. 86 | -------------------------------------------------------------------------------- /docs/interfaces/IAudioCodec.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / IAudioCodec 2 | 3 | # Interface: IAudioCodec 4 | 5 | Interface that inherits the common codec information and adds audio-specific information. 6 | When dealing with an [ICodec](ICodec.md), if [mediaTypes](ICodec.md#mediatypes) contains 7 | [Audio](../enums/MediaTypes.md#audio), it is safe to assume that the object also inherits [IAudioCodec](IAudioCodec.md) 8 | and can be recast without issue. 9 | 10 | ## Hierarchy 11 | 12 | - [`ICodec`](ICodec.md) 13 | 14 | ↳ **`IAudioCodec`** 15 | 16 | ↳↳ [`ILosslessAudioCodec`](ILosslessAudioCodec.md) 17 | 18 | ## Implemented by 19 | 20 | - [`Mpeg4IsoAudioSampleEntry`](../classes/Mpeg4IsoAudioSampleEntry.md) 21 | - [`MpegAudioHeader`](../classes/MpegAudioHeader.md) 22 | - [`OggOpusCodec`](../classes/OggOpusCodec.md) 23 | - [`OggVorbisCodec`](../classes/OggVorbisCodec.md) 24 | 25 | ## Table of contents 26 | 27 | ### Properties 28 | 29 | - [audioBitrate](IAudioCodec.md#audiobitrate) 30 | - [audioChannels](IAudioCodec.md#audiochannels) 31 | - [audioSampleRate](IAudioCodec.md#audiosamplerate) 32 | - [description](IAudioCodec.md#description) 33 | - [durationMilliseconds](IAudioCodec.md#durationmilliseconds) 34 | - [mediaTypes](IAudioCodec.md#mediatypes) 35 | 36 | ## Properties 37 | 38 | ### audioBitrate 39 | 40 | • **audioBitrate**: `number` 41 | 42 | Bitrate of the audio in kilobits per second represented by the current instance. 43 | 44 | ___ 45 | 46 | ### audioChannels 47 | 48 | • **audioChannels**: `number` 49 | 50 | Number of channels in the audio represented by the current instance. 51 | 52 | ___ 53 | 54 | ### audioSampleRate 55 | 56 | • **audioSampleRate**: `number` 57 | 58 | Sample rate of the audio represented by the current instance. 59 | 60 | ___ 61 | 62 | ### description 63 | 64 | • **description**: `string` 65 | 66 | Gets a text description of the media represented by the current instance. 67 | 68 | #### Inherited from 69 | 70 | [ICodec](ICodec.md).[description](ICodec.md#description) 71 | 72 | ___ 73 | 74 | ### durationMilliseconds 75 | 76 | • **durationMilliseconds**: `number` 77 | 78 | Duration of the media in milliseconds represented by the current instance. 79 | 80 | **`TODO`** 81 | 82 | Ensure milliseconds is the right way to interpret this field 83 | 84 | #### Inherited from 85 | 86 | [ICodec](ICodec.md).[durationMilliseconds](ICodec.md#durationmilliseconds) 87 | 88 | ___ 89 | 90 | ### mediaTypes 91 | 92 | • **mediaTypes**: [`MediaTypes`](../enums/MediaTypes.md) 93 | 94 | Types of media represented by the current instance, bitwise combined. 95 | 96 | #### Inherited from 97 | 98 | [ICodec](ICodec.md).[mediaTypes](ICodec.md#mediatypes) 99 | -------------------------------------------------------------------------------- /docs/interfaces/ICodec.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / ICodec 2 | 3 | # Interface: ICodec 4 | 5 | Interface that provides basic information common to all media codecs 6 | 7 | ## Hierarchy 8 | 9 | - **`ICodec`** 10 | 11 | ↳ [`IAudioCodec`](IAudioCodec.md) 12 | 13 | ↳ [`IVideoCodec`](IVideoCodec.md) 14 | 15 | ↳ [`IPhotoCodec`](IPhotoCodec.md) 16 | 17 | ↳ [`IOggCodec`](IOggCodec.md) 18 | 19 | ## Table of contents 20 | 21 | ### Properties 22 | 23 | - [description](ICodec.md#description) 24 | - [durationMilliseconds](ICodec.md#durationmilliseconds) 25 | - [mediaTypes](ICodec.md#mediatypes) 26 | 27 | ## Properties 28 | 29 | ### description 30 | 31 | • **description**: `string` 32 | 33 | Gets a text description of the media represented by the current instance. 34 | 35 | ___ 36 | 37 | ### durationMilliseconds 38 | 39 | • **durationMilliseconds**: `number` 40 | 41 | Duration of the media in milliseconds represented by the current instance. 42 | 43 | **`TODO`** 44 | 45 | Ensure milliseconds is the right way to interpret this field 46 | 47 | ___ 48 | 49 | ### mediaTypes 50 | 51 | • **mediaTypes**: [`MediaTypes`](../enums/MediaTypes.md) 52 | 53 | Types of media represented by the current instance, bitwise combined. 54 | -------------------------------------------------------------------------------- /docs/interfaces/IDisposable.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / IDisposable 2 | 3 | # Interface: IDisposable 4 | 5 | Interface for objects that can (and should) be disposed after they are no longer needed. 6 | 7 | ## Implemented by 8 | 9 | - [`File`](../classes/File.md) 10 | 11 | ## Table of contents 12 | 13 | ### Methods 14 | 15 | - [dispose](IDisposable.md#dispose) 16 | 17 | ## Methods 18 | 19 | ### dispose 20 | 21 | ▸ **dispose**(): `void` 22 | 23 | Disposes the current instance. 24 | 25 | #### Returns 26 | 27 | `void` 28 | -------------------------------------------------------------------------------- /docs/interfaces/IFileAbstraction.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / IFileAbstraction 2 | 3 | # Interface: IFileAbstraction 4 | 5 | This interface provides abstracted access to a file. It permits access to non-standard file 6 | systems and data retrieval methods. 7 | 8 | ## Implemented by 9 | 10 | - [`LocalFileAbstraction`](../classes/LocalFileAbstraction.md) 11 | 12 | ## Table of contents 13 | 14 | ### Properties 15 | 16 | - [name](IFileAbstraction.md#name) 17 | - [readStream](IFileAbstraction.md#readstream) 18 | - [writeStream](IFileAbstraction.md#writestream) 19 | 20 | ### Methods 21 | 22 | - [closeStream](IFileAbstraction.md#closestream) 23 | 24 | ## Properties 25 | 26 | ### name 27 | 28 | • **name**: `string` 29 | 30 | Name or identifier used by the implementation 31 | 32 | **`Remarks`** 33 | 34 | This value would typically represent a path or URL to be used when identifying 35 | the file system, but it could be any valid as appropriate for the implementation. 36 | 37 | ___ 38 | 39 | ### readStream 40 | 41 | • **readStream**: [`IStream`](IStream.md) 42 | 43 | Readable, seekable stream for the file referenced by the current instance. 44 | 45 | **`Remarks`** 46 | 47 | This property is typically used when constructing an instance of [File](../classes/File.md). 48 | Upon completion of the constructor [closeStream](IFileAbstraction.md#closestream) will be called to close the stream. 49 | If the stream is to be reused after this point, [closeStream](IFileAbstraction.md#closestream) should be implemented 50 | in a way to keep it open. 51 | 52 | ___ 53 | 54 | ### writeStream 55 | 56 | • **writeStream**: [`IStream`](IStream.md) 57 | 58 | Writable, seekable stream for the file referenced by the current instance. 59 | 60 | **`Remarks`** 61 | 62 | This property is typically used when saving a file with [save](../classes/File.md#save). Upon 63 | completion of the method, [closeStream](IFileAbstraction.md#closestream) will be called to close the stream. If the 64 | stream is to be reused after this point, [closeStream](IFileAbstraction.md#closestream) should be implemented in a way 65 | to keep it open 66 | 67 | ## Methods 68 | 69 | ### closeStream 70 | 71 | ▸ **closeStream**(`stream`): `void` 72 | 73 | Closes a stream created by the current instance. 74 | 75 | #### Parameters 76 | 77 | | Name | Type | Description | 78 | | :------ | :------ | :------ | 79 | | `stream` | [`IStream`](IStream.md) | Stream created by the current instance. | 80 | 81 | #### Returns 82 | 83 | `void` 84 | -------------------------------------------------------------------------------- /docs/interfaces/ILazy.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / ILazy 2 | 3 | # Interface: ILazy 4 | 5 | Interface for objects that can be lazily loaded. 6 | 7 | ## Implemented by 8 | 9 | - [`FlacBlock`](../classes/FlacBlock.md) 10 | - [`PictureLazy`](../classes/PictureLazy.md) 11 | - [`RiffList`](../classes/RiffList.md) 12 | - [`XiphPicture`](../classes/XiphPicture.md) 13 | 14 | ## Table of contents 15 | 16 | ### Properties 17 | 18 | - [isLoaded](ILazy.md#isloaded) 19 | 20 | ### Methods 21 | 22 | - [load](ILazy.md#load) 23 | 24 | ## Properties 25 | 26 | ### isLoaded 27 | 28 | • **isLoaded**: `boolean` 29 | 30 | Gets whether the object has been loaded. 31 | 32 | ## Methods 33 | 34 | ### load 35 | 36 | ▸ **load**(): `void` 37 | 38 | Loads the object. 39 | 40 | #### Returns 41 | 42 | `void` 43 | -------------------------------------------------------------------------------- /docs/interfaces/IPhotoCodec.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / IPhotoCodec 2 | 3 | # Interface: IPhotoCodec 4 | 5 | Interface that inherits the common codec information and adds photo-specific information. 6 | When dealing with an [ICodec](ICodec.md), if [mediaTypes](ICodec.md#mediatypes) contains 7 | [Photo](../enums/MediaTypes.md#photo), it is safe to assume that the object also inherits [IPhotoCodec](IPhotoCodec.md) 8 | and can be recast without issue. 9 | 10 | ## Hierarchy 11 | 12 | - [`ICodec`](ICodec.md) 13 | 14 | ↳ **`IPhotoCodec`** 15 | 16 | ## Implemented by 17 | 18 | - [`Properties`](../classes/Properties.md) 19 | 20 | ## Table of contents 21 | 22 | ### Properties 23 | 24 | - [description](IPhotoCodec.md#description) 25 | - [durationMilliseconds](IPhotoCodec.md#durationmilliseconds) 26 | - [mediaTypes](IPhotoCodec.md#mediatypes) 27 | - [photoHeight](IPhotoCodec.md#photoheight) 28 | - [photoQuality](IPhotoCodec.md#photoquality) 29 | - [photoWidth](IPhotoCodec.md#photowidth) 30 | 31 | ## Properties 32 | 33 | ### description 34 | 35 | • **description**: `string` 36 | 37 | Gets a text description of the media represented by the current instance. 38 | 39 | #### Inherited from 40 | 41 | [ICodec](ICodec.md).[description](ICodec.md#description) 42 | 43 | ___ 44 | 45 | ### durationMilliseconds 46 | 47 | • **durationMilliseconds**: `number` 48 | 49 | Duration of the media in milliseconds represented by the current instance. 50 | 51 | **`TODO`** 52 | 53 | Ensure milliseconds is the right way to interpret this field 54 | 55 | #### Inherited from 56 | 57 | [ICodec](ICodec.md).[durationMilliseconds](ICodec.md#durationmilliseconds) 58 | 59 | ___ 60 | 61 | ### mediaTypes 62 | 63 | • **mediaTypes**: [`MediaTypes`](../enums/MediaTypes.md) 64 | 65 | Types of media represented by the current instance, bitwise combined. 66 | 67 | #### Inherited from 68 | 69 | [ICodec](ICodec.md).[mediaTypes](ICodec.md#mediatypes) 70 | 71 | ___ 72 | 73 | ### photoHeight 74 | 75 | • **photoHeight**: `number` 76 | 77 | Height of the photo in pixels represented by the current instance. 78 | 79 | ___ 80 | 81 | ### photoQuality 82 | 83 | • **photoQuality**: `number` 84 | 85 | Format-specific quality indicator of the photo represented by the current instance. 86 | A value of `0` means there was no quality indicator for the format or file. 87 | 88 | ___ 89 | 90 | ### photoWidth 91 | 92 | • **photoWidth**: `number` 93 | 94 | Width of the photo in pixels represented by the current instance. 95 | -------------------------------------------------------------------------------- /docs/interfaces/IPicture.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / IPicture 2 | 3 | # Interface: IPicture 4 | 5 | Interface that provides generic information about a picture, including its contents, as used by 6 | various formats. 7 | 8 | ## Implemented by 9 | 10 | - [`Id3v2AttachmentFrame`](../classes/Id3v2AttachmentFrame.md) 11 | - [`Picture`](../classes/Picture.md) 12 | - [`PictureLazy`](../classes/PictureLazy.md) 13 | - [`XiphPicture`](../classes/XiphPicture.md) 14 | 15 | ## Table of contents 16 | 17 | ### Properties 18 | 19 | - [data](IPicture.md#data) 20 | - [description](IPicture.md#description) 21 | - [filename](IPicture.md#filename) 22 | - [mimeType](IPicture.md#mimetype) 23 | - [type](IPicture.md#type) 24 | 25 | ## Properties 26 | 27 | ### data 28 | 29 | • **data**: [`ByteVector`](../classes/ByteVector.md) 30 | 31 | Gets and sets the picture data stored in the current instance. 32 | 33 | ___ 34 | 35 | ### description 36 | 37 | • **description**: `string` 38 | 39 | Gets and sets a description of the picture stored in the current instance. Optional. 40 | 41 | ___ 42 | 43 | ### filename 44 | 45 | • **filename**: `string` 46 | 47 | Gets and sets a filename of the picture stored in the current instance. Optional. 48 | 49 | ___ 50 | 51 | ### mimeType 52 | 53 | • **mimeType**: `string` 54 | 55 | Gets and sets the mime-type of the picture data stored in the current instance. 56 | 57 | ___ 58 | 59 | ### type 60 | 61 | • **type**: [`PictureType`](../enums/PictureType.md) 62 | 63 | Gets and sets the type of the content visible in the picture stored in the current instance. 64 | -------------------------------------------------------------------------------- /docs/interfaces/IRiffChunk.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / IRiffChunk 2 | 3 | # Interface: IRiffChunk 4 | 5 | Interface for chunks that appear in a RIFF file. 6 | 7 | ## Implemented by 8 | 9 | - [`RiffList`](../classes/RiffList.md) 10 | 11 | ## Table of contents 12 | 13 | ### Properties 14 | 15 | - [chunkStart](IRiffChunk.md#chunkstart) 16 | - [fourcc](IRiffChunk.md#fourcc) 17 | - [originalDataSize](IRiffChunk.md#originaldatasize) 18 | - [originalTotalSize](IRiffChunk.md#originaltotalsize) 19 | 20 | ### Methods 21 | 22 | - [render](IRiffChunk.md#render) 23 | 24 | ## Properties 25 | 26 | ### chunkStart 27 | 28 | • **chunkStart**: `number` 29 | 30 | Offset into the file where the chunk begins. This is `undefined` if the object was 31 | constructed directly from data. 32 | 33 | ___ 34 | 35 | ### fourcc 36 | 37 | • **fourcc**: `string` 38 | 39 | FOURCC code for the chunk. 40 | 41 | ___ 42 | 43 | ### originalDataSize 44 | 45 | • **originalDataSize**: `number` 46 | 47 | Size of just the data contained within the current instance. Does not include the header or 48 | padding byte. This value does not update if contents of the chunk changes. 49 | 50 | ___ 51 | 52 | ### originalTotalSize 53 | 54 | • **originalTotalSize**: `number` 55 | 56 | Original size of the chunk, including header and padding byte. This value does not update if 57 | the contents of the chunk changes. 58 | 59 | ## Methods 60 | 61 | ### render 62 | 63 | ▸ **render**(): [`ByteVector`](../classes/ByteVector.md) 64 | 65 | Renders the chunk, including the header and padding byte. 66 | 67 | #### Returns 68 | 69 | [`ByteVector`](../classes/ByteVector.md) 70 | -------------------------------------------------------------------------------- /docs/interfaces/ISandwichFile.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / ISandwichFile 2 | 3 | # Interface: ISandwichFile 4 | 5 | Interface for a sandwich file. 6 | 7 | ## Implemented by 8 | 9 | - [`FlacFile`](../classes/FlacFile.md) 10 | - [`SandwichFile`](../classes/SandwichFile.md) 11 | 12 | ## Table of contents 13 | 14 | ### Properties 15 | 16 | - [mediaEndPosition](ISandwichFile.md#mediaendposition) 17 | - [mediaStartPosition](ISandwichFile.md#mediastartposition) 18 | 19 | ## Properties 20 | 21 | ### mediaEndPosition 22 | 23 | • `Readonly` **mediaEndPosition**: `number` 24 | 25 | Gets the position at which the media content of this file ends. 26 | 27 | ___ 28 | 29 | ### mediaStartPosition 30 | 31 | • `Readonly` **mediaStartPosition**: `number` 32 | 33 | Gets the position at which the media content of this file starts. 34 | -------------------------------------------------------------------------------- /docs/interfaces/IVideoCodec.md: -------------------------------------------------------------------------------- 1 | [node-taglib-sharp](../README.md) / [Exports](../modules.md) / IVideoCodec 2 | 3 | # Interface: IVideoCodec 4 | 5 | Interface that inherits the common codec information and adds video-specific information. 6 | When dealing with an [ICodec](ICodec.md), if [mediaTypes](ICodec.md#mediatypes) contains 7 | [Video](../enums/MediaTypes.md#video), it is safe to assume that the object also inherits [IVideoCodec](IVideoCodec.md) 8 | and can be recast without issue. 9 | 10 | ## Hierarchy 11 | 12 | - [`ICodec`](ICodec.md) 13 | 14 | ↳ **`IVideoCodec`** 15 | 16 | ## Implemented by 17 | 18 | - [`Mpeg4IsoVisualSampleEntry`](../classes/Mpeg4IsoVisualSampleEntry.md) 19 | - [`MpegVideoHeader`](../classes/MpegVideoHeader.md) 20 | - [`OggTheoraCodec`](../classes/OggTheoraCodec.md) 21 | - [`Properties`](../classes/Properties.md) 22 | - [`RiffBitmapInfoHeader`](../classes/RiffBitmapInfoHeader.md) 23 | 24 | ## Table of contents 25 | 26 | ### Properties 27 | 28 | - [description](IVideoCodec.md#description) 29 | - [durationMilliseconds](IVideoCodec.md#durationmilliseconds) 30 | - [mediaTypes](IVideoCodec.md#mediatypes) 31 | - [videoHeight](IVideoCodec.md#videoheight) 32 | - [videoWidth](IVideoCodec.md#videowidth) 33 | 34 | ## Properties 35 | 36 | ### description 37 | 38 | • **description**: `string` 39 | 40 | Gets a text description of the media represented by the current instance. 41 | 42 | #### Inherited from 43 | 44 | [ICodec](ICodec.md).[description](ICodec.md#description) 45 | 46 | ___ 47 | 48 | ### durationMilliseconds 49 | 50 | • **durationMilliseconds**: `number` 51 | 52 | Duration of the media in milliseconds represented by the current instance. 53 | 54 | **`TODO`** 55 | 56 | Ensure milliseconds is the right way to interpret this field 57 | 58 | #### Inherited from 59 | 60 | [ICodec](ICodec.md).[durationMilliseconds](ICodec.md#durationmilliseconds) 61 | 62 | ___ 63 | 64 | ### mediaTypes 65 | 66 | • **mediaTypes**: [`MediaTypes`](../enums/MediaTypes.md) 67 | 68 | Types of media represented by the current instance, bitwise combined. 69 | 70 | #### Inherited from 71 | 72 | [ICodec](ICodec.md).[mediaTypes](ICodec.md#mediatypes) 73 | 74 | ___ 75 | 76 | ### videoHeight 77 | 78 | • **videoHeight**: `number` 79 | 80 | Height of the video in pixels represented by the current instance. 81 | 82 | ___ 83 | 84 | ### videoWidth 85 | 86 | • **videoWidth**: `number` 87 | 88 | Width of the video in pixels represented by the current instance. 89 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-taglib-sharp", 3 | "description": "Read and write audio/video/picture tags using a similar interface to TagLib#", 4 | "version": "6.0.1", 5 | "license": "LGPL-2.1-or-later", 6 | "author": "Ben Russell (https://github.com/benrr101)", 7 | "repository": "github:benrr101/node-taglib-sharp", 8 | "bugs": "https://github.com/benrr101/node-taglib-sharp/issues", 9 | "main": "dist/index.js", 10 | "types": "dist/index.d.ts", 11 | "scripts": { 12 | "build": "tsc -p ./", 13 | "generate-docs": "typedoc --tsconfig tsconfig.json", 14 | "lint": "eslint -c .eslintrc.js --ext .ts ./src", 15 | "madge": "node node_modules/madge/bin/cli.js --warning --circular --extensions ts ./", 16 | "publish-coverage": "nyc report --reporter=text-lcov | coveralls", 17 | "test-unit": "mocha test-unit --ui bdd", 18 | "test-integration": "mocha test-integration --ui bdd", 19 | "test-unit-with-coverage": "nyc mocha test-unit --ui bdd" 20 | }, 21 | "engines": { 22 | "node": ">=12.16.1" 23 | }, 24 | "dependencies": { 25 | "iconv-lite": "^0.6.3", 26 | "os-locale": "^6.0.2", 27 | "uuid": "^8.3.2" 28 | }, 29 | "devDependencies": { 30 | "@istanbuljs/nyc-config-typescript": "^1.0.2", 31 | "@testdeck/mocha": "^0.3.3", 32 | "@types/chai": "^4.3.0", 33 | "@types/chai-as-promised": "^7.1.0", 34 | "@types/stream-buffers": "^3.0.2", 35 | "@types/uuid": "^8.3.4", 36 | "@typescript-eslint/eslint-plugin": "^5.15.0", 37 | "@typescript-eslint/parser": "^5.15.0", 38 | "chai": "^4.3.6", 39 | "chai-as-promised": "^7.1.1", 40 | "coveralls": "^3.1.1", 41 | "eslint": "^8.57.1", 42 | "eslint-plugin-import": "^2.25.4", 43 | "eslint-plugin-jsdoc": "^38.0.4", 44 | "eslint-plugin-prefer-arrow": "^1.2.3", 45 | "madge": "^4.0.1", 46 | "mocha": "^10.2.0", 47 | "nyc": "^15.1.0", 48 | "source-map-support": "^0.5.16", 49 | "stream-buffers": "^3.0.2", 50 | "ts-node": "^10.7.0", 51 | "typedoc": "github:benrr101/typedoc#dont-copy-remarks", 52 | "typedoc-plugin-markdown": "^3.14.0", 53 | "typemoq": "^2.1.0", 54 | "typescript": "^4.5.5" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/aac/aacFile.ts: -------------------------------------------------------------------------------- 1 | import AacAudioHeader from "./aacAudioHeader"; 2 | import AacFileSettings from "./aacFileSettings"; 3 | import SandwichFile from "../sandwich/sandwichFile"; 4 | import {CorruptFileError} from "../errors"; 5 | import {File, ReadStyle} from "../file"; 6 | import {IFileAbstraction} from "../fileAbstraction"; 7 | import {Properties} from "../properties"; 8 | import {TagTypes} from "../tag"; 9 | import {NumberUtils} from "../utils"; 10 | 11 | /** 12 | * This class extends {@link File} to provide tagging and properties for ADTS AAC audio files. 13 | */ 14 | export default class AacFile extends SandwichFile { 15 | private static readonly DEFAULT_TAG_LOCATION_MAPPING = new Map boolean>([ 16 | [TagTypes.Ape, () => AacFileSettings.preferApeTagAtFileEnd], 17 | [TagTypes.Id3v1, () => true], 18 | [TagTypes.Id3v2, () => AacFileSettings.preferId3v2TagAtFileEnd] 19 | ]); 20 | 21 | /** @inheritDoc */ 22 | public constructor(file: IFileAbstraction|string, propertiesStyle: ReadStyle) { 23 | super(file, propertiesStyle, AacFile.DEFAULT_TAG_LOCATION_MAPPING, AacFileSettings.defaultTagTypes); 24 | } 25 | 26 | protected readProperties(readStyle: ReadStyle): Properties { 27 | // Skip if we're not reading the properties 28 | if (!NumberUtils.hasFlag(readStyle, ReadStyle.Average)) { 29 | return undefined; 30 | } 31 | 32 | // Only search the first 16k before giving up 33 | const firstHeader = AacAudioHeader.find(this, this.mediaStartPosition, 0x4000); 34 | if (!firstHeader) { 35 | throw new CorruptFileError("ADTS audio header not found"); 36 | } 37 | 38 | firstHeader.streamLength = this.mediaEndPosition - this.mediaStartPosition; 39 | return new Properties(firstHeader.durationMilliseconds, [firstHeader]); 40 | } 41 | } 42 | 43 | // ///////////////////////////////////////////////////////////////////////// 44 | // Register the file type 45 | [ 46 | "taglib/aac", 47 | "audio/aac" 48 | ].forEach((mt) => File.addFileType(mt, AacFile)); 49 | -------------------------------------------------------------------------------- /src/aiff/aiffFileSettings.ts: -------------------------------------------------------------------------------- 1 | import {TagTypes} from "../tag"; 2 | import {NumberUtils} from "../utils"; 3 | 4 | /** 5 | * This class contains settings related to AIFF file operations. Open files will need to be re-read 6 | * in order for changes to take effect. 7 | */ 8 | export default class AiffFileSettings { 9 | public static readonly SUPPORTED_TAG_TYPES = TagTypes.Id3v2; 10 | 11 | private static _defaultTagTypes = TagTypes.Id3v2; 12 | 13 | /** 14 | * Gets the default types of tags for an AIFF file. When opening a file, if these tag types do 15 | * not exist on the file, they will be created. 16 | */ 17 | public static get defaultTagTypes(): TagTypes { return this._defaultTagTypes; } 18 | /** 19 | * Sets the default types of tags for an AIFF file. When opening a file, if these tag types do 20 | * not exist on the file, they will be created. See {@link SUPPORTED_TAG_TYPES} for a list of tag 21 | * types that are supported by node-taglib-sharp for AIFF files. 22 | */ 23 | public static set defaultTagTypes(value: TagTypes) { 24 | const unsupportedTagTypes = NumberUtils.uintAnd(value, ~this.SUPPORTED_TAG_TYPES); 25 | if (unsupportedTagTypes !== 0) { 26 | throw new Error( 27 | `Argument error: node-taglib-sharp does not support tag types ${unsupportedTagTypes} for AIFF files` 28 | ); 29 | } 30 | 31 | this._defaultTagTypes = value; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/ape/apeFile.ts: -------------------------------------------------------------------------------- 1 | import ApeFileSettings from "./apeFileSettings"; 2 | import SandwichFile from "../sandwich/sandwichFile"; 3 | import {ApeStreamHeader} from "./apeStreamHeader"; 4 | import {File, ReadStyle} from "../file"; 5 | import {IFileAbstraction} from "../fileAbstraction"; 6 | import {Properties} from "../properties"; 7 | import {TagTypes} from "../tag"; 8 | import {NumberUtils} from "../utils"; 9 | 10 | /** 11 | * Provides tagging and properties support for Monkey's Audio APE files. 12 | * Note, a {@link ApeTag} will be added automatically to any file that doesn't contain one. This 13 | * change does not affect the physical file until {@link File.save} is called and can be reversed 14 | * using the following method: `file.removeTags(file.tagTypes & ~file.tagTypesOnDisk);` 15 | */ 16 | export default class ApeFile extends SandwichFile { 17 | private static readonly DEFAULT_TAG_LOCATION_MAPPING = new Map boolean>([ 18 | [TagTypes.Ape, () => ApeFileSettings.preferApeTagAtFileEnd], 19 | [TagTypes.Id3v1, () => true], 20 | [TagTypes.Id3v2, () => ApeFileSettings.preferId3v2TagAtFileEnd] 21 | ]); 22 | 23 | /** @inheritDoc */ 24 | public constructor(file: IFileAbstraction|string, propertiesStyle: ReadStyle) { 25 | super(file, propertiesStyle, ApeFile.DEFAULT_TAG_LOCATION_MAPPING, ApeFileSettings.defaultTagTypes); 26 | } 27 | 28 | /** @inheritDoc */ 29 | protected readProperties(readStyle: ReadStyle): Properties { 30 | // Skip if we're not reading the properties 31 | if (!NumberUtils.hasFlag(readStyle, ReadStyle.Average)) { 32 | return undefined; 33 | } 34 | 35 | // Find the header and use it to generate the properties 36 | this.seek(this.mediaStartPosition); 37 | const headerBlock = this.readBlock(ApeStreamHeader.SIZE); 38 | const header = new ApeStreamHeader(headerBlock, this.mediaEndPosition - this.mediaStartPosition); 39 | return new Properties(header.durationMilliseconds, [header]); 40 | } 41 | } 42 | 43 | // ///////////////////////////////////////////////////////////////////////// 44 | // Register the file type 45 | [ 46 | "taglib/ape", 47 | "audio/x-ape", 48 | "audio/ape", 49 | "application/x-ape" 50 | ].forEach((mt) => File.addFileType(mt, ApeFile)); 51 | -------------------------------------------------------------------------------- /src/asf/objects/unknownObject.ts: -------------------------------------------------------------------------------- 1 | import BaseObject from "./baseObject"; 2 | import {ByteVector} from "../../byteVector"; 3 | import {ObjectType} from "../constants"; 4 | import {File} from "../../file"; 5 | import {Guards} from "../../utils"; 6 | 7 | /** 8 | * This class provides a representation of an ASF object that is unknown to the library, which can 9 | * be read from and written to disk. 10 | */ 11 | export default class UnknownObject extends BaseObject { 12 | private _data: ByteVector; 13 | 14 | private constructor() { 15 | super(); 16 | } 17 | 18 | /** 19 | * Constructs and initializes a new instance by reading the contents from a specified file. 20 | * @param file File from which the contents of the new instance will be read 21 | * @param position Index into the file where the object begins 22 | */ 23 | public static fromFile(file: File, position: number): UnknownObject { 24 | const instance = new UnknownObject(); 25 | instance.initializeFromFile(file, position); 26 | instance._data = file.readBlock(instance.originalSize - 24).toByteVector(); 27 | return instance; 28 | } 29 | 30 | // #region Properties 31 | 32 | /** 33 | * Gets the data contained in the current instance. 34 | */ 35 | public get data(): ByteVector { return this._data; } 36 | /** 37 | * Sets the data contained in the current instance. 38 | * @param value Data to store in the current instance. Must be truthy. 39 | */ 40 | public set data(value: ByteVector) { 41 | Guards.truthy(value, "value"); 42 | this._data = value; 43 | } 44 | 45 | /** @inheritDoc */ 46 | public get objectType(): ObjectType { return ObjectType.UnknownObject; } 47 | 48 | // #endregion 49 | 50 | /** @inheritDoc */ 51 | public render(): ByteVector { 52 | return super.renderInternal(this._data); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/asf/readWriteUtils.ts: -------------------------------------------------------------------------------- 1 | import UuidWrapper from "../uuidWrapper"; 2 | import {ByteVector, StringType} from "../byteVector"; 3 | import {File} from "../file"; 4 | 5 | /** 6 | * Utilities for reading and writing ASF data. 7 | * @internal 8 | */ 9 | export default { 10 | /** 11 | * Reads a 4-byte double word from the current instance. 12 | * @param file File to read the double word from 13 | */ 14 | readDWord: (file: File): number => { 15 | return file.readBlock(4).toUint(false); 16 | }, 17 | 18 | /** 19 | * Reads a 16-byte GUID from the current instance. 20 | * @param file File to read the guid from 21 | */ 22 | readGuid: (file: File): UuidWrapper => { 23 | return new UuidWrapper(file.readBlock(16)); 24 | }, 25 | 26 | /** 27 | * Reads an 8-byte quad word from the current instance. 28 | * @param file File to read the quad word from 29 | */ 30 | readQWord: (file: File): bigint => { 31 | return file.readBlock(8).toLong(false); 32 | }, 33 | 34 | /** 35 | * Reads a UTF-16LE string of specified length in bytes from the current instance. If null 36 | * byte is found before the end of specified end of the string, the string will be shortened 37 | * at the null byte. 38 | * @param length Length in bytes to read as the string 39 | * @param file File to read Unicode from 40 | */ 41 | readUnicode: (file: File, length: number): string => { 42 | const string = file.readBlock(length).toString(StringType.UTF16LE); 43 | const nullIndex = string.indexOf("\0"); 44 | return nullIndex >= 0 ? string.substring(0, nullIndex) : string; 45 | }, 46 | 47 | /** 48 | * Reads a 2-byte word from the current instance. 49 | * @param file File to read the word from 50 | */ 51 | readWord: (file: File): number => { 52 | return file.readBlock(2).toUshort(false); 53 | }, 54 | 55 | /** 56 | * Renders a 4-byte double word. 57 | * @param value Double word to render 58 | */ 59 | renderDWord: (value: number): ByteVector => { 60 | return ByteVector.fromUint(value, false); 61 | }, 62 | 63 | /** 64 | * Renders an 8-byte quad word. 65 | * @param value Quad word to render 66 | */ 67 | renderQWord: (value: bigint): ByteVector => { 68 | return ByteVector.fromUlong(value, false); 69 | }, 70 | 71 | /** 72 | * Renders a unicode string. 73 | * @param value Text to render 74 | */ 75 | renderUnicode: (value: string): ByteVector => { 76 | return ByteVector.concatenate( 77 | ByteVector.fromString(value, StringType.UTF16LE), 78 | ByteVector.fromUshort(0, false) 79 | ); 80 | }, 81 | 82 | /** 83 | * Renders a 2-byte word. 84 | * @param value Word to render 85 | */ 86 | renderWord: (value: number): ByteVector => { 87 | return ByteVector.fromUshort(value, false); 88 | }, 89 | }; 90 | -------------------------------------------------------------------------------- /src/ebml/ebmlParserOptions.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Class that stores the options used for parsing the current EBML element. 3 | */ 4 | export default interface EbmlParserOptions { 5 | /** 6 | * Maximum permitted length in bytes of element IDs. 7 | */ 8 | maxIdLength?: number; 9 | 10 | /** 11 | * Maximum permitted length in bytes of the expressions of all element data size. 12 | */ 13 | maxSizeLength?: number; 14 | } 15 | -------------------------------------------------------------------------------- /src/ebml/ids.ts: -------------------------------------------------------------------------------- 1 | export class EbmlIds { 2 | /** 3 | * Indicates an EBML Header element. 4 | */ 5 | public static readonly EBML_HEADER = 0x1A45DFA3; 6 | 7 | /** 8 | * Indicates an EBML Version element. 9 | */ 10 | public static readonly EBML_VERSION = 0x4286; 11 | 12 | /** 13 | * Indicates an EBML Read Version element. 14 | */ 15 | public static readonly EBML_READ_VERSION = 0x42F7; 16 | 17 | /** 18 | * Indicates an EBML Max ID Length element. 19 | */ 20 | public static readonly EBML_MAX_IDLENGTH = 0x42F2; 21 | 22 | /** 23 | * Indicates an EBML Max Size Length element. 24 | */ 25 | public static readonly EBML_MAX_SIZE_LENGTH = 0x42F3; 26 | 27 | /** 28 | * Indicates an EBML Doc Type element. 29 | */ 30 | public static readonly EBML_DOC_TYPE = 0x4282; 31 | 32 | /** 33 | * Indicates an EBML Doc Type Version element. 34 | */ 35 | public static readonly EBML_DOC_TYPE_VERSION = 0x4287; 36 | 37 | /** 38 | * Indicates an EBML Doc Type Read Version element. 39 | */ 40 | public static readonly EBML_DOC_TYPE_READ_VERSION = 0x4285; 41 | 42 | /** 43 | * Indicates an EBML Void element. 44 | */ 45 | public static readonly EBML_VOID = 0xEC; 46 | } 47 | -------------------------------------------------------------------------------- /src/errors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Error class that indicates the file is likely corrupt. 3 | */ 4 | export class CorruptFileError extends Error { 5 | public constructor(msg?: string) { 6 | super(msg); 7 | } 8 | } 9 | 10 | /** 11 | * Error class that indicates a piece of functionality is not implemented in the current version. 12 | */ 13 | export class NotImplementedError extends Error { 14 | public constructor(message?: string) { 15 | super(`Not implemented${message ? `: ${message}` : ""}`); 16 | } 17 | } 18 | 19 | /** 20 | * Error class that indicates a feature or format is not supported in the current version. 21 | */ 22 | export class NotSupportedError extends Error { 23 | public constructor(message?: string) { 24 | super(`Not supported${message ? `: ${message}` : ""}`); 25 | } 26 | } 27 | 28 | /** 29 | * Error class that indicates a format is not supported in the current version. 30 | */ 31 | export class UnsupportedFormatError extends Error { 32 | public constructor(message?: string) { 33 | super(`Unsupported format${message ? `: ${message}` : ""}`); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/id3v2/id3v2ExtendedHeader.ts: -------------------------------------------------------------------------------- 1 | import SyncData from "./syncData"; 2 | import {ByteVector} from "../byteVector"; 3 | import {Guards} from "../utils"; 4 | 5 | /** 6 | * This class is a filler until support for reading and writing the ID3v2 extended header is 7 | * implemented. 8 | */ 9 | export default class Id3v2ExtendedHeader { 10 | private _size: number; 11 | 12 | private constructor() { /* private to enforce construction via static methods */ } 13 | 14 | /** 15 | * Constructs and initializes a new instance by reading the raw contents. 16 | * @param data Raw extended header structure 17 | * @param version ID3v2 version. Must be an unsigned 8-bit integer. 18 | */ 19 | public static fromData(data: ByteVector, version: number): Id3v2ExtendedHeader { 20 | Guards.truthy(data, "data"); 21 | Guards.byte(version, "version"); 22 | 23 | const header = new Id3v2ExtendedHeader(); 24 | header.parse(data, version); 25 | return header; 26 | } 27 | 28 | /** 29 | * Constructs and initializes a new instance with no contents. 30 | */ 31 | public static fromEmpty(): Id3v2ExtendedHeader { 32 | return new Id3v2ExtendedHeader(); 33 | } 34 | 35 | /** 36 | * Gets the size of the data on disk in bytes. 37 | */ 38 | public get size(): number { return this._size; } 39 | 40 | private parse(data: ByteVector, version: number): void { 41 | this._size = (version === 3 ? 4 : 0) 42 | + SyncData.toUint(data.subarray(0, 4)); 43 | 44 | // TODO: Are we going to actually support any of the flags? 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/interfaces.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Interface for objects that can (and should) be disposed after they are no longer needed. 3 | */ 4 | export interface IDisposable { 5 | /** 6 | * Disposes the current instance. 7 | */ 8 | dispose(): void; 9 | } 10 | 11 | /** 12 | * Interface for objects that can be lazily loaded. 13 | */ 14 | export interface ILazy { 15 | /** 16 | * Gets whether the object has been loaded. 17 | */ 18 | isLoaded: boolean; 19 | 20 | /** 21 | * Loads the object. 22 | */ 23 | load(): void; 24 | } 25 | -------------------------------------------------------------------------------- /src/matroska/matroskaTag.ts: -------------------------------------------------------------------------------- 1 | import MatroskaTagValue from "./matroskaTagValue"; 2 | import {MatroskaTagTarget} from "./matroskaTagTarget"; 3 | import {Guards} from "../utils"; 4 | 5 | /** 6 | * Abstraction on that represents the combination of a Matroska simple tag and a tag target. 7 | * @remarks 8 | * This is different from the tag concept in Matroska. This is a 1:1 relation between 9 | * target and value while Matroska tags are 1:many relationship of target to tag. Therefore, 10 | * the target must be cloned when constructing >1 tag with the same target. 11 | */ 12 | export default class MatroskaTag { 13 | private readonly _value: MatroskaTagValue; 14 | private readonly _target: MatroskaTagTarget; 15 | 16 | /** 17 | * Constructs and initializes a new instance using a simple tag and a target. 18 | * @param value Tag value to store in the instance 19 | * @param target Tag target that the tag instance applies to 20 | */ 21 | public constructor(value: MatroskaTagValue, target: MatroskaTagTarget) { 22 | Guards.truthy(value, "value"); 23 | Guards.truthy(target, "target"); 24 | 25 | this._value = value; 26 | this._target = target; 27 | } 28 | 29 | /** 30 | * Target that the tag value applies to 31 | */ 32 | public get target(): MatroskaTagTarget { return this._target; } 33 | 34 | /** 35 | * Value of the tag 36 | */ 37 | public get value(): MatroskaTagValue { return this._value; } 38 | } 39 | -------------------------------------------------------------------------------- /src/matroska/tracks/audioTrack.ts: -------------------------------------------------------------------------------- 1 | import EbmlElement from "../../ebml/ebmlElement"; 2 | import {MatroskaIds} from "../matroskaIds"; 3 | import {ILosslessAudioCodec, MediaTypes} from "../../properties"; 4 | import {MatroskaTrackType, Track} from "./track"; 5 | import {Guards} from "../../utils"; 6 | 7 | export default class AudioTrack extends Track implements ILosslessAudioCodec { 8 | private readonly _bitDepth: number; 9 | private readonly _channels: number; 10 | private readonly _sampleRate: number; 11 | 12 | public constructor(trackElements: Map, audioElements: Map) { 13 | super(trackElements); 14 | 15 | Guards.truthy(audioElements, "audioElements"); 16 | if (this.type !== MatroskaTrackType.Audio) { 17 | throw new Error(`Video track constructor used to construct type ${this.type} track.`); 18 | } 19 | 20 | // Read the relevant values 21 | this._channels = audioElements.get(MatroskaIds.CHANNELS)?.getSafeUint(); 22 | this._bitDepth = audioElements.get(MatroskaIds.BIT_DEPTH)?.getSafeUint(); 23 | this._sampleRate = audioElements.get(MatroskaIds.SAMPLING_FREQ)?.getDouble(); 24 | } 25 | 26 | /** @inheritDoc */ 27 | public get audioBitrate(): number { 28 | // @TODO How can we calculate that 29 | return undefined; 30 | } 31 | 32 | /** @inheritDoc */ 33 | public get audioChannels(): number { return this._channels; } 34 | 35 | /** @inheritDoc */ 36 | public get audioSampleRate(): number { return this._sampleRate; } 37 | 38 | /** @inheritDoc */ 39 | public get bitsPerSample(): number { return this._bitDepth; } 40 | 41 | /** @inheritDoc */ 42 | public get mediaTypes(): MediaTypes { 43 | // @TODO: Determine if the codec is lossless or not 44 | return MediaTypes.Audio; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/matroska/tracks/trackFactory.ts: -------------------------------------------------------------------------------- 1 | import AudioTrack from "./audioTrack"; 2 | import EbmlElement from "../../ebml/ebmlElement"; 3 | import EbmlParser from "../../ebml/ebmlParser"; 4 | import {MatroskaIds} from "../matroskaIds"; 5 | import {MatroskaTrackType, Track} from "./track"; 6 | import {VideoTrack} from "./videoTrack"; 7 | 8 | export default class TrackFactory { 9 | public static fromTrackElement(trackElement: EbmlElement): Track { 10 | // Read all the elements from the track 11 | const elements = EbmlParser.getAllElements(trackElement.getParser()); 12 | 13 | // Parse the elements into a track object 14 | switch (elements.get(MatroskaIds.TRACK_TYPE)?.getSafeUint()) { 15 | case MatroskaTrackType.Audio: 16 | const audioElementParser = elements.get(MatroskaIds.AUDIO).getParser(); 17 | const audioElements = EbmlParser.getAllElements(audioElementParser); 18 | return new AudioTrack(elements, audioElements); 19 | case MatroskaTrackType.Video: 20 | const videoElementParser = elements.get(MatroskaIds.VIDEO).getParser(); 21 | const videoElements = EbmlParser.getAllElements(videoElementParser); 22 | return new VideoTrack(elements, videoElements); 23 | default: 24 | return new Track(elements); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/mpeg/mpegAudioFile.ts: -------------------------------------------------------------------------------- 1 | import MpegAudioFileSettings from "./mpegAudioFileSettings"; 2 | import MpegAudioHeader from "./mpegAudioHeader"; 3 | import SandwichFile from "../sandwich/sandwichFile"; 4 | import {CorruptFileError} from "../errors"; 5 | import {File, ReadStyle} from "../file"; 6 | import {IFileAbstraction} from "../fileAbstraction"; 7 | import {Properties} from "../properties"; 8 | import {TagTypes} from "../tag"; 9 | import {NumberUtils} from "../utils"; 10 | 11 | /** 12 | * This class extends {@link SandwichFile} to provide tagging and properties support for 13 | * MPEG-1, MPEG-2, and MPEG-2.5 non-containerized audio files. 14 | */ 15 | export default class MpegAudioFile extends SandwichFile { 16 | private static readonly DEFAULT_TAG_LOCATION_MAPPING = new Map boolean>([ 17 | [TagTypes.Ape, () => MpegAudioFileSettings.preferApeTagAtFileEnd], 18 | [TagTypes.Id3v1, () => true], 19 | [TagTypes.Id3v2, () => MpegAudioFileSettings.preferId3v2TagAtFileEnd] 20 | ]); 21 | 22 | private _firstHeader: MpegAudioHeader; 23 | 24 | public constructor(file: IFileAbstraction|string, propertiesStyle: ReadStyle) { 25 | super(file, propertiesStyle, MpegAudioFile.DEFAULT_TAG_LOCATION_MAPPING, MpegAudioFileSettings.defaultTagTypes); 26 | } 27 | 28 | protected readProperties(readStyle: ReadStyle): Properties { 29 | if (!NumberUtils.hasFlag(readStyle, ReadStyle.Average)) { 30 | return undefined; 31 | } 32 | 33 | // @TODO: if readStyle is higher than average, scan the entire file to accurately calculate 34 | // the duration and bitrate 35 | 36 | const searchStart = this.mediaStartPosition; 37 | const searchEnd = searchStart + 0x400; 38 | const streamLength = this.mediaEndPosition - this.mediaStartPosition; 39 | 40 | this._firstHeader = MpegAudioHeader.fromFile(this, searchStart, searchEnd, streamLength); 41 | if (!this._firstHeader) { 42 | throw new CorruptFileError("MPEG audio header not found"); 43 | } 44 | 45 | return new Properties(this._firstHeader.durationMilliseconds, [this._firstHeader]); 46 | } 47 | } 48 | 49 | // ///////////////////////////////////////////////////////////////////////// 50 | // Register the file type 51 | [ 52 | "taglib/mp3", 53 | "audio/x-mp3", 54 | "application/x-id3", 55 | "audio/mpeg", 56 | "audio/x-mpeg", 57 | "audio/x-mpeg-3", 58 | "audio/mpeg3", 59 | "audio/mp3", 60 | "taglib/m2a", 61 | "taglib/mp2", 62 | "taglib/mp1", 63 | "audio/x-mp2", 64 | "audio/x-mp1" 65 | ].forEach((mt) => File.addFileType(mt, MpegAudioFile)); 66 | -------------------------------------------------------------------------------- /src/mpeg/mpegContainerFileSettings.ts: -------------------------------------------------------------------------------- 1 | import {TagTypes} from "../tag"; 2 | import {NumberUtils} from "../utils"; 3 | 4 | /** 5 | * This class contains settings related to MPEG container file operations. Open files will need to 6 | * be re-read in order for changes to take effect. 7 | */ 8 | export default class MpegContainerFileSettings { 9 | public static readonly SUPPORTED_TAG_TYPES = TagTypes.Id3v1 | TagTypes.Id3v2 | TagTypes.Ape; 10 | 11 | private static _defaultTagTypes = TagTypes.Id3v1 | TagTypes.Id3v2; 12 | 13 | /** 14 | * Gets the default types of tags for an MPEG container file. When opening a file, if these tag 15 | * types do not exist on the file, they will be created. 16 | */ 17 | public static get defaultTagTypes(): TagTypes { return this._defaultTagTypes; } 18 | /** 19 | * Sets the default types of tags for an MPEG container file. When opening a file, if these tag 20 | * types do not exist on the file, they will be created. See {@link SUPPORTED_TAG_TYPES} for a 21 | * list of tag types that are supported by node-taglib-sharp for MPEG container files. 22 | */ 23 | public static set defaultTagTypes(value: TagTypes) { 24 | const unsupportedTagTypes = NumberUtils.uintAnd(value, ~this.SUPPORTED_TAG_TYPES); 25 | if (unsupportedTagTypes !== 0) { 26 | throw new Error( 27 | `Argument error: node-taglib-sharp does not support tag types ${unsupportedTagTypes} for AAC files` 28 | ); 29 | } 30 | 31 | this._defaultTagTypes = value; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/mpeg/mpegEnums.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Indicates the MPEG audio channel mode of a file or stream. 3 | */ 4 | export enum ChannelMode { 5 | /** Stereo */ 6 | Stereo = 0, 7 | 8 | /** Joint Stereo */ 9 | JointStereo = 1, 10 | 11 | /** Dual Channel Mono */ 12 | DualChannel = 2, 13 | 14 | /** Single Channel Mono */ 15 | SingleChannel= 3 16 | } 17 | 18 | /** 19 | * Indicates the MPEG version of a file or stream. 20 | */ 21 | export enum MpegVersion { 22 | /** Unknown version */ 23 | Unknown = -1, 24 | 25 | /** MPEG-1 */ 26 | Version1 = 0, 27 | 28 | /** MPEG-2 */ 29 | Version2 = 1, 30 | 31 | /** MPEG-2.5 */ 32 | Version25 = 2 33 | } 34 | -------------------------------------------------------------------------------- /src/mpeg/mpegVideoHeader.ts: -------------------------------------------------------------------------------- 1 | import {CorruptFileError} from "../errors"; 2 | import {File} from "../file"; 3 | import {IVideoCodec, MediaTypes} from "../properties"; 4 | import {Guards, NumberUtils} from "../utils"; 5 | 6 | /** 7 | * Provides information about an MPEG video stream. 8 | */ 9 | export default class MpegVideoHeader implements IVideoCodec { 10 | private static readonly FRAME_RATES = [ 11 | 0, 24000 / 1001, 24, 25, 30000 / 1001, 30, 50, 60000 / 1001, 60 12 | ]; 13 | 14 | private readonly _frameRateIndex: number; 15 | private readonly _videoBitrate: number; 16 | private readonly _videoHeight: number; 17 | private readonly _videoWidth: number; 18 | 19 | /** 20 | * Constructs and initializes a new instance of {@link MpegVideoHeader} by reading it from a 21 | * specified location in a specified file. 22 | * @param file File to read the header from 23 | * @param position Position in `file` at which the header begins 24 | */ 25 | public constructor(file: File, position: number) { 26 | Guards.truthy(file, "file"); 27 | Guards.safeUint(position, "position"); 28 | 29 | file.seek(position); 30 | const data = file.readBlock(7); 31 | 32 | if (data.length < 7) { 33 | throw new CorruptFileError("Insufficient data in header"); 34 | } 35 | 36 | this._videoWidth = data.subarray(0, 2).toUshort() >>> 4; 37 | this._videoHeight = NumberUtils.uintAnd(data.subarray(1, 2).toUshort(), 0x0FFF); 38 | this._frameRateIndex = NumberUtils.uintAnd(data.get(3), 0x0F); 39 | this._videoBitrate = NumberUtils.uintAnd(NumberUtils.uintRShift(data.subarray(4, 3).toUint(), 6), 0x3FFFF); 40 | } 41 | 42 | // #region 43 | 44 | /** @inheritDoc */ 45 | public get description(): string { return "MPEG Video"; } 46 | 47 | /** 48 | * @inheritDoc 49 | * @remarks For MPEG, this is always 0 50 | */ 51 | // @TODO: Can we calculate the duration? 52 | public get durationMilliseconds(): number { return 0; } 53 | 54 | /** @inheritDoc */ 55 | public get mediaTypes(): MediaTypes { return MediaTypes.Video; } 56 | 57 | /** @inheritDoc */ 58 | public get videoBitrate(): number { return this._videoBitrate; } 59 | 60 | /** @inheritDoc */ 61 | public get videoFrameRate(): number { 62 | return this._frameRateIndex < 9 ? MpegVideoHeader.FRAME_RATES[this._frameRateIndex] : 0; 63 | } 64 | 65 | /** @inheritDoc */ 66 | public get videoHeight(): number { return this._videoHeight; } 67 | 68 | /** @inheritDoc */ 69 | public get videoWidth(): number { return this._videoWidth; } 70 | 71 | // #endregion 72 | } 73 | -------------------------------------------------------------------------------- /src/mpeg/vbrHeader.ts: -------------------------------------------------------------------------------- 1 | export default abstract class VbrHeader { 2 | private readonly _bitrateKilobytes: number | undefined; 3 | private readonly _durationMilliseconds: number | undefined; 4 | private readonly _totalFrames: number | undefined; 5 | private readonly _totalBytes: number | undefined; 6 | 7 | protected constructor( 8 | totalFrames?: number, 9 | totalBytes?: number, 10 | durationSeconds?: number, 11 | bitrateBytes?: number 12 | ) { 13 | this._totalFrames = totalFrames; 14 | this._totalBytes = totalBytes; 15 | this._durationMilliseconds = durationSeconds ? durationSeconds * 1000 : undefined; 16 | this._bitrateKilobytes = bitrateBytes ? Math.floor(bitrateBytes / 1000) : undefined; 17 | } 18 | 19 | /** 20 | * Gets the bitrate of the ile in kilobytes per second, if it could be calculated using the 21 | * current instance. `undefined`, otherwise. 22 | */ 23 | public get bitrateKilobytes(): number | undefined { return this._bitrateKilobytes; } 24 | 25 | /** 26 | * Gets the duration of the file in milliseconds, if it could be calculated using the current 27 | * instance. `undefined`, otherwise. 28 | */ 29 | public get durationMilliseconds(): number | undefined { return this._durationMilliseconds; } 30 | 31 | /** 32 | * Gets the total number of frames in the file, as indicated by the current instance. 33 | */ 34 | public get totalFrames(): number | undefined { return this._totalFrames; } 35 | 36 | /** 37 | * Gets the total size of the file in bytes, as indicated by the current instance. 38 | */ 39 | public get totalBytes(): number | undefined { return this._totalBytes;} 40 | } -------------------------------------------------------------------------------- /src/mpeg/vbriHeader.ts: -------------------------------------------------------------------------------- 1 | import VbrHeader from "./vbrHeader"; 2 | import {ByteVector, StringType} from "../byteVector"; 3 | import {File} from "../file"; 4 | import {Guards} from "../utils"; 5 | 6 | /** 7 | * Information about a variable bitrate MPEG audio stream encoded by the Fraunhofer encoder 8 | */ 9 | export default class VbriHeader extends VbrHeader { 10 | private static readonly FILE_IDENTIFIER = ByteVector.fromString("VBRI", StringType.Latin1).makeReadOnly(); 11 | private static readonly HEADER_OFFSET = 36; 12 | 13 | private constructor(totalFrames: number, totalBytes: number, durationSeconds: number, bitrateBytes: number) { 14 | super(totalFrames, totalBytes, durationSeconds, bitrateBytes); 15 | } 16 | 17 | public static fromFile( 18 | file: File, 19 | mpegHeaderPosition: number, 20 | samplesPerFrame: number, 21 | samplesPerSecond: number 22 | ): VbriHeader { 23 | Guards.truthy(file, "files"); 24 | Guards.safeUint(mpegHeaderPosition, "mpegHeaderPosition"); 25 | Guards.uint(samplesPerFrame, "samplesPerFrame"); 26 | Guards.greaterThanInclusive(samplesPerFrame, 1, "samplesPerFrame"); 27 | Guards.uint(samplesPerSecond, "samplesPerSecond"); 28 | Guards.greaterThanInclusive(samplesPerSecond, 1, "samplesPerSecond"); 29 | 30 | // Seek to the position in the file where the VBRI header should be and read it 31 | file.seek(mpegHeaderPosition + this.HEADER_OFFSET); 32 | 33 | const vbriData = file.readBlock(24); 34 | if (vbriData.length !== 24 || !vbriData.startsWith(this.FILE_IDENTIFIER)) { 35 | return undefined; 36 | } 37 | 38 | // Parse the header 39 | const delay = vbriData.subarray(6, 2).toUshort(); 40 | const totalBytes = vbriData.subarray(10, 4).toUint(); 41 | const totalFrames = vbriData.subarray(14, 4).toUint(); 42 | 43 | // Calculate the rest of the values 44 | const totalSamples = (totalFrames * samplesPerFrame); 45 | const bitrateBytes = (totalBytes * 8) / (totalSamples / samplesPerSecond); 46 | const durationSeconds = (totalSamples - delay) / samplesPerSecond; 47 | 48 | return new VbriHeader(totalFrames, totalBytes, durationSeconds, bitrateBytes); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/mpeg4/boxes/appleAdditionalInfoBox.ts: -------------------------------------------------------------------------------- 1 | import FullBox from "./fullBox"; 2 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 3 | import {ByteVector, StringType} from "../../byteVector"; 4 | import {File} from "../../file"; 5 | import {Guards, StringUtils} from "../../utils"; 6 | 7 | /** 8 | * This class extends {@link FullBox} to provide an implementation of an Apple AdditionalInfoBox. 9 | */ 10 | export default class AppleAdditionalInfoBox extends FullBox { 11 | /** 12 | * Private constructor to force construction via static functions. 13 | */ 14 | private constructor() { 15 | super(); 16 | } 17 | 18 | /** 19 | * Constructs and initializes a new instance of {@link AppleAdditionalInfoBox} with a provided header 20 | * and handler by reading the contents from a specified file. 21 | * @param header A {@link Mpeg4BoxHeader} object containing the header to use for the new instance. 22 | * @param file A {@link File} object to read the contents of the box from. 23 | * @param handlerType Type of the handler box object containing the handler that applies to the 24 | * new instance, or undefined if no handler applies. 25 | */ 26 | public static fromFile(header: Mpeg4BoxHeader, file: File, handlerType: ByteVector): AppleAdditionalInfoBox { 27 | const instance = new AppleAdditionalInfoBox(); 28 | instance.initializeFromHeaderFileAndHandler(header, file, handlerType); 29 | instance.data = file.readBlock(instance.dataSize > 0 ? instance.dataSize : 0); 30 | 31 | return instance; 32 | } 33 | 34 | /** 35 | * Constructs and initializes a new instance of {@link FullBox} with a provided header, version, and flags. 36 | * @param type A {@link Mpeg4BoxHeader} object containing the header to use for the new instance. 37 | * @param version A value containing the version of the new instance. 38 | * @param flags A value containing the flags for the new instance. 39 | */ 40 | public static fromTypeVersionAndFlags(type: ByteVector, version: number, flags: number): AppleAdditionalInfoBox { 41 | const instance = new AppleAdditionalInfoBox(); 42 | instance.initializeFromTypeVersionAndFlags(type, version, flags); 43 | 44 | return instance; 45 | } 46 | 47 | /** 48 | * Gets the text contained in the current instance. 49 | */ 50 | public get text(): string { return StringUtils.trimStart(this.data.toString(StringType.Latin1), "\0"); } 51 | /** 52 | * Sets the text contained in the current instance. 53 | */ 54 | public set text(v: string) { 55 | Guards.notNullOrUndefined(v, "v"); 56 | this.data = ByteVector.fromString(v, StringType.Latin1); 57 | } 58 | } -------------------------------------------------------------------------------- /src/mpeg4/boxes/appleAnnotationBox.ts: -------------------------------------------------------------------------------- 1 | import Mpeg4Box from "./mpeg4Box"; 2 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 3 | import {ByteVector} from "../../byteVector"; 4 | 5 | /** 6 | * This class extends {@link Mpeg4Box} to provide an implementation of an Apple AnnotationBox. 7 | */ 8 | export default class AppleAnnotationBox extends Mpeg4Box { 9 | /** 10 | * Private constructor to force construction via static functions. 11 | */ 12 | private constructor() { 13 | super(); 14 | } 15 | 16 | /** 17 | * Constructs and initializes a new instance of {@link AppleAnnotationBox} with a provided header and 18 | * handler by reading the contents from a specified file. 19 | * @param header A {@link Mpeg4BoxHeader} object containing the header to use for the new instance. 20 | * @param handlerType Type of the handler box object containing the handler that applies to the 21 | * new instance, or undefined if no handler applies. 22 | */ 23 | public static fromHeader(header: Mpeg4BoxHeader, handlerType: ByteVector): AppleAnnotationBox { 24 | const instance = new AppleAnnotationBox(); 25 | instance.initializeFromHeader(header, handlerType); 26 | 27 | return instance; 28 | } 29 | 30 | /** 31 | * Constructs and initializes a new instance of {@link AppleAnnotationBox} of specified type with no children. 32 | * @param type A {@link ByteVector} object containing a 4-byte box type. 33 | */ 34 | public static fromType(type: ByteVector): AppleAnnotationBox { 35 | const instance = new AppleAnnotationBox(); 36 | instance.initializeFromType(type); 37 | 38 | return instance; 39 | } 40 | } -------------------------------------------------------------------------------- /src/mpeg4/boxes/isoFreeSpaceBox.ts: -------------------------------------------------------------------------------- 1 | import Mpeg4Box from "./mpeg4Box"; 2 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 3 | import Mpeg4BoxType from "../mpeg4BoxType"; 4 | import {ByteVector} from "../../byteVector"; 5 | import {Guards} from "../../utils"; 6 | 7 | /** 8 | * This class extends {@link Mpeg4Box} to provide an implementation of a ISO/IEC 14496-12 FreeSpaceBox. 9 | */ 10 | export default class IsoFreeSpaceBox extends Mpeg4Box { 11 | private _padding: number; 12 | 13 | /** 14 | * Private constructor to force construction via static functions. 15 | */ 16 | private constructor() { 17 | super(); 18 | } 19 | 20 | /** 21 | * Constructs and initializes a new instance of {@link IsoFreeSpaceBox} with a provided header and 22 | * handler by reading the contents from a specified file. 23 | * @param header A {@link Mpeg4BoxHeader} object containing the header to use for the new instance. 24 | * @param handlerType Type of the handler box object containing the handler that applies to the 25 | * new instance, or undefined if no handler applies. 26 | */ 27 | public static fromHeader(header: Mpeg4BoxHeader, handlerType: ByteVector): IsoFreeSpaceBox { 28 | const instance = new IsoFreeSpaceBox(); 29 | instance.initializeFromHeader(header, handlerType); 30 | instance._padding = instance.dataSize; 31 | 32 | return instance; 33 | } 34 | 35 | /** 36 | * Constructs and initializes a new instance of {@link IsoFreeSpaceBox} to occupy a specified number of bytes. 37 | * @param padding A value specifying the number of bytes the new instance should occupy when rendered. 38 | */ 39 | public static fromPadding(padding: number): IsoFreeSpaceBox { 40 | const instance = new IsoFreeSpaceBox(); 41 | instance.initializeFromType(Mpeg4BoxType.FREE); 42 | instance.paddingSize = padding; 43 | 44 | return instance; 45 | } 46 | 47 | /** 48 | * Gets the data contained in the current instance. 49 | */ 50 | public get data(): ByteVector { return ByteVector.fromSize(this._padding); } 51 | /** 52 | * Sets the data contained in the current instance. 53 | */ 54 | public set data(v: ByteVector) { this._padding = v ? v.length : 0; } 55 | 56 | /** 57 | * Gets the size the current instance will occupy when rendered. 58 | * @returns A value containing the size the current instance will occupy when rendered. 59 | */ 60 | public get paddingSize(): number { return this._padding + 8; } 61 | /** 62 | * Sets the size the current instance will occupy when rendered. 63 | */ 64 | public set paddingSize(v: number) { 65 | Guards.safeUint(v, "v"); 66 | this._padding = v - 8; 67 | } 68 | } -------------------------------------------------------------------------------- /src/mpeg4/boxes/isoMetaBox.ts: -------------------------------------------------------------------------------- 1 | import FullBox from "./fullBox"; 2 | import IsoHandlerBox from "./isoHandlerBox"; 3 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 4 | import Mpeg4BoxType from "../mpeg4BoxType"; 5 | import {ByteVector} from "../../byteVector"; 6 | import {File} from "../../file"; 7 | import {Guards} from "../../utils"; 8 | 9 | /** 10 | * This class extends {@link FullBox} to provide an implementation of a ISO/IEC 14496-12 MetaBox. 11 | */ 12 | export default class IsoMetaBox extends FullBox { 13 | /** 14 | * Private constructor to force construction via static functions. 15 | */ 16 | private constructor() { 17 | super(); 18 | } 19 | 20 | /** 21 | * Constructs and initializes a new instance of {@link IsoMetaBox} with a provided header and 22 | * handler by reading the contents from a specified file. 23 | * @param file A {@link File} object to read the contents of the box from. 24 | * new instance, or undefined if no handler applies. 25 | * @param header A {@link Mpeg4BoxHeader} object containing the header to use for the new instance. 26 | * @param handlerType Type of the handler box object containing the handler that applies to the 27 | */ 28 | public static fromFile(file: File, header: Mpeg4BoxHeader, handlerType: ByteVector): IsoMetaBox { 29 | const instance = new IsoMetaBox(); 30 | instance.initializeFromHeaderFileAndHandler(header, file, handlerType); 31 | 32 | return instance; 33 | } 34 | 35 | /** 36 | * Constructs and initializes a new instance of {@link IsoMetaBox} with a specified handler. 37 | * @param handlerType A {@link ByteVector} object specifying a 4 byte handler type. 38 | * @param handlerName A `string` object specifying the handler name. 39 | */ 40 | public static fromHandler(handlerType: ByteVector, handlerName?: string): IsoMetaBox { 41 | Guards.truthy(handlerType, "handlerType"); 42 | if (handlerType.length < 4) { 43 | throw new Error("The handler type must be four bytes long."); 44 | } 45 | 46 | const instance = new IsoMetaBox(); 47 | instance.initializeFromTypeVersionAndFlags(Mpeg4BoxType.META, 0, 0); 48 | 49 | const handlerBox = IsoHandlerBox.fromHandlerTypeAndHandlerName(handlerType, handlerName); 50 | instance.addChild(handlerBox); 51 | 52 | return instance; 53 | } 54 | } -------------------------------------------------------------------------------- /src/mpeg4/boxes/isoSampleDescriptionBox.ts: -------------------------------------------------------------------------------- 1 | import FullBox from "./fullBox"; 2 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 3 | import {File} from "../../file"; 4 | import {ByteVector} from "../../byteVector"; 5 | 6 | /** 7 | * This class extends {@link FullBox} to provide an implementation of a ISO/IEC 14496-12 SampleDescriptionBox. 8 | */ 9 | export default class IsoSampleDescriptionBox extends FullBox { 10 | private _entryCount: number; 11 | 12 | /** 13 | * Private constructor to force construction via static functions. 14 | */ 15 | private constructor() { 16 | super(); 17 | } 18 | 19 | /** 20 | * Constructs and initializes a new instance of {@link IsoSampleDescriptionBox} with a provided header 21 | * and handler by reading the contents from a specified file. 22 | * @param header A {@link Mpeg4BoxHeader} object containing the header to use for the new instance. 23 | * @param file A {@link File} object to read the contents of the box from. 24 | * @param handlerType Type of the handler box object containing the handler that applies to the 25 | * new instance, or undefined if no handler applies. 26 | */ 27 | public static fromFile(file: File, header: Mpeg4BoxHeader, handlerType: ByteVector): IsoSampleDescriptionBox { 28 | const instance = new IsoSampleDescriptionBox(); 29 | instance.initializeFromHeaderFileAndHandler(header, file, handlerType); 30 | instance.increaseDataPosition(4); 31 | instance._entryCount = file.readBlock(4).toUint(); 32 | 33 | return instance; 34 | } 35 | 36 | /** 37 | * The number of boxes at the beginning of the children that will be stored as {@link IsoAudioSampleEntry} 38 | * of {@link IsoVisualSampleEntry} objects, depending on the handler. 39 | */ 40 | public get entryCount(): number { return this._entryCount; } 41 | } 42 | -------------------------------------------------------------------------------- /src/mpeg4/boxes/isoSampleEntry.ts: -------------------------------------------------------------------------------- 1 | import Mpeg4Box from "./mpeg4Box"; 2 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 3 | import {File} from "../../file"; 4 | import {Guards} from "../../utils"; 5 | import {ByteVector} from "../../byteVector"; 6 | 7 | /** 8 | * This class extends {@link Mpeg4Box} to provide an implementation of a ISO/IEC 14496-12 SampleEntry. 9 | */ 10 | export default abstract class IsoSampleEntry extends Mpeg4Box { 11 | private _dataReferenceIndex: number; 12 | 13 | /** 14 | * Protected constructor to force construction via static functions. 15 | */ 16 | protected constructor() { 17 | super(); 18 | } 19 | 20 | /** 21 | * Constructs and initializes a new instance of {@link IsoSampleEntry} with a provided header and 22 | * handler by reading the contents from a specified file. 23 | * @param header A {@link Mpeg4BoxHeader} object containing the header to use for the new instance. 24 | * @param file A {@link File} object to read the contents of the box from. 25 | * @param handlerType Type of the handler box object containing the handler that applies to the 26 | * new instance, or undefined if no handler applies. 27 | */ 28 | public initializeFromHeaderFileAndHandler(header: Mpeg4BoxHeader, file: File, handlerType: ByteVector): void { 29 | Guards.truthy(file, "file"); 30 | 31 | this.initializeFromHeader(header, handlerType); 32 | const dataPositionBeforeIncrease = this.increaseDataPosition(8); 33 | file.seek(dataPositionBeforeIncrease + 6); 34 | this._dataReferenceIndex = file.readBlock(2).toUshort(); 35 | } 36 | 37 | /** 38 | * Gets the data reference index of the current instance. 39 | */ 40 | public get dataReferenceIndex(): number { return this._dataReferenceIndex; } 41 | } -------------------------------------------------------------------------------- /src/mpeg4/boxes/isoSampleTableBox.ts: -------------------------------------------------------------------------------- 1 | import Mpeg4Box from "./mpeg4Box"; 2 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 3 | import {ByteVector} from "../../byteVector"; 4 | 5 | /** 6 | * This class extends {@link Mpeg4Box} to provide an implementation of a ISO/IEC 14496-12 SampleTableBox. 7 | */ 8 | export default class IsoSampleTableBox extends Mpeg4Box { 9 | /** 10 | * Private constructor to force construction via static functions. 11 | */ 12 | private constructor() { 13 | super(); 14 | } 15 | 16 | /** 17 | * Constructs and initializes a new instance of {@link IsoSampleTableBox} with a provided header and 18 | * handler by reading the contents from a specified file. 19 | * @param header A {@link Mpeg4BoxHeader} object containing the header to use for the new instance. 20 | * @param handlerType Type of the handler box object containing the handler that applies to the 21 | * new instance, or undefined if no handler applies. 22 | * @returns A new instance of {@link IsoSampleTableBox} 23 | */ 24 | public static fromHeader(header: Mpeg4BoxHeader, handlerType: ByteVector): IsoSampleTableBox { 25 | const instance = new IsoSampleTableBox(); 26 | instance.initializeFromHeader(header, handlerType); 27 | 28 | return instance; 29 | } 30 | } -------------------------------------------------------------------------------- /src/mpeg4/boxes/isoUnknownSampleEntry.ts: -------------------------------------------------------------------------------- 1 | import IsoSampleEntry from "./isoSampleEntry"; 2 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 3 | import {File} from "../../file"; 4 | import {ByteVector} from "../../byteVector"; 5 | 6 | /** 7 | * This class extends {@link Mpeg4Box} to provide an implementation of a ISO/IEC 14496-12 SampleEntry. 8 | */ 9 | export default class IsoUnknownSampleEntry extends IsoSampleEntry { 10 | /** 11 | * Protected constructor to force construction via static functions. 12 | */ 13 | private constructor() { 14 | super(); 15 | } 16 | 17 | /** 18 | * Constructs and initializes a new instance of {@link IsoUnknownSampleEntry} with a provided header and 19 | * handler by reading the contents from a specified file. 20 | * @param header A {@link Mpeg4BoxHeader} object containing the header to use for the new instance. 21 | * @param file A {@link File} to read the contents of the box from. 22 | * new instance, or undefined if no handler applies. 23 | * @param handlerType Type of the handler box object containing the handler that applies to the 24 | * new instance, or undefined if no handler applies. 25 | */ 26 | public static fromFile(header: Mpeg4BoxHeader, file: File, handlerType: ByteVector): IsoUnknownSampleEntry { 27 | const instance = new IsoUnknownSampleEntry(); 28 | instance.initializeFromHeaderFileAndHandler(header, file, handlerType); 29 | return instance; 30 | } 31 | } -------------------------------------------------------------------------------- /src/mpeg4/boxes/isoUserDataBox.ts: -------------------------------------------------------------------------------- 1 | import Mpeg4Box from "./mpeg4Box"; 2 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 3 | import Mpeg4BoxType from "../mpeg4BoxType"; 4 | import {ByteVector} from "../../byteVector"; 5 | 6 | /** 7 | * This class extends {@link Mpeg4Box} to provide an implementation of a ISO/IEC 14496-12 UserDataBox. 8 | */ 9 | export default class IsoUserDataBox extends Mpeg4Box { 10 | private _parentTree: Mpeg4BoxHeader[]; 11 | 12 | /** 13 | * Private constructor to force construction via static functions. 14 | */ 15 | private constructor() { 16 | super(); 17 | } 18 | 19 | /** 20 | * Constructs and initializes a new instance of {@link IsoUserDataBox} with a provided header and 21 | * handler by reading the contents from a specified file. 22 | * @param header A {@link Mpeg4BoxHeader} object containing the header to use for the new instance. 23 | * @param handlerType Type of the handler box object containing the handler that applies to the 24 | * new instance, or undefined if no handler applies. 25 | */ 26 | public static fromHeader(header: Mpeg4BoxHeader, handlerType: ByteVector): IsoUserDataBox { 27 | const instance = new IsoUserDataBox(); 28 | instance.initializeFromHeader(header, handlerType); 29 | 30 | return instance; 31 | } 32 | 33 | /** 34 | * Constructs and initializes a new instance of @see IsoUserDataBox with no children. 35 | */ 36 | public static fromEmpty(): IsoUserDataBox { 37 | const instance = new IsoUserDataBox(); 38 | instance.initializeFromType(Mpeg4BoxType.UDTA); 39 | 40 | return instance; 41 | } 42 | 43 | /** 44 | * Gets the box headers for the current "udta" box and all parent boxes up to the top of the file. 45 | * @remarks Changes to the returned object will not be honored. Set the property to change it. 46 | */ 47 | public get parentTree(): Mpeg4BoxHeader[] { return this._parentTree.slice(); } 48 | /** 49 | * Sets the box headers for the current "udta" box and all parent boxes up to the top of the file. 50 | * @internal 51 | */ 52 | public set parentTree(v: Mpeg4BoxHeader[]) { this._parentTree = v; } 53 | } -------------------------------------------------------------------------------- /src/mpeg4/boxes/isoVisualSampleEntry.ts: -------------------------------------------------------------------------------- 1 | import IsoSampleEntry from "./isoSampleEntry"; 2 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 3 | import {ByteVector, StringType} from "../../byteVector"; 4 | import {File} from "../../file"; 5 | import {IVideoCodec, MediaTypes} from "../../properties"; 6 | 7 | /** 8 | * This class extends {@link IsoSampleEntry} and implements {@link IVideoCodec} to provide an implementation of a 9 | * ISO/IEC 14496-12 VisualSampleEntry and support for reading MPEG-4 video properties. 10 | */ 11 | export default class IsoVisualSampleEntry extends IsoSampleEntry implements IVideoCodec { 12 | private _videoHeight: number; 13 | private _videoWidth: number; 14 | 15 | /** 16 | * Private constructor to force construction via static functions. 17 | */ 18 | private constructor() { 19 | super(); 20 | } 21 | 22 | /** 23 | * Initializes the instance using the box's header, and additional information read from the file. 24 | * @param header Header for the box. 25 | * @param file File to read additional information from. 26 | * @param handlerType Type of the handler for the box. Optional. 27 | */ 28 | public static fromFile(header: Mpeg4BoxHeader, file: File, handlerType: ByteVector): IsoVisualSampleEntry { 29 | const instance = new IsoVisualSampleEntry(); 30 | instance.initializeFromHeaderFileAndHandler(header, file, handlerType); 31 | 32 | const dataPositionBeforeIncrease = instance.increaseDataPosition(62); 33 | file.seek(dataPositionBeforeIncrease + 16); 34 | instance._videoWidth = file.readBlock(2).toUshort(); 35 | instance._videoHeight = file.readBlock(2).toUshort(); 36 | 37 | return instance; 38 | } 39 | 40 | /** @inheritDoc */ 41 | public get durationMilliseconds(): number { return 0; } 42 | 43 | /** @inheritDoc */ 44 | public get mediaTypes(): MediaTypes { return MediaTypes.Video; } 45 | 46 | /** @inheritDoc */ 47 | // @TODO: I'm sure we can get a better description than this 48 | public get description(): string { return `MPEG-4 Video (${this.boxType.toString(StringType.Latin1)})`; } 49 | 50 | /** @inheritDoc */ 51 | public get videoHeight(): number { return this._videoHeight; } 52 | 53 | /** @inheritDoc */ 54 | public get videoWidth(): number { return this._videoWidth; } 55 | } -------------------------------------------------------------------------------- /src/mpeg4/boxes/textBox.ts: -------------------------------------------------------------------------------- 1 | import Mpeg4Box from "./mpeg4Box"; 2 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 3 | import {ByteVector} from "../../byteVector"; 4 | import {File} from "../../file"; 5 | 6 | /** 7 | * Represents an MP4 text box 8 | */ 9 | export default class TextBox extends Mpeg4Box { 10 | /** 11 | * Private constructor to force construction via static functions. 12 | */ 13 | private constructor() { 14 | super(); 15 | } 16 | 17 | /** 18 | * Constructs and initializes a new instance of @see TextBox with a provided header and handler 19 | * by reading the contents from a specified file. 20 | * @param header A @see Mpeg4BoxHeader object containing the header to use for the new instance. 21 | * @param file A @see File object to read the contents of the box from. 22 | * @param handlerType Type of the handler box object containing the handler that applies to the 23 | * new instance, or undefined if no handler applies. 24 | */ 25 | public static fromFile(header: Mpeg4BoxHeader, file: File, handlerType: ByteVector): TextBox { 26 | const instance = new TextBox(); 27 | instance.initializeFromHeader(header, handlerType); 28 | instance.data = instance.loadData(file); 29 | 30 | return instance; 31 | } 32 | } -------------------------------------------------------------------------------- /src/mpeg4/boxes/unknownBox.ts: -------------------------------------------------------------------------------- 1 | import Mpeg4Box from "./mpeg4Box"; 2 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 3 | import {ByteVector} from "../../byteVector"; 4 | import {File} from "../../file"; 5 | 6 | export default class UnknownBox extends Mpeg4Box { 7 | /** 8 | * Private constructor to force construction via static functions. 9 | */ 10 | private constructor() { 11 | super(); 12 | } 13 | 14 | /** 15 | * Constructs and initializes a new instance of @see UnknownBox with a provided header and handler 16 | * by reading the contents from a specified file. 17 | * @param header A @see Mpeg4BoxHeader object containing the header to use for the new instance. 18 | * @param file A @see File object to read the contents of the box from. 19 | * @param handlerType Type of the handler box object containing the handler that applies to the 20 | * new instance, or undefined if no handler applies. 21 | */ 22 | public static fromFile(header: Mpeg4BoxHeader, file: File, handlerType: ByteVector): UnknownBox { 23 | const instance = new UnknownBox(); 24 | instance.initializeFromHeader(header, handlerType); 25 | instance.data = file.readBlock(instance.dataSize > 0 ? instance.dataSize : 0); 26 | 27 | return instance; 28 | } 29 | } -------------------------------------------------------------------------------- /src/mpeg4/boxes/urlBox.ts: -------------------------------------------------------------------------------- 1 | import Mpeg4Box from "./mpeg4Box"; 2 | import Mpeg4BoxHeader from "../mpeg4BoxHeader"; 3 | import {ByteVector} from "../../byteVector"; 4 | import {File} from "../../file"; 5 | 6 | /** 7 | * Represent a MP4 URL box 8 | */ 9 | export default class UrlBox extends Mpeg4Box { 10 | /** 11 | * Private constructor to force construction via static functions. 12 | */ 13 | private constructor() { 14 | super(); 15 | } 16 | 17 | /** 18 | * Constructs and initializes a new instance of @see UrlBox with a provided header and handler 19 | * by reading the contents from a specified file. 20 | * @param header A @see Mpeg4BoxHeader object containing the header to use for the new instance. 21 | * @param file A @see File object to read the contents of the box from. 22 | * @param handlerType Type of the handler box object containing the handler that applies to the 23 | * new instance, or undefined if no handler applies. 24 | */ 25 | public static fromFile(header: Mpeg4BoxHeader, file: File, handlerType: ByteVector): UrlBox { 26 | const instance = new UrlBox(); 27 | instance.initializeFromHeader(header, handlerType); 28 | instance.data = instance.loadData(file); 29 | 30 | return instance; 31 | } 32 | } -------------------------------------------------------------------------------- /src/mpeg4/descriptorTag.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Descriptor Tags 3 | */ 4 | export enum DescriptorTag { 5 | Forbidden0 = 0, 6 | ObjectDescriptorTag = 1, 7 | InitialObjectDescriptorTag = 2, 8 | EsDescriptorTag = 3, 9 | DecoderConfigDescriptorTag = 4, 10 | DecSpecificInfoTag = 5, 11 | SlConfigDescriptorTag = 6, 12 | ContentIdentDescriptorTag = 7, 13 | SupplContentIdentDescriptorTag = 8, 14 | IpiDescriptorPointerTag = 9, 15 | IpmpDescriptorPointerTag = 10, 16 | IpmpDescriptorTag = 11, 17 | QosDescriptorTag = 12, 18 | RegistrationDescriptorTag = 13, 19 | EsIdIncTag = 14, 20 | EsIdRefTag = 15, 21 | Mp4IodTag = 16, 22 | Mp4OdTag = 17, 23 | IplDescriptorPointerRefTag = 18, 24 | ExtensionProfileLevelDescriptorTag = 19, 25 | ProfileLevelIndicationIndexDescriptorTag = 20, 26 | // Reserved for future ISO use 0x15 to 0x3F 27 | ContentClassificationDescriptorTag = 64, 28 | KeyWordDescriptorTag = 65, 29 | RatingDescriptorTag = 66, 30 | LanguageDescriptorTag = 67, 31 | ShortTextualDescriptorTag = 68, 32 | ExpandedTextualDescriptorTag = 69, 33 | ContentCreatorNameDescriptorTag = 70, 34 | ContentCreationDateDescriptorTag = 71, 35 | OciCreatorNameDescriptorTag = 72, 36 | OciCreationDateDescriptorTag = 73, 37 | SmpteCameraPositionDescriptorTag = 74, 38 | SegmentDescriptorTag = 75, 39 | MediaTimeDescriptorTag = 76, 40 | // Reserved for future ISO use 0x4D to 0x5F 41 | IpmpToolsListDescriptorTag = 96, 42 | IpmpToolTag = 97, 43 | M4MuxTimingDescriptorTag = 98, 44 | M4MuxCodeTableDescriptorTag = 99, 45 | ExtSLConfigDescriptorTag = 100, 46 | M4MuxBufferSizeDescriptorTag = 101, 47 | M4MuxIdentDescriptorTag = 102, 48 | DependencyPointerTag = 103, 49 | DependencyMarkerTag = 104, 50 | M4MuxChannelDescriptorTag = 105, 51 | // Reserved for future ISO use 0x6A to 0xBF 52 | UserPrivate = 192, 53 | Forbidden255 = 255, 54 | } 55 | -------------------------------------------------------------------------------- /src/mpeg4/descriptorTagReader.ts: -------------------------------------------------------------------------------- 1 | import { ByteVector } from "../byteVector"; 2 | import {Guards, NumberUtils} from "../utils"; 3 | 4 | /** 5 | * Provides methods to read descriptor tags 6 | * @internal 7 | */ 8 | export class DescriptorTagReader { 9 | private _data: ByteVector; 10 | private _length: number; 11 | private _offset: number; 12 | 13 | /** 14 | * Constructs and initializes a new descriptor tag reader with the data from which to read the 15 | * descriptor tag. 16 | * @param data Data from which the descriptor tag should be read 17 | */ 18 | public constructor(data: ByteVector) { 19 | Guards.truthy(data, "data"); 20 | 21 | this._data = data; 22 | this._length = 0; 23 | this._offset = 0; 24 | } 25 | 26 | /** 27 | * Gets the length of the descriptor tag. 28 | */ 29 | public get length(): number { return this._length; } 30 | 31 | /** 32 | * Gets the offset of the descriptor tag. 33 | */ 34 | public get offset(): number { return this._offset; } 35 | 36 | /** 37 | * Reads a section length and updates the offset to the end of the length block. 38 | * @returns number Length that was read. 39 | */ 40 | public readLength(): number { 41 | let b = 0; 42 | const end = this._offset + 4; 43 | 44 | do { 45 | b = this._data.get(this._offset++); 46 | this._length = NumberUtils.uintOr(NumberUtils.uintLShift(this._length, 7), NumberUtils.uintAnd(b, 0x7f)); 47 | } while (NumberUtils.uintAnd(b, 0x80) !== 0 && this._offset <= end); 48 | // The length could be between 1 and 4 bytes for each descriptor 49 | 50 | return this._length; 51 | } 52 | 53 | /** 54 | * Increases the current offset by a given value 55 | * @param value A number by which the offset should be increased 56 | * @returns number Offset before increase 57 | */ 58 | public increaseOffset(value: number): number { 59 | Guards.safeUint(value, "value"); 60 | 61 | const previousOffset = this._offset; 62 | this._offset += value; 63 | 64 | return previousOffset; 65 | } 66 | } -------------------------------------------------------------------------------- /src/mpeg4/mpeg4AudioTypes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * MPEG-4 audio object types as defined in https://wiki.multimedia.cx/index.php/MPEG-4_Audio#Audio_Object_Types . 3 | * Index corresponds to the value of the object type. 4 | */ 5 | export default [ 6 | "Null", 7 | "AAC Main", 8 | "AAC LC (Low Complexity)", 9 | "AAC SSR (Scalable Sample Rate)", 10 | "AAC LTP (Long-Term Prediction)", 11 | "SBR (Spectral Band Replication)", 12 | "AAC Scalable", 13 | "TwinVQ", 14 | "CELP (Code Excited Linear Prediction)", 15 | "HXVC (Harmonic Vector eXcitation Coding)", 16 | "Reserved", 17 | "Reserved", 18 | "TTSI (Text-To-Speech Interface)", 19 | "Main Synthesis", 20 | "Wavetable Synthesis", 21 | "General MIDI", 22 | "Algorithmic Synthesis and Audio Effects", 23 | "Error Resilient AAC LC (Low Complexity)", 24 | "Reserved", 25 | "Error Resilient AAC LTP (Long-Term Prediction)", 26 | "Error Resilient AAC Scalable", 27 | "Error Resilient TwinVQ", 28 | "Error Resilient BSAC (Bit-Sliced Arithmetic Coding)", 29 | "Error Resilient AAC LD (Low Delay)", 30 | "Error Resilient CELP (Code Excited Linear Prediction)", 31 | "Error Resilient HXVC (Harmonic Vector eXcitation Coding)", 32 | "Error Resilient HILN (Harmonic and Individual Lines plus Noise)", 33 | "Error Resilient Parametric", 34 | "SSC (SinuSoidal Coding)", 35 | "PS (Parametric Stereo)", 36 | "MPEG Surround", 37 | "(escape value)", 38 | "Layer-1", 39 | "Layer-2", 40 | "Layer-3", 41 | "DST (Direct Stream Transfer)", 42 | "ALS (Audio Lossless)", 43 | "SLS (Scalable Lossless)", 44 | "SLS non-core", 45 | "Error Resilient AAC ELD (Enhanced Low Delay)", 46 | "SMR (Symbolic Music Representation) Simple", 47 | "SMR (Symbolic Music Representation) Main", 48 | "USAC (Unified Speech and Audio Coding) (no SBR)", 49 | "SAOC (Spatial Audio Object Coding)", 50 | "Low Delay MPEG Surround", 51 | "USAC (Unified Speech and Audio Coding)" 52 | ]; 53 | -------------------------------------------------------------------------------- /src/mpeg4/mpeg4BoxRenderer.ts: -------------------------------------------------------------------------------- 1 | import IsoFreeSpaceBox from "./boxes/isoFreeSpaceBox"; 2 | import Mpeg4Box from "./boxes/mpeg4Box"; 3 | import Mpeg4BoxType from "./mpeg4BoxType"; 4 | import {ByteVector} from "../byteVector"; 5 | import {Guards} from "../utils"; 6 | 7 | /** 8 | * Renderer for {@link Mpeg4Box} objects. 9 | * @remarks Written this way to break a circular dependency from child {@link Mpeg4Box} classes and 10 | * the root {@link Mpeg4Box} class. 11 | */ 12 | export default class Mpeg4BoxRenderer { 13 | /** 14 | * Renders the provided `box` for output into a file. 15 | * @param box Box to render 16 | * @returns ByteVector Box as rendered for output into a file. 17 | */ 18 | public static renderBox(box: Mpeg4Box): ByteVector { 19 | Guards.truthy(box, "box"); 20 | 21 | let freeFound = false; 22 | const outputVectors: ByteVector[] = []; 23 | 24 | // Write children or data 25 | if (box.hasChildren) { 26 | for (const child of box.children) { 27 | if (box instanceof IsoFreeSpaceBox) { 28 | freeFound = true; 29 | } else { 30 | outputVectors.push(this.renderBox(child)); 31 | } 32 | } 33 | } else if (box.data) { 34 | // @TODO: If the box generates the data property on get, we should change it to a render method. 35 | outputVectors.push(box.data); 36 | } 37 | 38 | // If there was a free, don't take it away, and let meta be a special case 39 | if (freeFound || ByteVector.equals(box.boxType, Mpeg4BoxType.META)) { 40 | const newSizeSoFar = outputVectors.reduce((accum, current) => accum + current.length, 0); 41 | const sizeDifference = box.dataSize - newSizeSoFar; 42 | let newPadding: IsoFreeSpaceBox; 43 | if (box.header.dataSize !== 0 && sizeDifference >= 8) { 44 | // If we have room for free space, add it so we don't have to resize the file 45 | newPadding = IsoFreeSpaceBox.fromPadding(sizeDifference); 46 | } else { 47 | // If we're getting bigger, get a lot bigger so we might not have to do this again 48 | newPadding = IsoFreeSpaceBox.fromPadding(2048); 49 | } 50 | 51 | outputVectors.push(this.renderBox(newPadding)); 52 | } 53 | 54 | 55 | // Handle the box-specific headers 56 | const boxHeaders = box.renderBoxHeaders(); 57 | if (boxHeaders?.length > 0) { 58 | outputVectors.splice(0, 0, ...boxHeaders); 59 | } 60 | 61 | // Adjust the data's header size for the new content, render the header 62 | box.header.dataSize = outputVectors.reduce((accum, current) => accum + current.length, 0); 63 | outputVectors.splice(0, 0, box.header.render()); 64 | 65 | return ByteVector.concatenate(...outputVectors); 66 | } 67 | } -------------------------------------------------------------------------------- /src/mpeg4/mpeg4HandlerType.ts: -------------------------------------------------------------------------------- 1 | import {ByteVector, StringType} from "../byteVector"; 2 | 3 | /** 4 | * These are some of the handler types. 5 | * @remarks Two sources for these handlers are: 6 | * * https://cconcolato.github.io/mp4ra/handler.html# 7 | * * https://exiftool.org/TagNames/QuickTime.html#Meta 8 | */ 9 | export default class Mpeg4HandlerType { 10 | /** Quicktime Alias */ 11 | public static readonly ALIS = ByteVector.fromString("alis", StringType.UTF8).makeReadOnly(); 12 | /** Quicktime Metadata */ 13 | public static readonly MDIR = ByteVector.fromString("mdir", StringType.UTF8).makeReadOnly(); 14 | /** Audio */ 15 | public static readonly SOUN = ByteVector.fromString("soun", StringType.UTF8).makeReadOnly(); 16 | /** Video **/ 17 | public static readonly VIDE = ByteVector.fromString("vide", StringType.UTF8).makeReadOnly(); 18 | } -------------------------------------------------------------------------------- /src/mpeg4/mpeg4Utils.ts: -------------------------------------------------------------------------------- 1 | import Mpeg4BoxHeader from "./mpeg4BoxHeader"; 2 | 3 | /** 4 | * Collection of utilities for interacting with MPEG4 files. 5 | * @internal 6 | */ 7 | export default class Mpeg4Utils { 8 | /** 9 | * Adds a parent to the end of an existing list of parents. 10 | * @param parents A {@link Mpeg4BoxHeader[]} object containing an existing list of parents. 11 | * @param current A {@link Mpeg4BoxHeader} object to add to the list. 12 | * @returns Mpeg4BoxHeader[] List of parents, including the added header. 13 | */ 14 | public static addParent(parents: Mpeg4BoxHeader[], current: Mpeg4BoxHeader): Mpeg4BoxHeader[] { 15 | const boxes: Mpeg4BoxHeader[] = []; 16 | 17 | if (parents) { 18 | boxes.push(...parents); 19 | } 20 | 21 | boxes.push(current); 22 | 23 | return boxes; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ogg/codecs/iOggCodec.ts: -------------------------------------------------------------------------------- 1 | import XiphComment from "../../xiph/xiphComment"; 2 | import {ByteVector} from "../../byteVector"; 3 | import {ICodec} from "../../properties"; 4 | 5 | /** 6 | * Interface for an OGG codec. 7 | */ 8 | export default interface IOggCodec extends ICodec { 9 | /** 10 | * Gets the raw Xiph comment data contained in the codec. 11 | */ 12 | get commentData(): ByteVector; 13 | 14 | /** 15 | * Reads an Ogg packet that has been encountered in the stream, looking for the comment data. 16 | * @param packet Packet to read 17 | * @returns 18 | * `true` if the codec has read all the necessary packets for the stream and 19 | * does not need to be called again, 20 | */ 21 | readPacket(packet: ByteVector): boolean; 22 | 23 | /** 24 | * Sets the file offset information necessary for calculating the duration of the stream. Once 25 | * called, the duration can be accessed by calling {@link ICodec.durationMilliseconds}. 26 | * @param firstGranularPosition First granular position of the stream 27 | * @param lastGranularPosition Last granular position of the stream 28 | */ 29 | setDuration(firstGranularPosition: ByteVector, lastGranularPosition: ByteVector): void; 30 | 31 | /** 32 | * Renders and write the provided comment into the provided list of packets. 33 | * @param packets List of packets the comment packet should be written into. 34 | * @param comment Xiph comment to write into the list of packets. 35 | */ 36 | writeCommentPacket(packets: ByteVector[], comment: XiphComment): void; 37 | } 38 | -------------------------------------------------------------------------------- /src/ogg/oggFileSettings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This class contains settings related to Ogg file operations. Open files will need to be re-read 3 | * in order for changes to take effect. 4 | */ 5 | export default class OggFileSettings { 6 | private static _writeToAllComments = false; 7 | 8 | /** 9 | * Gets whether changes to Ogg tag fields should be written to all Xiph comments or just the 10 | * first Xiph comment in the file. 11 | * @remarks 12 | * Ogg files are required to have one Xiph comment per stream. In files with multiple 13 | * streams, this means there are multiple Xiph comments per file. 14 | */ 15 | public static get writeToAllComments(): boolean { return this._writeToAllComments; } 16 | /** 17 | * Sets whether changes to Ogg tag fields should be written to all Xiph comments or just the 18 | * first Xiph comment in the file. 19 | * @remarks 20 | * Ogg files are required to have one Xiph comment per stream. In files with multiple 21 | * streams, this means there are multiple Xiph comments per file. 22 | */ 23 | public static set writeToAllComments(value: boolean) { this._writeToAllComments = value; } 24 | } 25 | -------------------------------------------------------------------------------- /src/riff/aviFileSettings.ts: -------------------------------------------------------------------------------- 1 | import {TagTypes} from "../tag"; 2 | import {NumberUtils} from "../utils"; 3 | 4 | /** 5 | * This class contains settings related to AVI file operations. Open files will need to be re-read 6 | * in order for changes to take effect. 7 | */ 8 | export default class AviFileSettings { 9 | /** 10 | * The types of tags that are supported by AVI files. 11 | */ 12 | public static readonly SUPPORTED_TAG_TYPES = TagTypes.DivX | TagTypes.Id3v2 | TagTypes.RiffInfo | TagTypes.MovieId; 13 | 14 | private static _defaultTagTypes = AviFileSettings.SUPPORTED_TAG_TYPES; 15 | 16 | /** 17 | * Gets the default types of tags for an AVI file. When opening a file, if these tag types do 18 | * not exist on the file, they will be created. 19 | */ 20 | public static get defaultTagTypes(): TagTypes { return this._defaultTagTypes; } 21 | 22 | /** 23 | * Sets the default types of tags for an AVI file. When opening a file, if these tag types do 24 | * not exist on the file, they will be created. See {@link SUPPORTED_TAG_TYPES} for a list of tag 25 | * types that are supported by node-taglib-sharp for AVI files. 26 | */ 27 | public static set defaultTagTypes(value: TagTypes) { 28 | const unsupportedTagTypes = NumberUtils.uintAnd(value, ~this.SUPPORTED_TAG_TYPES); 29 | if (unsupportedTagTypes !== 0) { 30 | throw new Error( 31 | `Argument error: node-taglib-sharp does not support tag types ${unsupportedTagTypes} for AVI files` 32 | ); 33 | } 34 | 35 | this._defaultTagTypes = value; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/riff/iRiffChunk.ts: -------------------------------------------------------------------------------- 1 | import {ByteVector} from "../byteVector"; 2 | 3 | /** 4 | * Interface for chunks that appear in a RIFF file. 5 | */ 6 | export default interface IRiffChunk { 7 | /** 8 | * Offset into the file where the chunk begins. This is `undefined` if the object was 9 | * constructed directly from data. 10 | */ 11 | chunkStart: number|undefined; 12 | 13 | /** 14 | * FOURCC code for the chunk. 15 | */ 16 | fourcc: string; 17 | 18 | /** 19 | * Size of just the data contained within the current instance. Does not include the header or 20 | * padding byte. This value does not update if contents of the chunk changes. 21 | */ 22 | originalDataSize: number; 23 | 24 | /** 25 | * Original size of the chunk, including header and padding byte. This value does not update if 26 | * the contents of the chunk changes. 27 | */ 28 | originalTotalSize: number; 29 | 30 | /** 31 | * Renders the chunk, including the header and padding byte. 32 | */ 33 | render(): ByteVector; 34 | } 35 | -------------------------------------------------------------------------------- /src/riff/riffTags.ts: -------------------------------------------------------------------------------- 1 | import CombinedTag from "../combinedTag"; 2 | import {Tag, TagTypes} from "../tag"; 3 | import DivxTag from "./divxTag"; 4 | import Id3v2Tag from "../id3v2/id3v2Tag"; 5 | import InfoTag from "./infoTag"; 6 | import MovieIdTag from "./movieIdTag"; 7 | import {Id3v2TagHeaderFlags} from ".."; 8 | import {UnsupportedFormatError} from "../errors"; 9 | 10 | export default class RiffTags extends CombinedTag { 11 | public static readonly SUPPORTED_TAG_TYPES = TagTypes.DivX | TagTypes.Id3v2 | TagTypes.RiffInfo | TagTypes.MovieId; 12 | 13 | public constructor(divxTag: DivxTag, id3v2Tag: Id3v2Tag, infoTag: InfoTag, movieIdTag: MovieIdTag) { 14 | super(RiffTags.SUPPORTED_TAG_TYPES, true); 15 | 16 | // NOTE: We're adding ID3 first because it is the most flexible tagging format. Divx is last 17 | // because it is the least flexible tagging format. 18 | this.addTag(id3v2Tag); 19 | this.addTag(infoTag); 20 | this.addTag(movieIdTag); 21 | this.addTag(divxTag); 22 | } 23 | 24 | /** @inheritDoc */ 25 | public createTag(tagType: TagTypes, copy: boolean): Tag { 26 | this.validateTagCreation(tagType); 27 | 28 | // Create the desired tag 29 | let tag: Tag; 30 | switch (tagType) { 31 | case TagTypes.DivX: 32 | tag = DivxTag.fromEmpty(); 33 | break; 34 | case TagTypes.Id3v2: 35 | const id3v2Tag = Id3v2Tag.fromEmpty(); 36 | // @TODO: have default version be configurable 37 | id3v2Tag.version = 4; 38 | id3v2Tag.flags |= Id3v2TagHeaderFlags.FooterPresent; 39 | tag = id3v2Tag; 40 | break; 41 | case TagTypes.RiffInfo: 42 | tag = InfoTag.fromEmpty(); 43 | break; 44 | case TagTypes.MovieId: 45 | tag = MovieIdTag.fromEmpty(); 46 | break; 47 | default: 48 | throw new UnsupportedFormatError(`Specified tag type ${tagType} is invalid`); 49 | } 50 | 51 | 52 | // Copy the contents of this tag to the new tag if desired 53 | if (copy) { 54 | this.copyTo(tag, true); 55 | } 56 | 57 | this.addTag(tag); 58 | return tag; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/riff/waveFileSettings.ts: -------------------------------------------------------------------------------- 1 | import {TagTypes} from "../tag"; 2 | import {NumberUtils} from "../utils"; 3 | 4 | /** 5 | * This class contains settings related to WAV file operations. Open files will need to be re-read 6 | * in order for changes to take effect. 7 | */ 8 | export default class WaveFileSettings { 9 | /** 10 | * The types of tags that are supported by WAV files. 11 | */ 12 | public static readonly SUPPORTED_TAG_TYPES = TagTypes.DivX | TagTypes.Id3v2 | TagTypes.RiffInfo | TagTypes.MovieId; 13 | 14 | private static _defaultTagTypes = WaveFileSettings.SUPPORTED_TAG_TYPES; 15 | 16 | /** 17 | * Gets the default types of tags for an WAV file. When opening a file, if these tag types do 18 | * not exist on the file, they will be created. 19 | */ 20 | public static get defaultTagTypes(): TagTypes { return this._defaultTagTypes; } 21 | 22 | /** 23 | * Sets the default types of tags for an WAV file. When opening a file, if these tag types do 24 | * not exist on the file, they will be created. See {@link SUPPORTED_TAG_TYPES} for a list of tag 25 | * types that are supported by node-taglib-sharp for WAV files. 26 | */ 27 | public static set defaultTagTypes(value: TagTypes) { 28 | const unsupportedTagTypes = NumberUtils.uintAnd(value, ~this.SUPPORTED_TAG_TYPES); 29 | if (unsupportedTagTypes !== 0) { 30 | throw new Error( 31 | `Argument error: node-taglib-sharp does not support tag types ${unsupportedTagTypes} for AVI files` 32 | ); 33 | } 34 | 35 | this._defaultTagTypes = value; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/sandwich/tagParsers.ts: -------------------------------------------------------------------------------- 1 | import {Tag} from "../tag"; 2 | import {File, ReadStyle} from "../file"; 3 | 4 | /** 5 | * Common logic for parsing sequential tags at the start or end of a file. Classes that inherit 6 | * from this class are expected to provide `while(parser.read())` functionality. If {@link read} 7 | * returns `true` the tag that was just read can be read from {@link currentTag}. 8 | */ 9 | export default abstract class TagParser { 10 | // @TODO: Don't allow access to member variables 11 | private readonly _file: File; 12 | private readonly _readStyle: ReadStyle; 13 | private _currentTag: Tag; 14 | private _fileOffset: number; 15 | 16 | protected constructor(file: File, readStyle: ReadStyle, initialOffset: number) { 17 | this._file = file; 18 | this._fileOffset = initialOffset; 19 | this._readStyle = readStyle; 20 | } 21 | 22 | /** 23 | * Tag that was just read from the file. This will be `undefined` until {@link read} is called. 24 | * The value is not guaranteed if {@link read} returns `false` 25 | */ 26 | public get currentTag(): Tag { return this._currentTag; } 27 | protected set currentTag(value: Tag) { this._currentTag = value; } 28 | 29 | protected get file(): File { return this._file; } 30 | 31 | protected get fileOffset(): number { return this._fileOffset; } 32 | protected set fileOffset(value: number) { this._fileOffset = value; } 33 | 34 | protected get readStyle(): ReadStyle { return this._readStyle; } 35 | 36 | /** 37 | * Reads the next tag from the file. 38 | * @returns 39 | * `true` is returned if a tag is found, the tag can be accessed from 40 | * {@link currentTag}. `false` is returned if no tag was found. 41 | */ 42 | public abstract read(): boolean; 43 | } 44 | -------------------------------------------------------------------------------- /src/settings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * General settings for the node-taglib-sharp libary. 3 | */ 4 | export default class Settings { 5 | private static _copyExistingTagsToNewDefaultTags: boolean = true; 6 | 7 | /** 8 | * Gets whether existing tags should be copied into newly created default tags. 9 | * If `true`, tags that already exist in the file will be copied into any newly created default 10 | * tags. If `false`, newly created default tags will be left empty. 11 | */ 12 | public static get copyExistingTagsToNewDefaultTags(): boolean { return this._copyExistingTagsToNewDefaultTags; } 13 | 14 | /** 15 | * Sets whether existing tags should be copied into newly created default tags. 16 | * If `true`, tags that already exist in the file will be copied into any newly created default 17 | * tags. If `false`, newly created default tags will be left empty. 18 | */ 19 | public static set copyExistingTagsToNewDefaultTags(value: boolean) { 20 | this._copyExistingTagsToNewDefaultTags = value; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/xiph/xiphSettings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This class contains settings related to Xiph tagging. Open files will need to be re-opened in 3 | * order for changes to take effect. 4 | */ 5 | export default class XiphSettings { 6 | private static _useTempoToStoreBpm: boolean = true; 7 | 8 | // noinspection JSUnusedLocalSymbols 9 | /** 10 | * Private constructor to prevent inadvertent construction 11 | */ 12 | private constructor() { /* private to prevent constructing instances */ } 13 | 14 | /** 15 | * Gets whether to use "TEMPO" field to store {@link XiphComment.beatsPerMinute} property. If `true` 16 | * "TEMPO" will be used, if `false` "BPM" will be used. 17 | * @default `true` 18 | */ 19 | public static get useTempoToStoreBpm(): boolean { return this._useTempoToStoreBpm; } 20 | /** 21 | * Sets whether to use "TEMPO" field to store {@link XiphComment.beatsPerMinute} property. If `true` 22 | * "TEMPO" will be used, if `false` "BPM" will be used. 23 | */ 24 | public static set useTempoToStoreBpm(value: boolean) { this._useTempoToStoreBpm = value; } 25 | } 26 | -------------------------------------------------------------------------------- /test-integration/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": ["../.eslintrc.js"], 3 | "rules": { 4 | "@typescript-eslint/dot-notation": "off", 5 | "@typescript-eslint/explicit-function-return-type": "off", 6 | "@typescript-eslint/naming-convention": "off", 7 | "@typescript-eslint/no-unsafe-argument": "off", 8 | "@typescript-eslint/no-unused-vars": "off" 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /test-integration/aac_fileTests.ts: -------------------------------------------------------------------------------- 1 | import * as Chai from "chai"; 2 | import {suite, test} from "@testdeck/mocha"; 3 | 4 | import TestConstants from "./utilities/testConstants"; 5 | import {File} from "../src"; 6 | import {StandardFileTests} from "./utilities/standardFileTests"; 7 | 8 | // Setup chai 9 | const assert = Chai.assert; 10 | 11 | @suite class Aac_FileTests { 12 | private static readonly corruptFilePath = TestConstants.getCorruptFilePath("corrupt.aac"); 13 | private static readonly sampleFilePath = TestConstants.getSampleFilePath("sample.aac"); 14 | private static readonly tmpFileName = "tmpwrite.aac"; 15 | 16 | private static file: File; 17 | 18 | public static before() { 19 | Aac_FileTests.file = File.createFromPath(Aac_FileTests.sampleFilePath); 20 | } 21 | 22 | public static after() { 23 | Aac_FileTests.file.dispose(); 24 | } 25 | 26 | @test 27 | public readAudioProperties() { 28 | StandardFileTests.readAudioProperties(Aac_FileTests.file); 29 | assert.approximately(Aac_FileTests.file.properties.audioBitrate, 236, 1); 30 | assert.strictEqual(Aac_FileTests.file.properties.audioSampleRate, 44100); 31 | assert.strictEqual(Aac_FileTests.file.properties.audioChannels, 2); 32 | assert.approximately(Aac_FileTests.file.properties.durationMilliseconds, 5000, 50); 33 | } 34 | 35 | @test 36 | public readTags() { 37 | assert.strictEqual(Aac_FileTests.file.tag.album, "AAC album"); 38 | assert.strictEqual(Aac_FileTests.file.tag.firstPerformer, "AAC artist"); 39 | assert.strictEqual(Aac_FileTests.file.tag.comment, "AAC comment"); 40 | assert.strictEqual(Aac_FileTests.file.tag.firstGenre, "Acid Punk"); 41 | assert.strictEqual(Aac_FileTests.file.tag.title, "AAC title"); 42 | assert.strictEqual(Aac_FileTests.file.tag.track, 6); 43 | assert.strictEqual(Aac_FileTests.file.tag.year, 1234); 44 | } 45 | 46 | @test 47 | public testCorruptionResistance() { 48 | StandardFileTests.testCorruptionResistance(Aac_FileTests.corruptFilePath); 49 | } 50 | 51 | @test 52 | public writeStandardPictures() { 53 | const tmpFilePath = TestConstants.getTempFilePath(Aac_FileTests.tmpFileName); 54 | StandardFileTests.writeStandardPictures(Aac_FileTests.sampleFilePath, tmpFilePath); 55 | } 56 | 57 | @test 58 | public writeStandardTags() { 59 | const tmpFilePath = TestConstants.getTempFilePath(Aac_FileTests.tmpFileName); 60 | StandardFileTests.writeStandardTags(Aac_FileTests.sampleFilePath, tmpFilePath); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test-integration/ape_fileTests.ts: -------------------------------------------------------------------------------- 1 | import {suite, test} from "@testdeck/mocha"; 2 | import {assert} from "chai"; 3 | 4 | import ExtendedFileTests from "./utilities/extendedFileTests"; 5 | import TestConstants from "./utilities/testConstants"; 6 | import {File} from "../src"; 7 | import {StandardFileTests} from "./utilities/standardFileTests"; 8 | 9 | @suite class Ape_FileTests { 10 | private static readonly sampleFilePath = TestConstants.getSampleFilePath("sample.ape"); 11 | private static readonly tmpFileName = "tmpwrite.ape"; 12 | 13 | private static file: File; 14 | 15 | public static before() { 16 | Ape_FileTests.file = File.createFromPath(Ape_FileTests.sampleFilePath); 17 | } 18 | 19 | public static after() { 20 | Ape_FileTests.file.dispose(); 21 | } 22 | 23 | @test 24 | public readAudioProperties() { 25 | assert.approximately(Ape_FileTests.file.properties.audioBitrate, 604, 0.5); 26 | assert.strictEqual(Ape_FileTests.file.properties.audioSampleRate, 44100); 27 | assert.strictEqual(Ape_FileTests.file.properties.audioChannels, 2); 28 | assert.approximately(Ape_FileTests.file.properties.durationMilliseconds, 5230, 10); 29 | } 30 | 31 | @test 32 | public readTags() { 33 | assert.strictEqual(Ape_FileTests.file.tag.album, "APE album"); 34 | assert.strictEqual(Ape_FileTests.file.tag.firstPerformer, "APE artist"); 35 | assert.strictEqual(Ape_FileTests.file.tag.comment, "APE comment"); 36 | assert.strictEqual(Ape_FileTests.file.tag.firstGenre, "Acid Punk"); 37 | assert.strictEqual(Ape_FileTests.file.tag.track, 6); 38 | assert.strictEqual(Ape_FileTests.file.tag.trackCount, 7); 39 | assert.strictEqual(Ape_FileTests.file.tag.year, 1234); 40 | } 41 | 42 | @test 43 | public writeExtendedTags() { 44 | const tmpFilePath = TestConstants.getTempFilePath(Ape_FileTests.tmpFileName); 45 | ExtendedFileTests.writeExtendedTags(Ape_FileTests.sampleFilePath, tmpFilePath); 46 | } 47 | 48 | @test 49 | public writeStandardPictures() { 50 | const tmpFilePath = TestConstants.getTempFilePath(Ape_FileTests.tmpFileName); 51 | StandardFileTests.writeStandardPictures(Ape_FileTests.sampleFilePath, tmpFilePath); 52 | } 53 | 54 | @test 55 | public writeStandardTags() { 56 | const tmpFilePath = TestConstants.getTempFilePath(Ape_FileTests.tmpFileName); 57 | StandardFileTests.writeStandardTags(Ape_FileTests.sampleFilePath, tmpFilePath); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /test-integration/matroska_fileTests.ts: -------------------------------------------------------------------------------- 1 | import {assert} from "chai"; 2 | import {suite, test} from "@testdeck/mocha"; 3 | 4 | import TestConstants from "./utilities/testConstants"; 5 | import {File, MediaTypes} from "../src"; 6 | 7 | @suite class Matroska_FileTests { 8 | private static readonly sampleFilePath = TestConstants.getSampleFilePath("sample.mkv"); 9 | 10 | private static file: File; 11 | 12 | public static before() { 13 | Matroska_FileTests.file = File.createFromPath(Matroska_FileTests.sampleFilePath); 14 | } 15 | 16 | public static after() { 17 | Matroska_FileTests.file?.dispose(); 18 | } 19 | 20 | @test 21 | public readProperties() { 22 | assert.strictEqual(Matroska_FileTests.file.properties.mediaTypes, MediaTypes.Audio | MediaTypes.Video); 23 | assert.strictEqual(Matroska_FileTests.file.properties.audioBitrate, 0); 24 | assert.strictEqual(Matroska_FileTests.file.properties.audioChannels, 1); 25 | assert.strictEqual(Matroska_FileTests.file.properties.audioSampleRate, 48000); 26 | assert.strictEqual(Matroska_FileTests.file.properties.bitsPerSample, 0); 27 | assert.strictEqual(Matroska_FileTests.file.properties.durationMilliseconds, 1120); 28 | assert.strictEqual(Matroska_FileTests.file.properties.videoHeight, 480); 29 | assert.strictEqual(Matroska_FileTests.file.properties.videoWidth, 640); 30 | } 31 | 32 | @test 33 | public readTags() { 34 | assert.strictEqual(Matroska_FileTests.file.tag.firstPerformer, "Lime"); 35 | assert.strictEqual(Matroska_FileTests.file.tag.comment, "no comments"); 36 | assert.strictEqual(Matroska_FileTests.file.tag.firstGenre, "Test"); 37 | assert.strictEqual(Matroska_FileTests.file.tag.year, 2017); 38 | assert.strictEqual(Matroska_FileTests.file.tag.firstComposer, "Starwer"); 39 | assert.strictEqual(Matroska_FileTests.file.tag.conductor, "Starwer"); 40 | assert.strictEqual(Matroska_FileTests.file.tag.copyright, "Starwer 2017"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test-integration/mp3_id3v1_fileTests.ts: -------------------------------------------------------------------------------- 1 | import * as Chai from "chai"; 2 | import {suite, test} from "@testdeck/mocha"; 3 | 4 | import TestConstants from "./utilities/testConstants"; 5 | import {File, ReadStyle} from "../src"; 6 | import {StandardFileTests} from "./utilities/standardFileTests"; 7 | 8 | // Setup chai 9 | const assert = Chai.assert; 10 | 11 | @suite class Mp3_id3v1_fileTests { 12 | private static readonly sampleFilePath = TestConstants.getSampleFilePath("sample_v1_only.mp3"); 13 | private static readonly tmpFileName = "tmpwrite_v1_only.mp3"; 14 | 15 | private static file: File; 16 | 17 | public static before() { 18 | Mp3_id3v1_fileTests.file = File.createFromPath(Mp3_id3v1_fileTests.sampleFilePath); 19 | } 20 | 21 | public static after() { 22 | Mp3_id3v1_fileTests.file.dispose(); 23 | } 24 | 25 | @test 26 | public readTags() { 27 | assert.strictEqual(Mp3_id3v1_fileTests.file.tag.album, "MP3 album"); 28 | assert.strictEqual(Mp3_id3v1_fileTests.file.tag.firstPerformer, "MP3 artist"); 29 | assert.strictEqual(Mp3_id3v1_fileTests.file.tag.comment, "MP3 comment"); 30 | assert.strictEqual(Mp3_id3v1_fileTests.file.tag.firstGenre, "Acid Punk"); 31 | assert.strictEqual(Mp3_id3v1_fileTests.file.tag.track, 6); 32 | assert.strictEqual(Mp3_id3v1_fileTests.file.tag.year, 1234); 33 | } 34 | 35 | @test 36 | public writeStandardPictures() { 37 | const tmpFilePath = TestConstants.getTempFilePath(Mp3_id3v1_fileTests.tmpFileName); 38 | StandardFileTests.writeStandardPictures(Mp3_id3v1_fileTests.sampleFilePath, tmpFilePath, ReadStyle.None); 39 | } 40 | 41 | @test 42 | public writeStandardTags() { 43 | const tmpFilePath = TestConstants.getTempFilePath(Mp3_id3v1_fileTests.tmpFileName); 44 | StandardFileTests.writeStandardTags(Mp3_id3v1_fileTests.sampleFilePath, tmpFilePath); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test-integration/mpeg_fileTest.ts: -------------------------------------------------------------------------------- 1 | import * as Chai from "chai"; 2 | import {suite, test} from "@testdeck/mocha"; 3 | 4 | import TestConstants from "./utilities/testConstants"; 5 | import {File, ReadStyle} from "../src"; 6 | import {StandardFileTests, TestTagLevel} from "./utilities/standardFileTests"; 7 | 8 | const assert = Chai.assert; 9 | 10 | @suite class Mpeg_FileTests { 11 | private static readonly corruptFilePath = TestConstants.getCorruptFilePath("corrupt.mpg"); 12 | private static readonly sampleFilePath = TestConstants.getSampleFilePath("sample.mpg"); 13 | private static readonly tmpFileName = "tmpwrite.mpg"; 14 | 15 | private static file: File; 16 | 17 | public static before() { 18 | Mpeg_FileTests.file = File.createFromPath(Mpeg_FileTests.sampleFilePath); 19 | } 20 | 21 | public static after() { 22 | Mpeg_FileTests.file.dispose(); 23 | } 24 | 25 | @test 26 | public readAudioProperties() { 27 | assert.strictEqual(Mpeg_FileTests.file.properties.audioBitrate, 128); 28 | assert.strictEqual(Mpeg_FileTests.file.properties.audioChannels, 2); 29 | assert.strictEqual(Mpeg_FileTests.file.properties.audioSampleRate, 44100); 30 | assert.approximately(Mpeg_FileTests.file.properties.durationMilliseconds, 1391, 0.5); 31 | assert.strictEqual(Mpeg_FileTests.file.properties.videoHeight, 480); 32 | assert.strictEqual(Mpeg_FileTests.file.properties.videoWidth, 640); 33 | } 34 | 35 | @test 36 | public readTags() { 37 | assert.isTrue(Mpeg_FileTests.file.tag.isEmpty); 38 | } 39 | 40 | @test 41 | public RemoveStandardTags() { 42 | const tempFilePath = TestConstants.getTempFilePath(Mpeg_FileTests.tmpFileName); 43 | StandardFileTests.removeStandardTags(Mpeg_FileTests.sampleFilePath, tempFilePath); 44 | } 45 | 46 | @test 47 | public TestCorruptionResistance() { 48 | StandardFileTests.testCorruptionResistance(Mpeg_FileTests.corruptFilePath); 49 | } 50 | 51 | @test 52 | public WriteStandardPictures() { 53 | const tempFilePath = TestConstants.getTempFilePath(Mpeg_FileTests.tmpFileName); 54 | StandardFileTests.writeStandardPictures(Mpeg_FileTests.sampleFilePath, tempFilePath, ReadStyle.None); 55 | } 56 | 57 | // @test 58 | // public WriteStandardPicturesLazy() { 59 | // StandardFileTests.writeStandardPictures( 60 | // Mpeg_FileTests.sampleFilePath, 61 | // Mpeg_FileTests.tmpFileName, 62 | // ReadStyle.PictureLazy 63 | // ); 64 | // } 65 | 66 | @test 67 | public WriteStandardTags() { 68 | const tempFilePath = TestConstants.getTempFilePath(Mpeg_FileTests.tmpFileName); 69 | StandardFileTests.writeStandardTags(Mpeg_FileTests.sampleFilePath, tempFilePath, TestTagLevel.Medium); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /test-integration/ogg_opus_fileTests.ts: -------------------------------------------------------------------------------- 1 | import {assert} from "chai"; 2 | import {suite, test} from "@testdeck/mocha"; 3 | 4 | import ExtendedFileTests from "./utilities/extendedFileTests"; 5 | import TestConstants from "./utilities/testConstants"; 6 | import {File} from "../src"; 7 | import {StandardFileTests, TestTagLevel} from "./utilities/standardFileTests"; 8 | 9 | @suite class Ogg_Opus_FileTests { 10 | private static readonly sampleFilePath = TestConstants.getSampleFilePath("sample.opus"); 11 | private static readonly tmpFileName = "tmpwrite.opus"; 12 | 13 | private static file: File; 14 | 15 | public static before() { 16 | Ogg_Opus_FileTests.file = File.createFromPath(Ogg_Opus_FileTests.sampleFilePath); 17 | } 18 | 19 | public static after() { 20 | if (Ogg_Opus_FileTests.file) { Ogg_Opus_FileTests.file.dispose(); } 21 | } 22 | 23 | @test 24 | public readAudioProperties() { 25 | assert.strictEqual(Ogg_Opus_FileTests.file.properties.audioBitrate, 0); 26 | assert.strictEqual(Ogg_Opus_FileTests.file.properties.audioChannels, 2); 27 | assert.strictEqual(Ogg_Opus_FileTests.file.properties.audioSampleRate, 44100); 28 | assert.strictEqual(Ogg_Opus_FileTests.file.properties.bitsPerSample, 0); 29 | assert.approximately(Ogg_Opus_FileTests.file.properties.durationMilliseconds, 5232, 10); 30 | // TODO: Figure out why we're off by around 10 31 | } 32 | 33 | @test 34 | public readTags() { 35 | assert.strictEqual(Ogg_Opus_FileTests.file.tag.album, "Opus album"); 36 | assert.strictEqual(Ogg_Opus_FileTests.file.tag.firstPerformer, "Opus artist"); 37 | assert.strictEqual(Ogg_Opus_FileTests.file.tag.description, "Opus comment"); 38 | assert.strictEqual(Ogg_Opus_FileTests.file.tag.firstGenre, "Acid Punk"); 39 | assert.strictEqual(Ogg_Opus_FileTests.file.tag.title, "Opus title"); 40 | assert.strictEqual(Ogg_Opus_FileTests.file.tag.track, 6); 41 | assert.strictEqual(Ogg_Opus_FileTests.file.tag.trackCount, 7); 42 | assert.strictEqual(Ogg_Opus_FileTests.file.tag.year, 1234); 43 | } 44 | 45 | @test 46 | public writeStandardTags() { 47 | const tmpFilePath = TestConstants.getTempFilePath(Ogg_Opus_FileTests.tmpFileName); 48 | StandardFileTests.writeStandardTags(Ogg_Opus_FileTests.sampleFilePath, tmpFilePath, TestTagLevel.Medium); 49 | } 50 | 51 | @test 52 | public writeExtendedTags() { 53 | const tmpFilePath = TestConstants.getTempFilePath(Ogg_Opus_FileTests.tmpFileName); 54 | ExtendedFileTests.writeExtendedTags(Ogg_Opus_FileTests.sampleFilePath, tmpFilePath); 55 | } 56 | 57 | @test 58 | public writeStandardPictures() { 59 | const tmpFilePath = TestConstants.getTempFilePath(Ogg_Opus_FileTests.tmpFileName); 60 | StandardFileTests.writeStandardPictures(Ogg_Opus_FileTests.sampleFilePath, tmpFilePath); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test-integration/resources/corruptSamples/corrupt.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/corruptSamples/corrupt.aac -------------------------------------------------------------------------------- /test-integration/resources/corruptSamples/corrupt.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/corruptSamples/corrupt.aif -------------------------------------------------------------------------------- /test-integration/resources/corruptSamples/corrupt.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/corruptSamples/corrupt.avi -------------------------------------------------------------------------------- /test-integration/resources/corruptSamples/corrupt.flac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/corruptSamples/corrupt.flac -------------------------------------------------------------------------------- /test-integration/resources/corruptSamples/corrupt.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/corruptSamples/corrupt.m4a -------------------------------------------------------------------------------- /test-integration/resources/corruptSamples/corrupt.mpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/corruptSamples/corrupt.mpg -------------------------------------------------------------------------------- /test-integration/resources/corruptSamples/corrupt.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/corruptSamples/corrupt.ogg -------------------------------------------------------------------------------- /test-integration/resources/corruptSamples/corrupt.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/corruptSamples/corrupt.wav -------------------------------------------------------------------------------- /test-integration/resources/corruptSamples/corrupt.wma: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/corruptSamples/corrupt.wma -------------------------------------------------------------------------------- /test-integration/resources/corruptSamples/corruptMissingFlag.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/corruptSamples/corruptMissingFlag.ogg -------------------------------------------------------------------------------- /test-integration/resources/corruptSamples/corruptNullTitleId3v2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/corruptSamples/corruptNullTitleId3v2.mp3 -------------------------------------------------------------------------------- /test-integration/resources/samples/apple_tags.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/apple_tags.m4a -------------------------------------------------------------------------------- /test-integration/resources/samples/bgo_658920.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/bgo_658920.m4a -------------------------------------------------------------------------------- /test-integration/resources/samples/bgo_676934.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/bgo_676934.m4a -------------------------------------------------------------------------------- /test-integration/resources/samples/bgo_701689.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/bgo_701689.m4a -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.aac -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.aif -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.ape: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.ape -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.avi -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.flac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.flac -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.m4a -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.m4v: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.m4v -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.mkv -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.mp3 -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.mpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.mpg -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.ogg -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.ogv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.ogv -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.opus: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.opus -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.wav -------------------------------------------------------------------------------- /test-integration/resources/samples/sample.wma: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample.wma -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_gimp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_gimp.gif -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_props_cbr.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_props_cbr.mp3 -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_props_vbri.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_props_vbri.mp3 -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_props_xingabr.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_props_xingabr.mp3 -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_props_xingcbr.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_props_xingcbr.mp3 -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_props_xingvbr.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_props_xingvbr.mp3 -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_replaygain.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_replaygain.m4a -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_replaygain.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_replaygain.mp3 -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_teenytiny.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_teenytiny.gif -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_v1_only.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_v1_only.mp3 -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_v2_3_ext_header.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_v2_3_ext_header.mp3 -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_v2_4_unsynch.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_v2_4_unsynch.mp3 -------------------------------------------------------------------------------- /test-integration/resources/samples/sample_v2_only.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benrr101/node-taglib-sharp/e92ed7210da05fa13d01947243478adce87f578c/test-integration/resources/samples/sample_v2_only.mp3 -------------------------------------------------------------------------------- /test-integration/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "experimentalDecorators": true, 5 | "inlineSources": true, 6 | "module": "commonjs", 7 | "noImplicitAny": true, 8 | "outDir": "./dist", 9 | "sourceMap": true, 10 | "baseUrl": ".", 11 | "paths": { 12 | "*": ["node_modules/*"] 13 | }, 14 | "target": "es6" 15 | }, 16 | "include": [ "./**/*" ] 17 | } 18 | -------------------------------------------------------------------------------- /test-integration/utilities/extendedFileTests.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import {assert} from "chai"; 3 | 4 | import Utilities from "./utilities"; 5 | import {File, Tag} from "../../src"; 6 | 7 | export default class ExtendedFileTests { 8 | public static writeExtendedTags(sampleFile: string, tmpFile: string): void { 9 | if (fs.existsSync(tmpFile)) { 10 | fs.unlinkSync(tmpFile); 11 | } 12 | 13 | fs.copyFileSync(sampleFile, tmpFile); 14 | 15 | try { 16 | let tmp = File.createFromPath(tmpFile); 17 | ExtendedFileTests.setTags(tmp.tag); 18 | tmp.save(); 19 | 20 | tmp = File.createFromPath(tmpFile); 21 | ExtendedFileTests.checkTags(tmp.tag); 22 | } finally { 23 | Utilities.deleteBestEffort(tmpFile); 24 | } 25 | } 26 | 27 | private static checkTags(tag: Tag): void { 28 | assert.strictEqual(tag.replayGainTrackGain, -10.28); 29 | assert.strictEqual(tag.replayGainTrackPeak, 0.999969); 30 | assert.strictEqual(tag.replayGainAlbumGain, -9.98); 31 | assert.strictEqual(tag.replayGainAlbumPeak, 0.999980); 32 | } 33 | 34 | private static setTags(tag: Tag): void { 35 | tag.replayGainTrackGain = -10.28; 36 | tag.replayGainTrackPeak = 0.999969; 37 | tag.replayGainAlbumGain = -9.98; 38 | tag.replayGainAlbumPeak = 0.999980; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test-integration/utilities/testConstants.ts: -------------------------------------------------------------------------------- 1 | import * as Path from "path"; 2 | import {v4 as Uuidv4} from "uuid"; 3 | 4 | export default class TestConstants { 5 | public static testFileFolderPath: string = "./test-integration/resources"; 6 | 7 | public static getCorruptFilePath: (fileName: string) => string = (fileName: string ) => { 8 | return Path.join(TestConstants.testFileFolderPath, "corruptSamples", fileName); 9 | } 10 | 11 | public static getSampleFilePath: (fileName: string) => string = (fileName: string) => { 12 | return Path.join(TestConstants.testFileFolderPath, "samples", fileName); 13 | } 14 | 15 | public static getTempFilePath: (fileName: string) => string = (fileName: string) => { 16 | const fileUid: string = Uuidv4(); 17 | return Path.join(TestConstants.testFileFolderPath, `${fileUid}_${fileName}`); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test-integration/utilities/utilities.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | 3 | export default class Utilities { 4 | public static deleteBestEffort(path: string) { 5 | try { 6 | fs.unlinkSync(path); 7 | } catch { 8 | // Ignore failed deletions 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test-unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": ["../.eslintrc.js"], 3 | "rules": { 4 | "@typescript-eslint/dot-notation": "off", 5 | "@typescript-eslint/explicit-function-return-type": "off", 6 | "@typescript-eslint/naming-convention": "off", 7 | "@typescript-eslint/no-unsafe-argument": "off", 8 | "@typescript-eslint/no-unsafe-member-access": "off", 9 | "@typescript-eslint/no-unused-vars": "off", 10 | "dot-notation": "off" 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /test-unit/asf/objectTests.ts: -------------------------------------------------------------------------------- 1 | import {test} from "@testdeck/mocha"; 2 | import {assert} from "chai"; 3 | 4 | import TestFile from "../utilities/testFile"; 5 | import UuidWrapper from "../../src/uuidWrapper"; 6 | import {ByteVector} from "../../src/byteVector"; 7 | import {Testers} from "../utilities/testers"; 8 | import {File} from "../../src/file"; 9 | 10 | export default abstract class ObjectTests { 11 | protected abstract get fromFileConstructor(): (f: File, p: number) => TObject; 12 | protected abstract get minSize(): number; 13 | protected abstract get objectGuid(): UuidWrapper; 14 | 15 | @test 16 | public fromFile_invalidParameters() { 17 | // Arrange 18 | const mockFile = {}; 19 | 20 | // Act / Assert 21 | Testers.testTruthy((v: File) => this.fromFileConstructor(v, 0)); 22 | Testers.testSafeUint((v) => this.fromFileConstructor(mockFile, v)); 23 | } 24 | 25 | @test 26 | public fromFile_tooSmall() { 27 | // Only run if there is a min size 28 | if (this.minSize === undefined) { 29 | return; 30 | } 31 | 32 | // Arrange 33 | const data = ByteVector.concatenate( 34 | ByteVector.fromSize(10), // Offset 35 | this.objectGuid.toBytes(), // Object ID 36 | ByteVector.fromUlong(Math.min(26, this.minSize - 10)) // Object size 37 | ); 38 | const file = TestFile.getFile(data); 39 | 40 | // Act / Assert 41 | assert.throws(() => this.fromFileConstructor(file, 10)); 42 | } 43 | 44 | @test 45 | public fromFile_wrongGuid() { 46 | // Only run if there is a guid 47 | if (this.objectGuid === undefined) { 48 | return; 49 | } 50 | 51 | // Arrange 52 | const data = ByteVector.concatenate( 53 | ByteVector.fromSize(10), // Offset 54 | new UuidWrapper().toBytes(), // Object ID 55 | ByteVector.fromUlong(123), // Object size 56 | ByteVector.fromSize(20) // Just some bogus bytes 57 | ); 58 | const file = TestFile.getFile(data); 59 | 60 | // Act / Assert 61 | assert.throws(() => this.fromFileConstructor(file, 10)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test-unit/fileAbstractionTests.ts: -------------------------------------------------------------------------------- 1 | import * as Chai from "chai"; 2 | import * as TypeMoq from "typemoq"; 3 | import {suite, test} from "@testdeck/mocha"; 4 | 5 | import TestConstants from "./testConstants"; 6 | import {LocalFileAbstraction} from "../src/fileAbstraction"; 7 | import {IStream} from "../src/stream"; 8 | import {Testers} from "./utilities/testers"; 9 | 10 | // Setup Chai 11 | const assert = Chai.assert; 12 | 13 | @suite class LocalFileAbstractionTests { 14 | @test 15 | public constructor_test() { 16 | // Act 17 | const fileAbstraction = new LocalFileAbstraction(TestConstants.testFilePath); 18 | 19 | // Assert 20 | assert.strictEqual(fileAbstraction.name, TestConstants.testFilePath); 21 | 22 | let readStream; 23 | let writeStream; 24 | try { 25 | readStream = fileAbstraction.readStream; 26 | assert.isFalse(readStream.canWrite); 27 | 28 | writeStream = fileAbstraction.writeStream; 29 | assert.isTrue(writeStream.canWrite); 30 | } finally { 31 | if (readStream) { readStream.close(); } 32 | if (writeStream) { writeStream.close(); } 33 | } 34 | } 35 | 36 | @test 37 | public closeStream_invalidStream() { 38 | // Arrange 39 | const abstraction = new LocalFileAbstraction(TestConstants.testFilePath); 40 | 41 | // Act / Assert 42 | Testers.testTruthy((v: IStream) => { abstraction.closeStream(v); }); 43 | } 44 | 45 | @test 46 | public closeStream_closesStream() { 47 | // Arrange 48 | const abstraction = new LocalFileAbstraction(TestConstants.testFilePath); 49 | const testStream = TypeMoq.Mock.ofType(); 50 | testStream.setup((s) => s.close()); 51 | 52 | // Act 53 | abstraction.closeStream(testStream.object); 54 | 55 | // Assert 56 | testStream.verify((s) => s.close(), TypeMoq.Times.once()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test-unit/id3v2/frameConstructorTests.ts: -------------------------------------------------------------------------------- 1 | import {test} from "@testdeck/mocha"; 2 | 3 | import {ByteVector} from "../../src/byteVector"; 4 | import {Frame} from "../../src/id3v2/frames/frame"; 5 | import {Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; 6 | import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; 7 | import {Testers} from "../utilities/testers"; 8 | 9 | export default abstract class FrameConstructorTests { 10 | 11 | public abstract get fromOffsetRawData(): (d: ByteVector, o: number, h: Id3v2FrameHeader, v: number) => Frame; 12 | public abstract get fromRawData(): (d: ByteVector, v: number) => Frame; 13 | 14 | @test 15 | public fromOffsetRawData_falsyData_throws() { 16 | // Arrange 17 | const header = new Id3v2FrameHeader(FrameIdentifiers.WCOM); 18 | 19 | // Act/Assert 20 | Testers.testTruthy((v: ByteVector) => { this.fromOffsetRawData(v, 2, header, 4); }); 21 | } 22 | 23 | @test 24 | public fromOffsetRawData_invalidVersion_throws() { 25 | // Arrange 26 | const data = ByteVector.empty(); 27 | const header = new Id3v2FrameHeader(FrameIdentifiers.WCOM); 28 | 29 | // Act/Assert 30 | Testers.testUint((v: number) => { this.fromOffsetRawData(data, v, header, 4); }); 31 | } 32 | 33 | @test 34 | public fromOffsetRawData_falsyHeader_throws() { 35 | // Arrange 36 | const data = ByteVector.empty(); 37 | 38 | // Act/Assert 39 | Testers.testTruthy((v: Id3v2FrameHeader) => { this.fromOffsetRawData(data, 2, v, 4); }); 40 | } 41 | 42 | @test 43 | public fromRawData_falsyData_throws() { 44 | // Act/Assert 45 | Testers.testTruthy((v: ByteVector) => { this.fromRawData(v, 2); }); 46 | } 47 | 48 | @test 49 | public fromRawData_invalidVersion_throws() { 50 | // Arrange 51 | const data = ByteVector.empty(); 52 | 53 | // Act/Assert 54 | Testers.testByte((v: number) => { this.fromRawData(data, v); }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test-unit/id3v2/tagExtendedHeaderTests.ts: -------------------------------------------------------------------------------- 1 | import {suite, test} from "@testdeck/mocha"; 2 | import {assert} from "chai"; 3 | 4 | import Id3v2ExtendedHeader from "../../src/id3v2/id3v2ExtendedHeader"; 5 | import {ByteVector} from "../../src/byteVector"; 6 | import {Testers} from "../utilities/testers"; 7 | 8 | @suite class Id3v2_TagExtendedHeaderTests { 9 | @test 10 | public fromData_falsyData() { 11 | // Act/Assert 12 | Testers.testTruthy((v: ByteVector) => { Id3v2ExtendedHeader.fromData(v, 2); }); 13 | } 14 | 15 | @test 16 | public fromData_invalidVersion() { 17 | // Arrange 18 | const testData = ByteVector.empty(); 19 | 20 | // Act/Assert 21 | Testers.testByte((v: number) => { Id3v2ExtendedHeader.fromData(testData, v); }); 22 | } 23 | 24 | @test 25 | public fromData_version3() { 26 | // Arrange 27 | const testData = ByteVector.concatenate(0x10, 0x10, 0x10, 0x10); 28 | 29 | // Act 30 | const output = Id3v2ExtendedHeader.fromData(testData, 3); 31 | 32 | // Assert 33 | assert.equal(output.size, 4 + 0x2040810); 34 | } 35 | 36 | @test 37 | public fromData_version2() { 38 | // Arrange 39 | const testData = ByteVector.concatenate(0x10, 0x10, 0x10, 0x10); 40 | 41 | // Act 42 | const output = Id3v2ExtendedHeader.fromData(testData, 2); 43 | 44 | // Assert 45 | assert.equal(output.size, 0x2040810); 46 | } 47 | 48 | @test 49 | public fromData_version4() { 50 | // Arrange 51 | const testData = ByteVector.concatenate(0x10, 0x10, 0x10, 0x10); 52 | 53 | // Act 54 | const output = Id3v2ExtendedHeader.fromData(testData, 4); 55 | 56 | // Assert 57 | assert.equal(output.size, 0x2040810); 58 | } 59 | 60 | public fromEmpty() { 61 | // Act 62 | const output = Id3v2ExtendedHeader.fromEmpty(); 63 | 64 | // Assert 65 | assert.equal(output.size, 0); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /test-unit/matroska/matroskaTagTests.ts: -------------------------------------------------------------------------------- 1 | import {suite, test} from "@testdeck/mocha"; 2 | import {assert} from "chai"; 3 | import {Mock} from "typemoq"; 4 | 5 | import MatroskaTag from "../../src/matroska/matroskaTag"; 6 | import MatroskaTagValue from "../../src/matroska/matroskaTagValue"; 7 | import {MatroskaTagTarget} from "../../src/matroska/matroskaTagTarget"; 8 | import {Testers} from "../utilities/testers"; 9 | 10 | @suite 11 | class Matroska_TagTests { 12 | @test 13 | public constructor_invalidParams() { 14 | // Arrange 15 | const mockValue = Mock.ofType(); 16 | const mockTarget = Mock.ofType(); 17 | 18 | // Act / Assert 19 | Testers.testTruthy((v) => new MatroskaTag(v, mockTarget.object)); 20 | Testers.testTruthy((v) => new MatroskaTag(mockValue.object, v)); 21 | } 22 | 23 | @test 24 | public constructor_valid() { 25 | // Arrange 26 | const mockValue = Mock.ofType(); 27 | const mockTarget = Mock.ofType(); 28 | 29 | // Act 30 | const tag = new MatroskaTag(mockValue.object, mockTarget.object); 31 | 32 | // Assert 33 | assert.strictEqual(tag.value, mockValue.object); 34 | assert.strictEqual(tag.target, mockTarget.object); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test-unit/matroska/utils.ts: -------------------------------------------------------------------------------- 1 | import {ByteVector, StringType} from "../../src"; 2 | import EbmlElement from "../../src/ebml/ebmlElement"; 3 | import TestFile from "../utilities/testFile"; 4 | 5 | export default class MatroskaTestUtils { 6 | public static getTestElement(value: string|boolean|number|bigint|ByteVector, id: number): EbmlElement { 7 | let bytes: ByteVector; 8 | // noinspection FallThroughInSwitchStatementJS 9 | switch (typeof (value)) { 10 | case "object": 11 | if (value instanceof ByteVector) { 12 | bytes = value; 13 | } 14 | break; 15 | 16 | case "string": 17 | bytes = ByteVector.fromString(value, StringType.UTF8); 18 | break; 19 | 20 | case "bigint": 21 | bytes = ByteVector.fromUlong(value); 22 | break; 23 | 24 | case "boolean": 25 | value = value ? 1 : 0; 26 | 27 | case "number": 28 | bytes = ByteVector.fromUint(value); 29 | break; 30 | } 31 | 32 | return new EbmlElement(TestFile.getFile(bytes), 0, id, bytes.length, {}); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test-unit/mpeg/mpegContainerFileTests.ts: -------------------------------------------------------------------------------- 1 | import {suite, test} from "@testdeck/mocha"; 2 | import {assert} from "chai"; 3 | 4 | import MpegContainerFile from "../../src/mpeg/mpegContainerFile"; 5 | import MpegContainerFileSettings from "../../src/mpeg/mpegContainerFileSettings"; 6 | import {default as TestFile} from "../utilities/testFile"; 7 | import {ByteVector} from "../../src/byteVector"; 8 | import {ReadStyle} from "../../src/file"; 9 | import {TagTypes} from "../../src/tag"; 10 | 11 | @suite class MpegContainer_MpegContainerFileTests { 12 | @test 13 | public constructor_noDefaultsPreferred() { 14 | // Arrange 15 | const originalDefaults = MpegContainerFileSettings.defaultTagTypes; 16 | try { 17 | const testAbstraction = TestFile.getFileAbstraction(ByteVector.fromSize(100)); 18 | 19 | // Act 20 | MpegContainerFileSettings.defaultTagTypes = TagTypes.None; 21 | const file = new MpegContainerFile(testAbstraction, ReadStyle.None); 22 | 23 | // Assert 24 | assert.isEmpty(file.tag.tags); 25 | assert.strictEqual(file.tagTypes, TagTypes.None); 26 | assert.strictEqual(file.tagTypesOnDisk, TagTypes.None); 27 | assert.isUndefined(file.properties); 28 | 29 | } finally { 30 | // Cleanup 31 | MpegContainerFileSettings.defaultTagTypes = originalDefaults; 32 | } 33 | } 34 | 35 | @test 36 | public constructor_defaultTagsAtEnd() { 37 | // Arrange 38 | const originalDefaults = MpegContainerFileSettings.defaultTagTypes; 39 | try { 40 | const testAbstraction = TestFile.getFileAbstraction(ByteVector.fromSize(100)); 41 | 42 | // Act 43 | MpegContainerFileSettings.defaultTagTypes = TagTypes.Id3v1 | TagTypes.Id3v2 | TagTypes.Ape; 44 | const file = new MpegContainerFile(testAbstraction, ReadStyle.None); 45 | 46 | // Assert 47 | assert.strictEqual(file.tag.tags.length, 3); 48 | assert.strictEqual(file.tagTypes, TagTypes.Id3v1 | TagTypes.Id3v2 | TagTypes.Ape); 49 | assert.strictEqual(file.tagTypesOnDisk, TagTypes.None); 50 | 51 | assert.strictEqual(file.tag.startTag.tags.length, 0); 52 | assert.strictEqual(file.tag.startTag.tagTypes, TagTypes.None); 53 | assert.strictEqual(file.tag.endTag.tags.length, 3); 54 | assert.strictEqual(file.tag.endTag.tagTypes, TagTypes.Id3v1 | TagTypes.Id3v2 | TagTypes.Ape); 55 | 56 | assert.isUndefined(file.properties); 57 | 58 | } finally { 59 | // Cleanup 60 | MpegContainerFileSettings.defaultTagTypes = originalDefaults; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test-unit/mpeg/mpegVideoHeaderTests.ts: -------------------------------------------------------------------------------- 1 | import * as TypeMoq from "typemoq"; 2 | import {suite, test} from "@testdeck/mocha"; 3 | import {assert} from "chai"; 4 | 5 | import MpegVideoHeader from "../../src/mpeg/mpegVideoHeader"; 6 | import TestFile from "../utilities/testFile"; 7 | import {ByteVector} from "../../src/byteVector"; 8 | import {File} from "../../src/file"; 9 | import {MediaTypes} from "../../src/properties"; 10 | import {Testers} from "../utilities/testers"; 11 | 12 | @suite class Mpeg_VideoHeader_ConstructorTests { 13 | @test 14 | public constructor_invalidArguments() { 15 | // Act/Assert 16 | Testers.testTruthy((f: File) => new MpegVideoHeader(f, 0)); 17 | Testers.testUint((p: number) => new MpegVideoHeader(TypeMoq.Mock.ofType().object, p)); 18 | } 19 | 20 | @test 21 | public constructor_headerTooShort() { 22 | // Arrange 23 | const mockData = ByteVector.fromSize(10); 24 | const mockFile = TestFile.getFile(mockData); 25 | 26 | // Act/Assert 27 | assert.throws(() => new MpegVideoHeader(mockFile, 5)); 28 | } 29 | 30 | @test 31 | public constructor_validData() { 32 | // Arrange 33 | const mockData = ByteVector.concatenate( 34 | 0x00, 0x00, 0x00, 35 | 0x28, 0x31, 0xE3, 0x26, // 643x483, 4:3 aspect ratio, 50fps 36 | 0xD8, 0x53, 0xBF // 221518bps 37 | ); 38 | const mockFile = TestFile.getFile(mockData); 39 | 40 | // Act 41 | const header = new MpegVideoHeader(mockFile, 3); 42 | 43 | // Assert 44 | assert.strictEqual(header.description, "MPEG Video"); 45 | assert.strictEqual(header.durationMilliseconds, 0); 46 | assert.strictEqual(header.mediaTypes, MediaTypes.Video); 47 | assert.strictEqual(header.videoBitrate, 221518); 48 | assert.strictEqual(header.videoFrameRate, 50); 49 | assert.strictEqual(header.videoHeight, 483); 50 | assert.strictEqual(header.videoWidth, 643); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test-unit/mpeg/vbriHeaderTests.ts: -------------------------------------------------------------------------------- 1 | import {suite, test} from "@testdeck/mocha"; 2 | import {assert} from "chai"; 3 | import {Mock} from "typemoq"; 4 | 5 | import TestFile from "../utilities/testFile"; 6 | import VbriHeader from "../../src/mpeg/vbriHeader"; 7 | import {ByteVector, StringType} from "../../src/byteVector"; 8 | import {File} from "../../src/file"; 9 | import {Testers} from "../utilities/testers"; 10 | 11 | @suite class Mpeg_XingHeaderTests { 12 | 13 | @test 14 | public fromFile_invalidParameters() { 15 | // Arrange 16 | const mockFile = Mock.ofType().object; 17 | 18 | // Act / Assert 19 | Testers.testTruthy((f: File) => VbriHeader.fromFile(f, 0, 1, 1, )); 20 | Testers.testUint((v: number) => VbriHeader.fromFile(mockFile, v, 1, 1)); 21 | Testers.testUint((v: number) => VbriHeader.fromFile(mockFile, 0, v, 1)); 22 | assert.throws(() => VbriHeader.fromFile(mockFile, 0, 0, 1)); 23 | Testers.testUint((v: number) => VbriHeader.fromFile(mockFile, 0, 1, v)); 24 | assert.throws(() => VbriHeader.fromFile(mockFile, 0, 1, 0)); 25 | } 26 | 27 | @test 28 | public fromFile_fileTooShort() { 29 | // Arrange 30 | const file = TestFile.getFile(ByteVector.fromSize(60)); 31 | 32 | // Act / Assert 33 | assert.isUndefined(VbriHeader.fromFile(file, 1, 1, 1)); 34 | } 35 | 36 | @test 37 | public fromFile_doesNotStartWithIdentifier() { 38 | // Arrange 39 | const file = TestFile.getFile(ByteVector.fromSize(60)); 40 | 41 | // Act / Assert 42 | assert.isUndefined(VbriHeader.fromFile(file, 0, 1, 1)); 43 | } 44 | 45 | @test 46 | public fromFile_validParameters() { 47 | // Arrange 48 | const file = TestFile.getFile(ByteVector.concatenate( 49 | ByteVector.fromSize(40), 50 | ByteVector.fromString("VBRI", StringType.Latin1), 51 | ByteVector.fromSize(2), // Version 52 | ByteVector.fromUshort(12), // Delay 53 | ByteVector.fromSize(2), // Quality 54 | ByteVector.fromUint(12345), // Bytes 55 | ByteVector.fromUint(123), // Frames 56 | ByteVector.fromSize(8) // TOC Size, TOC scale, TOC entry size, TOC entry frame count 57 | )); 58 | 59 | // Act 60 | const header = VbriHeader.fromFile(file, 4, 1152, 44100); 61 | 62 | // Assert 63 | assert.isOk(header); 64 | assert.strictEqual(header.bitrateKilobytes, 30); 65 | assert.approximately(header.durationMilliseconds, 3212, 1); 66 | assert.strictEqual(header.totalBytes, 12345); 67 | assert.strictEqual(header.totalFrames, 123); 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /test-unit/mpeg4/mpeg4UtilsTests.ts: -------------------------------------------------------------------------------- 1 | import {suite, test} from "@testdeck/mocha"; 2 | import {assert} from "chai"; 3 | 4 | import Mpeg4BoxHeader from "../../src/mpeg4/mpeg4BoxHeader"; 5 | import Mpeg4Utils from "../../src/mpeg4/mpeg4Utils"; 6 | import {ByteVector, StringType} from "../../src/byteVector"; 7 | 8 | @suite 9 | class Mpeg4_Mpeg4UtilsTests { 10 | @test 11 | public addParent_withParentsNull_returnsListContainingOnlyCurrent() { 12 | // Arrange 13 | const current: Mpeg4BoxHeader = Mpeg4BoxHeader.fromType(ByteVector.fromString("xxxx", StringType.Latin1)); 14 | 15 | // Act 16 | const headers: Mpeg4BoxHeader[] = Mpeg4Utils.addParent(null, current); 17 | 18 | // Assert 19 | assert.equal(headers.length, 1); 20 | assert.equal(headers[0], current); 21 | } 22 | 23 | @test 24 | public addParent_withParentsUndefined_returnsListContainingOnlyCurrent() { 25 | // Arrange 26 | const current: Mpeg4BoxHeader = Mpeg4BoxHeader.fromType(ByteVector.fromString("xxxx", StringType.Latin1)); 27 | 28 | // Act 29 | const headers: Mpeg4BoxHeader[] = Mpeg4Utils.addParent(undefined, current); 30 | 31 | // Assert 32 | assert.equal(headers.length, 1); 33 | assert.equal(headers[0], current); 34 | } 35 | 36 | @test 37 | public addParent_withParentsHaving2Elements_returnsListContainingParentsFollowedByCurrent() { 38 | // Arrange 39 | const parent1: Mpeg4BoxHeader = Mpeg4BoxHeader.fromType(ByteVector.fromString("xxxx", StringType.Latin1)); 40 | const parent2: Mpeg4BoxHeader = Mpeg4BoxHeader.fromType(ByteVector.fromString("xxxx", StringType.Latin1)); 41 | const parents: Mpeg4BoxHeader[] = [parent1, parent2]; 42 | const current: Mpeg4BoxHeader = Mpeg4BoxHeader.fromType(ByteVector.fromString("xxxx", StringType.Latin1)); 43 | 44 | // Act 45 | const headers: Mpeg4BoxHeader[] = Mpeg4Utils.addParent(parents, current); 46 | 47 | // Assert 48 | assert.equal(headers.length, 3); 49 | assert.equal(headers[0], parent1); 50 | assert.equal(headers[1], parent2); 51 | assert.equal(headers[2], current); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test-unit/ogg/codecPackets.ts: -------------------------------------------------------------------------------- 1 | import {ByteVector, StringType} from "../../src/byteVector"; 2 | 3 | export default class CodecPackets { 4 | public static getTestOpusPacket(): ByteVector { 5 | return ByteVector.concatenate( 6 | ByteVector.fromString("OpusHead", StringType.UTF8), 7 | 0x01, 0x08, 0x03, 0x04, 8 | 0x05, 0x06, 0x07, 0x08, 9 | 0x09, 0x0A, 0x01, 0x05, 0x03 10 | ); 11 | } 12 | 13 | public static getTestTheoraPacket(): ByteVector { 14 | return ByteVector.concatenate( 15 | 0x80, ByteVector.fromString("theora", StringType.UTF8), 16 | 0x01, 0x02, 0x03, // version 17 | ByteVector.fromUint(0), // Size in macro blocks 18 | 0xF0, 0x12, 0x34, // Width in pixels 19 | 0xF0, 0x45, 0x67, // Height in pixels 20 | 0x01, 0x02, // Picture offset in pixels 21 | ByteVector.fromUint(1234), // Frame rate numerator 22 | ByteVector.fromUint(2345), // Frame rate denominator 23 | ByteVector.fromSize(10, 0xFF), // Stuff we don't care about 24 | 0xFC, 0x56, 0xEF // "last bits" including keyframe granule shift 25 | ); 26 | } 27 | 28 | public static getTestVorbisPacket(): ByteVector { 29 | return ByteVector.concatenate( 30 | 0x01, ByteVector.fromString("vorbis", StringType.UTF8), 31 | ByteVector.fromUint(1234, false), // Version 32 | 0x05, // Channels 33 | ByteVector.fromUint(456789, false), // Sample rate 34 | ByteVector.fromUint(200000, false), // bitrate max 35 | ByteVector.fromUint(128000, false), // bitrate nominal 36 | ByteVector.fromUint(100000, false), // bitrate min 37 | // We don't care about anything after this 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test-unit/resources/testFile.txt: -------------------------------------------------------------------------------- 1 | 12345abcde -------------------------------------------------------------------------------- /test-unit/riff/riffWaveFormatExTests.ts: -------------------------------------------------------------------------------- 1 | import {suite, test} from "@testdeck/mocha"; 2 | import {assert} from "chai"; 3 | 4 | import RiffWaveFormatEx from "../../src/riff/riffWaveFormatEx"; 5 | import {default as Resources} from "./resources"; 6 | import {ByteVector} from "../../src/byteVector"; 7 | import {MediaTypes} from "../../src/properties"; 8 | import {Testers} from "../utilities/testers"; 9 | 10 | @suite class Riff_WaveFormatExTests { 11 | @test 12 | public constructor_invalidParams() { 13 | // Act / Assert 14 | Testers.testTruthy((v: ByteVector) => new RiffWaveFormatEx(v)); 15 | } 16 | 17 | @test 18 | public constructor_dataTooShort() { 19 | // Arrange 20 | const data = ByteVector.fromSize(10); 21 | 22 | // Act / Assert 23 | assert.throws(() => new RiffWaveFormatEx(data)); 24 | } 25 | 26 | @test 27 | public constructor_knownAudioFormat() { 28 | // Arrange 29 | const data = Resources.getAudioFormatBlock(0xF1AC); 30 | 31 | // Act 32 | const object = new RiffWaveFormatEx(data); 33 | 34 | // Assert 35 | assert.strictEqual(object.audioBitrate, 2345 * 8 / 1000); 36 | assert.strictEqual(object.audioChannels, 3); 37 | assert.strictEqual(object.audioSampleRate, 1234); 38 | assert.strictEqual(object.averageBytesPerSecond, 2345); 39 | assert.strictEqual(object.bitsPerSample, 16); 40 | assert.isTrue(object.description.indexOf("FLAC") >= 0); 41 | assert.isTrue(object.description.indexOf("0xF1AC") >= 0); 42 | assert.strictEqual(object.durationMilliseconds, 0); 43 | assert.strictEqual(object.formatTag, 0xF1AC); 44 | assert.strictEqual(object.mediaTypes, MediaTypes.LosslessAudio); 45 | } 46 | 47 | @test 48 | public constructor_unknownAudioFormat() { 49 | // Arrange 50 | const data = Resources.getAudioFormatBlock(0xBBBB); 51 | 52 | // Act 53 | const object = new RiffWaveFormatEx(data); 54 | 55 | // Assert 56 | assert.strictEqual(object.audioBitrate, 2345 * 8 / 1000); 57 | assert.strictEqual(object.audioChannels, 3); 58 | assert.strictEqual(object.audioSampleRate, 1234); 59 | assert.strictEqual(object.averageBytesPerSecond, 2345); 60 | assert.strictEqual(object.bitsPerSample, 16); 61 | assert.isTrue(object.description.indexOf( "Unknown") >= 0); 62 | assert.isTrue(object.description.indexOf("0xBBBB") >= 0); 63 | assert.strictEqual(object.durationMilliseconds, 0); 64 | assert.strictEqual(object.formatTag, 0xBBBB); 65 | assert.strictEqual(object.mediaTypes, MediaTypes.LosslessAudio); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /test-unit/testConstants.ts: -------------------------------------------------------------------------------- 1 | import * as Path from "path"; 2 | import {v4 as Uuidv4} from "uuid"; 3 | 4 | import {ByteVector, StringType} from "../src/byteVector"; 5 | 6 | export default class TestConstants { 7 | public static testFileFolderPath: string = "./test-unit/resources/"; 8 | public static testFileName = "testFile.txt"; 9 | public static testFilePath: string = Path.join(TestConstants.testFileFolderPath, TestConstants.testFileName); 10 | public static testFileContents: Uint8Array = new Uint8Array( 11 | [0x31, 0x32, 0x33, 0x34, 0x35, 0x61, 0x62, 0x63, 0x64, 0x65] 12 | ); 13 | public static testFileContentsStr: string = "12345abcde"; 14 | 15 | public static getTestFilePath: () => string = () => { 16 | const fileUid: string = Uuidv4(); 17 | return Path.join(TestConstants.testFileFolderPath, `testFile_${fileUid}.txt`); 18 | } 19 | 20 | public static testStrings: {[key: string]: {bytes: Uint8Array, str: string}} = { 21 | Latin1: { 22 | bytes: new Uint8Array([ 23 | 0x21, 0x31, 0x32, 0x33, 0x41, 0x42, 0x43, 0x61, 0x62, 0x63, 0xC1, 0xD1, 0xFC, 0xAE, 0xBE 24 | ]), 25 | str: "!123ABCabcÁÑü®¾" 26 | }, 27 | UTF16BE: { 28 | bytes: new Uint8Array([ 29 | 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 30 | 0x03, 0xBA, 0x03, 0xCC, 0x03, 0xC3, 0x03, 0xBC, 0x03, 0xB5 31 | ]), 32 | str: "abcκόσμε" 33 | }, 34 | UTF16LE: { 35 | bytes: new Uint8Array([ 36 | 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 37 | 0xBA, 0x03, 0xCC, 0x03, 0xC3, 0x03, 0xBC, 0x03, 0xB5, 0x03 38 | ]), 39 | str: "abcκόσμε" 40 | }, 41 | UTF16LEWithBOM: { 42 | bytes: new Uint8Array([ 43 | 0xFF, 0xFE, 44 | 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 45 | 0xBA, 0x03, 0xCC, 0x03, 0xC3, 0x03, 0xBC, 0x03, 0xB5, 0x03 46 | ]), 47 | str: "abcκόσμε" 48 | }, 49 | UTF8: { 50 | bytes: new Uint8Array([ 51 | 0x61, 0x62, 0x63, 52 | 0xCE, 0xBA, 0xCF, 0x8C, 0xCF, 0x83, 0xCE, 0xBC, 0xCE, 0xB5 53 | ]), 54 | str: "abcκόσμε" 55 | } 56 | }; 57 | 58 | public static testByteVector: ByteVector = ByteVector.fromString("foobarbaz", StringType.UTF8); 59 | 60 | public static syncedUint = 0x2040810; 61 | public static syncedUintBytes = ByteVector.fromSize(4, 0x10); 62 | } 63 | -------------------------------------------------------------------------------- /test-unit/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "experimentalDecorators": true, 5 | "inlineSources": true, 6 | "module": "commonjs", 7 | "noImplicitAny": true, 8 | "outDir": "./dist", 9 | "sourceMap": true, 10 | "baseUrl": ".", 11 | "paths": { 12 | "*": ["node_modules/*"] 13 | }, 14 | "target": "es6" 15 | }, 16 | "include": [ "./**/*" ] 17 | } 18 | -------------------------------------------------------------------------------- /test-unit/utilities/propertyTests.ts: -------------------------------------------------------------------------------- 1 | import {assert} from "chai"; 2 | 3 | export default class PropertyTests { 4 | public static propertyRoundTrip(set: (v: T) => void, get: () => T, val: T) { 5 | // Act 6 | set(val); 7 | const output = get(); 8 | 9 | // Assert 10 | assert.deepStrictEqual(output, val); 11 | } 12 | 13 | public static propertyNormalized(set: (v: T) => void, get: () => T, input: T, output: T) { 14 | // Act 15 | set(input); 16 | const result = get(); 17 | 18 | // Assert 19 | assert.deepStrictEqual(result, output); 20 | } 21 | 22 | public static propertyThrows(set: (v: T) => void, input: T) { 23 | // Act 24 | assert.throws(() => { set(input); }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test-unit/utilities/testFile.ts: -------------------------------------------------------------------------------- 1 | import * as TypeMoq from "typemoq"; 2 | 3 | import TestConstants from "../testConstants"; 4 | import TestStream from "./testStream"; 5 | import {ByteVector} from "../../src/byteVector"; 6 | import {File} from "../../src/file"; 7 | import {IStream, SeekOrigin} from "../../src/stream"; 8 | import {IFileAbstraction} from "../../src/fileAbstraction"; 9 | 10 | export type TestFileAbstraction = IFileAbstraction & {allBytes: ByteVector}; 11 | export default { 12 | mockFile: (): File => { return TypeMoq.Mock.ofType().object; }, 13 | getFile: (data: ByteVector|number[]): File => { 14 | const mockFile = TypeMoq.Mock.ofType(); 15 | let position = 0; 16 | 17 | const dataBv = data instanceof ByteVector 18 | ? data 19 | : ByteVector.fromByteArray(data); 20 | 21 | mockFile.setup((f) => f.length).returns(() => dataBv.length); 22 | mockFile.setup((f) => f.seek(TypeMoq.It.isAnyNumber(), TypeMoq.It.isAny())) 23 | .returns((p: number, o: SeekOrigin) => { 24 | switch (o || SeekOrigin.Begin) { 25 | case SeekOrigin.Begin: 26 | position = Math.min(dataBv.length, p); 27 | break; 28 | case SeekOrigin.Current: 29 | position = Math.min(dataBv.length, position + p); 30 | break; 31 | case SeekOrigin.End: 32 | position = Math.min(dataBv.length, dataBv.length + p); 33 | break; 34 | } 35 | }); 36 | mockFile.setup((f) => f.readBlock(TypeMoq.It.isAnyNumber())) 37 | .returns((s: number) => { 38 | if (position + s > dataBv.length) { 39 | s = dataBv.length - position; 40 | } 41 | if (s <= 0) { 42 | return ByteVector.empty(); 43 | } 44 | 45 | const output = dataBv.subarray(position, s); 46 | position += s; 47 | return output; 48 | }); 49 | mockFile.setup((f) => f.position) 50 | .returns(() => { 51 | return position; 52 | }); 53 | mockFile.setup((f) => f.mode); 54 | 55 | return mockFile.object; 56 | }, 57 | getFileAbstraction: (data: ByteVector): TestFileAbstraction => { 58 | return { 59 | name: TestConstants.name, 60 | get allBytes(): ByteVector { return data; }, 61 | get readStream(): IStream { return new TestStream(data, false); }, 62 | get writeStream(): IStream { return new TestStream(data, true); }, 63 | closeStream: (stream: IStream): void => { stream.close(); } 64 | }; 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /test-unit/utilities/testStream.ts: -------------------------------------------------------------------------------- 1 | import {ByteVector} from "../../src/byteVector"; 2 | import {IStream, SeekOrigin} from "../../src/stream"; 3 | 4 | export default class TestStream implements IStream { 5 | private readonly _isWritable: boolean; 6 | private readonly _data: ByteVector; 7 | private _position: number; 8 | 9 | public constructor(bytesToReturn: ByteVector, isWritable: boolean) { 10 | this._data = bytesToReturn; 11 | this._position = 0; 12 | this._isWritable = isWritable; 13 | } 14 | 15 | public get canWrite(): boolean { 16 | return this._isWritable; 17 | } 18 | 19 | public get data(): ByteVector { return this._data; } 20 | 21 | public get length(): number { 22 | return this._data.length; 23 | } 24 | 25 | public get position(): number { 26 | return this._position; 27 | } 28 | public set position(value: number) { 29 | this._position = value; 30 | } 31 | 32 | public close(): void { /* no op */ } 33 | 34 | public read(buffer: Uint8Array, bufferOffset: number, length: number): number { 35 | let bytesRead = 0; 36 | while (bytesRead < length && this._position + bytesRead < this._data.length) { 37 | buffer[bufferOffset + bytesRead] = this._data.get(this._position + bytesRead); 38 | bytesRead++; 39 | } 40 | 41 | this._position += bytesRead; 42 | return bytesRead; 43 | } 44 | 45 | public seek(offset: number, origin: SeekOrigin): void { 46 | switch (origin) { 47 | case SeekOrigin.Begin: 48 | this._position = offset; 49 | break; 50 | case SeekOrigin.Current: 51 | this._position += offset; 52 | break; 53 | case SeekOrigin.End: 54 | this._position = this._data.length - offset; 55 | break; 56 | } 57 | } 58 | 59 | public setLength(length: number): void { 60 | this._data.resize(length); 61 | this._position = Math.max(this.length, this._position); 62 | } 63 | 64 | public write(buffer: ByteVector | Uint8Array, bufferOffset: number, length: number): number { 65 | if (buffer instanceof Uint8Array) { 66 | buffer = ByteVector.fromByteArray(buffer); 67 | } 68 | 69 | if (!this._isWritable) { 70 | throw new Error("Invalid operation: this stream is a read-only stream"); 71 | } 72 | 73 | const bufferStart = bufferOffset; 74 | const bufferEnd = bufferOffset + length; 75 | const bytesToWrite = buffer.subarray(bufferStart, bufferEnd); 76 | this._data.splice(this._position, bytesToWrite.length, bytesToWrite); 77 | this._position = bufferOffset + bytesToWrite.length; 78 | 79 | return bytesToWrite.length; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /test-unit/xiph/resources.ts: -------------------------------------------------------------------------------- 1 | import {ByteVector, PictureType, StringType} from "../../src"; 2 | 3 | export default class XiphTestResources { 4 | public static readonly pictureData = ByteVector.fromString("foobarbaz", StringType.UTF8); 5 | public static readonly pictureMimeType = "application/octet-stream"; 6 | public static readonly pictureDescription = "image"; 7 | public static readonly pictureWidth = 640; 8 | public static readonly pictureHeight = 480; 9 | public static readonly pictureColorDepth = 123; 10 | public static readonly pictureIndexedColors = 234; 11 | public static readonly pictureType = PictureType.ColoredFish; 12 | public static readonly pictureBytes = ByteVector.concatenate( 13 | ByteVector.fromUint(XiphTestResources.pictureType), 14 | ByteVector.fromUint(XiphTestResources.pictureMimeType.length), 15 | ByteVector.fromString(XiphTestResources.pictureMimeType, StringType.UTF8), 16 | ByteVector.fromUint(XiphTestResources.pictureDescription.length), 17 | ByteVector.fromString(XiphTestResources.pictureDescription, StringType.UTF8), 18 | ByteVector.fromUint(XiphTestResources.pictureWidth), 19 | ByteVector.fromUint(XiphTestResources.pictureHeight), 20 | ByteVector.fromUint(XiphTestResources.pictureColorDepth), 21 | ByteVector.fromUint(XiphTestResources.pictureIndexedColors), 22 | ByteVector.fromUint(XiphTestResources.pictureData.length), 23 | XiphTestResources.pictureData 24 | ); 25 | public static readonly pictureEncodedBytes = XiphTestResources.pictureBytes.toBase64String(); 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "experimentalDecorators": true, 5 | "inlineSources": true, 6 | "module": "commonjs", 7 | "noImplicitAny": true, 8 | "outDir": "./dist", 9 | "sourceMap": true, 10 | "baseUrl": ".", 11 | "paths": { 12 | "*": ["node_modules/*"] 13 | }, 14 | "target": "es6" 15 | }, 16 | "include": [ 17 | "./src/**/*", 18 | ".eslintrc.js" 19 | ], 20 | "typedocOptions": { 21 | "entryPoints": ["./src/index.ts"], 22 | "out": "docs/", 23 | "excludeInternal": true, 24 | "excludePrivate": true, 25 | "disableSources": true, 26 | "validation": { 27 | "invalidLink": true, 28 | "notDocumented": true 29 | } 30 | } 31 | } 32 | --------------------------------------------------------------------------------