├── examples
├── angular
│ ├── .gitignore
│ ├── src
│ │ ├── app
│ │ │ ├── app.config.ts
│ │ │ ├── app.component.html
│ │ │ └── app.component.ts
│ │ ├── main.ts
│ │ └── index.html
│ ├── .vscode
│ │ └── settings.json
│ ├── tsconfig.app.json
│ ├── README.md
│ ├── eslint.config.js
│ ├── tsconfig.json
│ ├── package.json
│ └── angular.json
├── vite-react
│ ├── src
│ │ ├── vite-env.d.ts
│ │ ├── main.tsx
│ │ └── App.tsx
│ ├── .gitignore
│ ├── index.html
│ ├── README.md
│ ├── tsconfig.json
│ ├── eslint.config.js
│ ├── package.json
│ └── vite.config.ts
├── webpack-react
│ ├── .gitignore
│ ├── src
│ │ ├── index.html
│ │ ├── main.tsx
│ │ └── App.tsx
│ ├── .vscode
│ │ └── settings.json
│ ├── tsconfig.json
│ ├── eslint.config.js
│ ├── README.md
│ ├── package.json
│ └── webpack.config.js
└── browser-umd
│ ├── example.js
│ └── index.html
├── .husky
└── commit-msg
├── __tests__
├── fixtures
│ └── many_tracks.mp4
├── jest.d.ts
├── unicode.test.ts
├── locateFile.test.ts
├── concurrentAnalysis.test.ts
├── many_tracks.test.ts
├── args.test.ts
├── error.readChunk.test.ts
├── instantiation.test.ts
├── AudioVideoInterleave.avi.test.ts
├── error.wasmLoading.test.ts
├── jest
│ ├── toBeNear.ts
│ └── setup.ts
├── freeMXF-mxf1.mxf.test.ts
├── utils.ts
├── coverData.test.ts
├── options.test.ts
└── dwsample_mp4_360p.mp4.test.ts
├── .prettierrc.json
├── gulpfile.ts
├── .versionrc.json
├── .gitignore
├── gulp
├── typings
│ └── gulp.d.ts
├── index.ts
├── default.ts
├── compile
│ ├── zenlib.ts
│ ├── mediainfolib.ts
│ ├── optimizeWasm.ts
│ └── wasm.ts
├── declaration.ts
├── download.ts
├── generate-types
│ ├── data
│ │ ├── parseCsv.ts
│ │ ├── parseXsd.ts
│ │ └── getFields.ts
│ ├── factories.ts
│ └── generate.ts
├── transpile
│ ├── babel.ts
│ └── rollup.ts
├── constants.ts
└── utils.ts
├── .editorconfig
├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── FEATURE_REQUEST.md
│ └── BUG_REPORT.md
├── CONTRIBUTING.md
└── workflows
│ └── close_inactive_issues.yml
├── .vscode
└── settings.json
├── jest.config.json
├── src
├── error.ts
├── index.ts
├── typeGuard.ts
├── MediaInfoModule.d.ts
├── MediaInfoModule.cpp
├── cli.ts
├── mediaInfoFactory.ts
└── MediaInfo.ts
├── patches
└── gulp-sourcemaps@3.0.0.patch
├── tsconfig.json
├── README.md
├── LICENSE.txt
├── babel.config.cjs
├── eslint.config.js
├── package.json
└── CHANGELOG.md
/examples/angular/.gitignore:
--------------------------------------------------------------------------------
1 | /dist
2 | /node_modules
3 | /.angular
4 |
--------------------------------------------------------------------------------
/examples/vite-react/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/examples/webpack-react/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | .webpack/
4 | dist/
5 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | pnpm commitlint --edit ${1}
5 |
--------------------------------------------------------------------------------
/__tests__/fixtures/many_tracks.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/buzz/mediainfo.js/main/__tests__/fixtures/many_tracks.mp4
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "arrowParens": "always",
3 | "endOfLine": "lf",
4 | "printWidth": 100,
5 | "semi": false,
6 | "singleQuote": true,
7 | "trailingComma": "es5"
8 | }
9 |
--------------------------------------------------------------------------------
/gulpfile.ts:
--------------------------------------------------------------------------------
1 | export {
2 | babel,
3 | declaration,
4 | default,
5 | download,
6 | generateTypes,
7 | mediainfolib,
8 | rollup,
9 | wasm,
10 | zenlib,
11 | } from './gulp/index.ts'
12 |
--------------------------------------------------------------------------------
/.versionrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "header": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n:::note\nChanges preceding version 0.2.0 are not included in the changelog.\n:::\n"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.svn
2 | *~
3 | .DS_Store
4 | ThumbsDB
5 | \#*#
6 | .#*
7 | /node_modules
8 | npm-debug.log
9 | /build
10 | /dist
11 | /__tests__/fixtures
12 | !/__tests__/fixtures/many_tracks.mp4
13 | /TODO.txt
14 |
--------------------------------------------------------------------------------
/gulp/typings/gulp.d.ts:
--------------------------------------------------------------------------------
1 | // @types/gulp-babel is incomplete as it lacks `envName` property in `options`
2 |
3 | declare module 'gulp-babel' {
4 | function babel(options?: { envName: string }): NodeJS.ReadWriteStream
5 | export default babel
6 | }
7 |
--------------------------------------------------------------------------------
/examples/angular/src/app/app.config.ts:
--------------------------------------------------------------------------------
1 | import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'
2 |
3 | export const appConfig: ApplicationConfig = {
4 | providers: [provideZoneChangeDetection({ eventCoalescing: true })],
5 | }
6 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 | end_of_line = lf
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/examples/angular/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnSave": true,
3 | "eslint.experimental.useFlatConfig": true,
4 | "search.exclude": {
5 | "**/dist": true,
6 | "**/node_modules": true
7 | },
8 | "editor.rulers": [100]
9 | }
10 |
--------------------------------------------------------------------------------
/examples/webpack-react/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | mediainfo.js Webpack/React Example
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/webpack-react/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnSave": true,
3 | "eslint.experimental.useFlatConfig": true,
4 | "search.exclude": {
5 | "**/dist": true,
6 | "**/node_modules": true
7 | },
8 | "editor.rulers": [100]
9 | }
10 |
--------------------------------------------------------------------------------
/examples/webpack-react/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { createRoot } from 'react-dom/client'
3 | import App from './App'
4 |
5 | const appEl = document.getElementById('app')
6 |
7 | if (appEl) {
8 | createRoot(appEl).render()
9 | }
10 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: 🙋 Ask a question on Stack Overflow
4 | url: https://stackoverflow.com/search?q=mediainfo.js
5 | about: Check if your question has been answered at Stack Overflow. Or create a new question.
6 |
--------------------------------------------------------------------------------
/examples/angular/src/app/app.component.html:
--------------------------------------------------------------------------------
1 | MediaInfo Angular Example
2 |
3 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnSave": true,
3 | "eslint.useFlatConfig": true,
4 | "search.exclude": {
5 | "**/.husky": true,
6 | "**/build": true,
7 | "**/dist": true,
8 | "**/docs": true,
9 | "**/node_modules": true
10 | },
11 | "editor.rulers": [100]
12 | }
13 |
--------------------------------------------------------------------------------
/examples/angular/src/main.ts:
--------------------------------------------------------------------------------
1 | import { bootstrapApplication } from '@angular/platform-browser'
2 | import { appConfig } from './app/app.config'
3 | import { AppComponent } from './app/app.component'
4 |
5 | bootstrapApplication(AppComponent, appConfig).catch((err: unknown) => {
6 | console.error(err)
7 | })
8 |
--------------------------------------------------------------------------------
/examples/vite-react/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.tsx'
4 |
5 | const rootEl = document.getElementById('root')
6 |
7 | if (rootEl) {
8 | ReactDOM.createRoot(rootEl).render(
9 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/examples/angular/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/examples/angular/README.md:
--------------------------------------------------------------------------------
1 | # mediainfo.js Angular example
2 |
3 | ## WASM module
4 |
5 | The `MediaInfoModule.wasm` file is copied during build using `assets` configuration.
6 |
7 | ```json
8 | "assets": [
9 | {
10 | "input": "node_modules/mediainfo.js/dist",
11 | "glob": "MediaInfoModule.wasm",
12 | "output": ""
13 | }
14 | ],
15 | ```
16 |
--------------------------------------------------------------------------------
/jest.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "globalSetup": "/__tests__/jest/setup.ts",
3 | "setupFilesAfterEnv": ["/__tests__/jest/toBeNear.ts"],
4 | "testEnvironment": "jest-environment-node",
5 | "testMatch": ["**/__tests__/**/*.test.ts"],
6 | "testPathIgnorePatterns": ["/build/", "/dist/", "/node_modules/"],
7 | "verbose": true
8 | }
9 |
--------------------------------------------------------------------------------
/__tests__/jest.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare namespace jest {
4 | interface Matchers {
5 | /**
6 | * Use `.toBeNear` when checking if a number is a given offset away from a given value.
7 | *
8 | * @param {Number} value
9 | * @param {Number} offset
10 | */
11 | toBeNear(value: number, offset: number): R
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/examples/vite-react/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/examples/angular/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | mediainfo.js Angular example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/vite-react/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | mediainfo.js Vite/React Example
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/error.ts:
--------------------------------------------------------------------------------
1 | function isError(error: unknown): error is Error {
2 | return (
3 | error !== null &&
4 | typeof error === 'object' &&
5 | Object.prototype.hasOwnProperty.call(error, 'message')
6 | )
7 | }
8 |
9 | function unknownToError(error: unknown): Error {
10 | if (isError(error)) {
11 | return error
12 | }
13 | return new Error(typeof error === 'string' ? error : 'Unknown error')
14 | }
15 |
16 | export { unknownToError }
17 |
--------------------------------------------------------------------------------
/examples/webpack-react/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "baseUrl": ".",
5 | "esModuleInterop": true,
6 | "jsx": "react",
7 | "module": "ESNext",
8 | "moduleResolution": "node",
9 | "noImplicitAny": true,
10 | "outDir": "dist",
11 | "resolveJsonModule": true,
12 | "skipLibCheck": true,
13 | "sourceMap": true,
14 | "strict": true,
15 | "target": "ES6"
16 | },
17 | "include": ["src", "webpack.config.js"]
18 | }
19 |
--------------------------------------------------------------------------------
/gulp/index.ts:
--------------------------------------------------------------------------------
1 | export { default as mediainfolib } from './compile/mediainfolib.ts'
2 | export { default as wasm } from './compile/wasm.ts'
3 | export { default as zenlib } from './compile/zenlib.ts'
4 | export { default as declaration } from './declaration.ts'
5 | export { default } from './default.ts'
6 | export { default as download } from './download.ts'
7 | export { default as generateTypes } from './generate-types/generate.ts'
8 | export { default as babel } from './transpile/babel.ts'
9 | export { default as rollup } from './transpile/rollup.ts'
10 |
--------------------------------------------------------------------------------
/__tests__/unicode.test.ts:
--------------------------------------------------------------------------------
1 | import { analyzeFile, expectToBeDefined, fixturePath } from './utils.ts'
2 |
3 | const filePath = fixturePath('sample.mkv')
4 |
5 | it('should return unicode data', async () => {
6 | const result = await analyzeFile(filePath, { full: true })
7 | expectToBeDefined(result.media)
8 |
9 | const { track } = result.media
10 | const [track0] = track
11 | expect(track0.Title).toBe(
12 | 'Dès Noël où un zéphyr haï me vêt de glaçons würmiens je dîne ' +
13 | 'd’exquis rôtis de bœuf au kir à l’aÿ d’âge mûr & cætera !'
14 | )
15 | })
16 |
--------------------------------------------------------------------------------
/__tests__/locateFile.test.ts:
--------------------------------------------------------------------------------
1 | import path from 'node:path'
2 |
3 | import mediaInfoFactory from '..'
4 |
5 | const distDir = path.resolve(import.meta.dirname, '..', 'dist', 'cjs')
6 |
7 | it('should use locateFile callback', async () => {
8 | const locateFile = jest.fn((filename: string, prefix: string) =>
9 | path.resolve(prefix, '..', filename)
10 | )
11 | const mi = await mediaInfoFactory({ locateFile })
12 | expect(locateFile).toHaveBeenCalledTimes(1)
13 | expect(locateFile).toHaveBeenCalledWith('MediaInfoModule.wasm', `${distDir}/`)
14 | mi.close()
15 | })
16 |
--------------------------------------------------------------------------------
/examples/angular/eslint.config.js:
--------------------------------------------------------------------------------
1 | import globals from 'globals'
2 | import tsEslint from 'typescript-eslint'
3 |
4 | export default tsEslint.config(
5 | ...tsEslint.configs.strictTypeChecked,
6 | ...tsEslint.configs.stylisticTypeChecked,
7 | {
8 | files: ['**/*.{js,ts,tsx}'],
9 | languageOptions: {
10 | globals: globals.browser,
11 | parserOptions: {
12 | project: true,
13 | tsconfigRootDir: import.meta.dirname,
14 | },
15 | },
16 | },
17 | {
18 | ignores: ['dist/*', 'eslint.config.js', 'vite.config.ts'],
19 | }
20 | )
21 |
--------------------------------------------------------------------------------
/__tests__/concurrentAnalysis.test.ts:
--------------------------------------------------------------------------------
1 | import mediaInfoFactory, { type ReadChunkFunc } from '..'
2 |
3 | const readChunk: ReadChunkFunc = async () => {
4 | await new Promise((r) => setTimeout(r, 50))
5 | return new Uint8Array([1, 2, 3])
6 | }
7 |
8 | it('should not allow multiple simultaneous analyzeData calls (issue #173)', async () => {
9 | const mi = await mediaInfoFactory()
10 | void mi.analyzeData(99_999, readChunk)
11 |
12 | await expect(mi.analyzeData(99_999, readChunk)).rejects.toThrow(
13 | /cannot start a new analysis while another is in progress/
14 | )
15 | })
16 |
--------------------------------------------------------------------------------
/patches/gulp-sourcemaps@3.0.0.patch:
--------------------------------------------------------------------------------
1 | diff --git a/src/utils.js b/src/utils.js
2 | index 33a0003d7293e502c508b63ef748aae77ca2754f..199564829258dd72e1167f0f67d1d0381ffa0364 100644
3 | --- a/src/utils.js
4 | +++ b/src/utils.js
5 | @@ -28,6 +28,9 @@ var commentFormatters = {
6 | js: function jsCommentFormatter(preLine, newline, url) {
7 | return preLine + '//# sourceMappingURL=' + url + newline;
8 | },
9 | + cjs: function jsCommentFormatter(preLine, newline, url) {
10 | + return preLine + '//# sourceMappingURL=' + url + newline;
11 | + },
12 | default: function defaultFormatter() {
13 | return '';
14 | },
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export type {
2 | FormatType,
3 | default as MediaInfo,
4 | ReadChunkFunc,
5 | ResultMap,
6 | SizeArg,
7 | } from './MediaInfo.js'
8 | export type { MediaInfoFactoryOptions } from './mediaInfoFactory.js'
9 | export { default, default as mediaInfoFactory } from './mediaInfoFactory.js'
10 | export type {
11 | AudioTrack,
12 | BaseTrack,
13 | CreationInfo,
14 | Extra,
15 | GeneralTrack,
16 | ImageTrack,
17 | Media,
18 | MediaInfoResult,
19 | MenuTrack,
20 | OtherTrack,
21 | TextTrack,
22 | Track,
23 | VideoTrack,
24 | } from './MediaInfoResult.js'
25 | export { isTrackType } from './typeGuard.js'
26 |
--------------------------------------------------------------------------------
/src/typeGuard.ts:
--------------------------------------------------------------------------------
1 | import type { Track } from './MediaInfoResult'
2 |
3 | /**
4 | * Checks if a given object is of a specified track type.
5 | *
6 | * @template T - The type of track to check for.
7 | * @param thing - The object to check.
8 | * @param type - The track type to check against.
9 | * @returns A boolean indicating whether the object is of the specified track type.
10 | */
11 | function isTrackType(
12 | thing: unknown,
13 | type: T
14 | ): thing is Extract