node-av 0.0.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -117
- package/binding.gyp +1 -1
- package/dist/api/encoder.js +5 -7
- package/dist/api/encoder.js.map +1 -1
- package/dist/lib/binding.d.ts +3 -3
- package/dist/lib/binding.js +12 -36
- package/dist/lib/binding.js.map +1 -1
- package/dist/lib/constants.d.ts +0 -19
- package/dist/lib/constants.js +0 -13
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/error.d.ts +64 -12
- package/dist/lib/error.js +85 -15
- package/dist/lib/error.js.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +2 -2
- package/dist/lib/index.js.map +1 -1
- package/install/check.js +76 -66
- package/install/ffmpeg.js +26 -112
- package/package.json +16 -18
- package/release_notes.md +11 -0
package/install/check.js
CHANGED
|
@@ -1,113 +1,123 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { join } from 'node:path';
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
log(msg);
|
|
7
|
-
log('Building from source requires:');
|
|
8
|
-
log(' - FFmpeg 7.1+ with development headers');
|
|
9
|
-
log(' - Python 3.12+');
|
|
10
|
-
log(' - node-gyp and node-addon-api');
|
|
7
|
+
import { log, spawnRebuild, useGlobalFFmpeg } from './ffmpeg.js';
|
|
11
8
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
|
|
11
|
+
const tryLoadPrebuilt = () => {
|
|
12
|
+
// Try to load from platform-specific package (optionalDependencies)
|
|
13
|
+
const platform = process.platform;
|
|
14
|
+
const arch = process.arch;
|
|
15
|
+
const packageName = `@seydx/node-av-${platform}-${arch}`;
|
|
15
16
|
|
|
16
17
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const packagePath = require.resolve(`${packageName}/node-av.node`);
|
|
19
|
+
if (existsSync(packagePath)) {
|
|
20
|
+
log(`Using prebuilt binary from ${packageName}`);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
20
23
|
} catch {
|
|
21
|
-
//
|
|
24
|
+
// Package not installed or file not found
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Try local binary folder (for development)
|
|
28
|
+
const localBinary = join(process.cwd(), 'binary', 'node-av.node');
|
|
29
|
+
if (existsSync(localBinary)) {
|
|
30
|
+
log('Using local binary from binary/node-av.node');
|
|
31
|
+
return true;
|
|
22
32
|
}
|
|
23
33
|
|
|
34
|
+
return false;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const buildFromSource = () => {
|
|
38
|
+
log('Building from source...');
|
|
39
|
+
|
|
40
|
+
// Check for required build dependencies
|
|
41
|
+
const missingDeps = [];
|
|
42
|
+
|
|
24
43
|
try {
|
|
25
|
-
|
|
26
|
-
await import('node-gyp');
|
|
27
|
-
hasNodeGyp = true;
|
|
44
|
+
require('node-addon-api');
|
|
28
45
|
} catch {
|
|
29
|
-
|
|
46
|
+
missingDeps.push('node-addon-api');
|
|
30
47
|
}
|
|
31
48
|
|
|
32
|
-
|
|
49
|
+
try {
|
|
50
|
+
require('node-gyp');
|
|
51
|
+
} catch {
|
|
52
|
+
missingDeps.push('node-gyp');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (missingDeps.length > 0) {
|
|
33
56
|
log('');
|
|
34
|
-
log(
|
|
35
|
-
log('
|
|
57
|
+
log(`Missing build dependencies: ${missingDeps.join(', ')}`);
|
|
58
|
+
log('Please install:');
|
|
59
|
+
log(` npm install --save-dev ${missingDeps.join(' ')}`);
|
|
36
60
|
log('');
|
|
37
61
|
log('Then run npm install again.');
|
|
38
62
|
process.exit(1);
|
|
39
63
|
}
|
|
40
64
|
|
|
41
|
-
log('Found required build dependencies');
|
|
42
65
|
log('Building native bindings...');
|
|
43
66
|
|
|
44
67
|
const status = spawnRebuild();
|
|
45
68
|
if (status !== 0) {
|
|
69
|
+
log('');
|
|
46
70
|
log('Build failed. Please ensure you have:');
|
|
47
71
|
log(' - FFmpeg 7.1+ libraries and headers installed');
|
|
48
72
|
log(' - Python 3.12+ installed');
|
|
49
73
|
log(' - A C++ compiler with C++17 support');
|
|
74
|
+
log('');
|
|
50
75
|
log('See https://github.com/seydx/av for detailed requirements');
|
|
51
76
|
process.exit(status);
|
|
52
77
|
}
|
|
78
|
+
|
|
79
|
+
log('Build completed successfully!');
|
|
53
80
|
};
|
|
54
81
|
|
|
55
82
|
(async () => {
|
|
56
83
|
try {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
log(`Using prebuilt binary from ${packageName}`);
|
|
84
|
+
const shouldBuildFromSource = process.env.npm_config_build_from_source === 'true';
|
|
85
|
+
|
|
86
|
+
// Priority 1: User explicitly wants to build from source
|
|
87
|
+
if (shouldBuildFromSource) {
|
|
88
|
+
if (!useGlobalFFmpeg()) {
|
|
89
|
+
log('--build-from-source specified but no FFmpeg libraries found');
|
|
90
|
+
log('Please install FFmpeg 7.1+ with development headers');
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
// Fall through to build logic below
|
|
94
|
+
} else {
|
|
95
|
+
// Priority 2: Try to use prebuilt binary if not forcing source build
|
|
96
|
+
if (tryLoadPrebuilt()) {
|
|
71
97
|
return;
|
|
72
|
-
} catch {
|
|
73
|
-
// No prebuilt binary available, will build from source
|
|
74
98
|
}
|
|
75
99
|
}
|
|
76
100
|
|
|
77
|
-
//
|
|
78
|
-
if (useGlobalFFmpeg(
|
|
79
|
-
|
|
80
|
-
if (versions && versions.length > 0) {
|
|
81
|
-
log('Detected globally-installed FFmpeg libraries:');
|
|
82
|
-
for (const lib of versions) {
|
|
83
|
-
log(` ✓ ${lib.name.padEnd(20)} v${lib.version} (${lib.description})`);
|
|
84
|
-
}
|
|
85
|
-
await buildFromSource('Building with system FFmpeg');
|
|
86
|
-
} else {
|
|
87
|
-
await buildFromSource(`Detected globally-installed FFmpeg v${globalFFmpegVersion()}`);
|
|
88
|
-
}
|
|
89
|
-
} else {
|
|
90
|
-
// No system FFmpeg found
|
|
101
|
+
// Build from source (either requested or as fallback)
|
|
102
|
+
if (useGlobalFFmpeg()) {
|
|
103
|
+
// Determine why we're building
|
|
91
104
|
if (shouldBuildFromSource) {
|
|
92
|
-
log('
|
|
93
|
-
log('Please install FFmpeg 7.1+ with development headers');
|
|
94
|
-
process.exit(1);
|
|
105
|
+
log('Building from source as requested');
|
|
95
106
|
} else {
|
|
96
107
|
log('No prebuilt binary available for your platform');
|
|
97
|
-
log('
|
|
98
|
-
log('');
|
|
99
|
-
log('Please install FFmpeg 7.1+ and build dependencies:');
|
|
100
|
-
log(' - FFmpeg development libraries');
|
|
101
|
-
log(' - Python 3.12+');
|
|
102
|
-
log(' - npm install --save-dev node-addon-api node-gyp');
|
|
103
|
-
log('');
|
|
104
|
-
log('Then run npm install again.');
|
|
105
|
-
process.exit(1);
|
|
108
|
+
log('System FFmpeg detected, building from source automatically');
|
|
106
109
|
}
|
|
110
|
+
|
|
111
|
+
buildFromSource();
|
|
112
|
+
} else {
|
|
113
|
+
// No FFmpeg found and no prebuilt available
|
|
114
|
+
log('⚠️ No prebuilt binary and no system FFmpeg found');
|
|
115
|
+
log('Please install FFmpeg 7.1+ with development headers');
|
|
116
|
+
log('See https://github.com/seydx/av for installation instructions');
|
|
117
|
+
process.exit(1);
|
|
107
118
|
}
|
|
108
119
|
} catch (err) {
|
|
109
|
-
|
|
110
|
-
console.log(`node-av: installation error: ${summary}`);
|
|
120
|
+
console.error(`node-av: Installation error: ${err.message}`);
|
|
111
121
|
process.exit(1);
|
|
112
122
|
}
|
|
113
123
|
})();
|
package/install/ffmpeg.js
CHANGED
|
@@ -1,29 +1,13 @@
|
|
|
1
|
-
// https://github.com/lovell/sharp/blob/main/lib/libvips.js
|
|
1
|
+
// Adapted from https://github.com/lovell/sharp/blob/main/lib/libvips.js
|
|
2
2
|
|
|
3
3
|
import detectLibc from 'detect-libc';
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
|
-
import { readFileSync } from 'node:fs';
|
|
6
|
-
import { dirname, join } from 'node:path';
|
|
7
|
-
import { fileURLToPath } from 'node:url';
|
|
8
|
-
import semverCoerce from 'semver/functions/coerce.js';
|
|
9
|
-
import semverGreaterThanOrEqualTo from 'semver/functions/gte.js';
|
|
10
|
-
import semverSatisfies from 'semver/functions/satisfies.js';
|
|
11
|
-
|
|
12
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
-
const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
|
|
14
|
-
const { engines } = packageJson;
|
|
15
5
|
|
|
16
6
|
const spawnSyncOptions = {
|
|
17
7
|
encoding: 'utf8',
|
|
18
8
|
shell: true,
|
|
19
9
|
};
|
|
20
10
|
|
|
21
|
-
// Minimum FFmpeg version required
|
|
22
|
-
export const minimumFFmpegVersion = '7.1.0';
|
|
23
|
-
|
|
24
|
-
// Minimum Python version required for node-gyp
|
|
25
|
-
export const minimumPythonVersion = '3.12.0';
|
|
26
|
-
|
|
27
11
|
export const log = (item) => {
|
|
28
12
|
if (item instanceof Error) {
|
|
29
13
|
console.error(`node-av: Installation error: ${item.message}`);
|
|
@@ -42,122 +26,52 @@ export const buildPlatformArch = () => {
|
|
|
42
26
|
return `${npm_config_platform ?? process.platform}${libc}-${npm_config_arch ?? process.arch}`;
|
|
43
27
|
};
|
|
44
28
|
|
|
45
|
-
export const isUnsupportedNodeRuntime = () => {
|
|
46
|
-
if (process.release?.name === 'node' && process.versions) {
|
|
47
|
-
if (!semverSatisfies(process.versions.node, engines.node)) {
|
|
48
|
-
return { found: process.versions.node, expected: engines.node };
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
29
|
export const spawnRebuild = () =>
|
|
54
30
|
spawnSync('node-gyp rebuild', {
|
|
55
31
|
...spawnSyncOptions,
|
|
56
32
|
stdio: 'inherit',
|
|
57
33
|
}).status;
|
|
58
34
|
|
|
59
|
-
export const
|
|
60
|
-
if (process.platform
|
|
61
|
-
const ffmpegVersion =
|
|
62
|
-
spawnSync('pkg-config --modversion libavcodec', {
|
|
63
|
-
...spawnSyncOptions,
|
|
64
|
-
env: {
|
|
65
|
-
...process.env,
|
|
66
|
-
PKG_CONFIG_PATH: pkgConfigPath(),
|
|
67
|
-
},
|
|
68
|
-
}).stdout || '';
|
|
69
|
-
return ffmpegVersion.trim();
|
|
70
|
-
} else {
|
|
35
|
+
export const pkgConfigPath = () => {
|
|
36
|
+
if (process.platform === 'win32') {
|
|
71
37
|
return '';
|
|
72
38
|
}
|
|
73
|
-
};
|
|
74
39
|
|
|
75
|
-
|
|
76
|
-
if (process.platform === 'win32') {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
40
|
+
const paths = [];
|
|
79
41
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
{ name: 'libswresample', description: 'audio resampling library' },
|
|
86
|
-
{ name: 'libavfilter', description: 'filter library' },
|
|
87
|
-
{ name: 'libavdevice', description: 'device library' },
|
|
88
|
-
{ name: 'libpostproc', description: 'post-processing library' },
|
|
89
|
-
];
|
|
90
|
-
|
|
91
|
-
const versions = [];
|
|
92
|
-
|
|
93
|
-
for (const lib of libraries) {
|
|
94
|
-
const version = spawnSync(`pkg-config --modversion ${lib.name}`, {
|
|
95
|
-
...spawnSyncOptions,
|
|
96
|
-
env: {
|
|
97
|
-
...process.env,
|
|
98
|
-
PKG_CONFIG_PATH: pkgConfigPath(),
|
|
99
|
-
},
|
|
100
|
-
}).stdout;
|
|
101
|
-
|
|
102
|
-
if (version && version.trim()) {
|
|
103
|
-
versions.push({
|
|
104
|
-
name: lib.name,
|
|
105
|
-
description: lib.description,
|
|
106
|
-
version: version.trim(),
|
|
107
|
-
});
|
|
42
|
+
// Try homebrew path on macOS
|
|
43
|
+
if (process.platform === 'darwin') {
|
|
44
|
+
const brewPath = spawnSync('brew --prefix 2>/dev/null', spawnSyncOptions).stdout;
|
|
45
|
+
if (brewPath) {
|
|
46
|
+
paths.push(`${brewPath.trim()}/lib/pkgconfig`);
|
|
108
47
|
}
|
|
109
48
|
}
|
|
110
49
|
|
|
111
|
-
|
|
112
|
-
|
|
50
|
+
// Add standard paths
|
|
51
|
+
paths.push(process.env.PKG_CONFIG_PATH, '/usr/local/lib/pkgconfig', '/usr/lib/pkgconfig', '/usr/local/libdata/pkgconfig', '/usr/libdata/pkgconfig');
|
|
113
52
|
|
|
114
|
-
|
|
115
|
-
if (process.platform !== 'win32') {
|
|
116
|
-
const brewPkgConfigPath = spawnSync('which brew >/dev/null 2>&1 && brew environment --plain | grep PKG_CONFIG_LIBDIR | cut -d" " -f2', spawnSyncOptions).stdout || '';
|
|
117
|
-
return [
|
|
118
|
-
brewPkgConfigPath.trim(),
|
|
119
|
-
process.env.PKG_CONFIG_PATH,
|
|
120
|
-
'/usr/local/lib/pkgconfig',
|
|
121
|
-
'/usr/lib/pkgconfig',
|
|
122
|
-
'/usr/local/libdata/pkgconfig',
|
|
123
|
-
'/usr/libdata/pkgconfig',
|
|
124
|
-
]
|
|
125
|
-
.filter(Boolean)
|
|
126
|
-
.join(':');
|
|
127
|
-
} else {
|
|
128
|
-
return '';
|
|
129
|
-
}
|
|
53
|
+
return paths.filter(Boolean).join(':');
|
|
130
54
|
};
|
|
131
55
|
|
|
132
|
-
export const useGlobalFFmpeg = (
|
|
133
|
-
|
|
134
|
-
if (!globalVersion) {
|
|
56
|
+
export const useGlobalFFmpeg = () => {
|
|
57
|
+
if (process.platform === 'win32') {
|
|
135
58
|
return false;
|
|
136
59
|
}
|
|
137
60
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}).stdout || '';
|
|
149
|
-
if (!version?.trim()) {
|
|
150
|
-
if (logger) {
|
|
151
|
-
logger(`Missing required FFmpeg library: ${lib}`);
|
|
152
|
-
}
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
61
|
+
let ffmpegVersion =
|
|
62
|
+
spawnSync('pkg-config --modversion libavcodec', {
|
|
63
|
+
...spawnSyncOptions,
|
|
64
|
+
env: {
|
|
65
|
+
...process.env,
|
|
66
|
+
PKG_CONFIG_PATH: pkgConfigPath(),
|
|
67
|
+
},
|
|
68
|
+
}).stdout || '';
|
|
69
|
+
|
|
70
|
+
ffmpegVersion = ffmpegVersion.trim();
|
|
156
71
|
|
|
157
|
-
|
|
158
|
-
if (!coercedVersion) {
|
|
72
|
+
if (!ffmpegVersion) {
|
|
159
73
|
return false;
|
|
160
74
|
}
|
|
161
75
|
|
|
162
|
-
return
|
|
76
|
+
return true;
|
|
163
77
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-av",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "FFmpeg bindings for Node.js",
|
|
5
5
|
"author": "seydx (https://github.com/seydx/av)",
|
|
6
6
|
"type": "module",
|
|
@@ -32,17 +32,16 @@
|
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
|
-
"build": "npm run build:
|
|
36
|
-
"build:all": "npm run build:native && npm run build:tests && npm run build:examples && npm run build:tsc",
|
|
35
|
+
"build": "npm run generate && npm run build:tests && npm run build:examples && npm run build:tsc && npm run build:native",
|
|
37
36
|
"build:examples": "tsc -p tsconfig.examples.json",
|
|
38
37
|
"build:native": "node-gyp rebuild && cpy --flat build/Release/node-av.node binary/",
|
|
39
38
|
"build:tests": "tsc -p tsconfig.tests.json",
|
|
40
|
-
"build:tsc": "rimraf dist &&
|
|
41
|
-
"clean": "node-gyp clean &&
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"generate:constants": "node scripts/generate-constants.js && prettier --write
|
|
45
|
-
"generate:layouts": "node scripts/generate-channel-layouts.js && prettier --write
|
|
39
|
+
"build:tsc": "rimraf dist && tsc -p tsconfig.build.json",
|
|
40
|
+
"clean": "rimraf dist && node-gyp clean && npm run generate && npm run format && npm run lint:fix && npm run build:tests && npm run build:examples && npm run build:tsc",
|
|
41
|
+
"format": "prettier --write src/ --write test/ --write scripts/ --write examples/ --ignore-unknown --no-error-on-unmatched-pattern",
|
|
42
|
+
"generate": "npm run generate:constants && npm run generate:layouts",
|
|
43
|
+
"generate:constants": "node scripts/generate-constants.js && prettier --write src/lib/constants.ts",
|
|
44
|
+
"generate:layouts": "node scripts/generate-channel-layouts.js && prettier --write src/lib/channel-layouts.ts",
|
|
46
45
|
"install": "node install/check.js",
|
|
47
46
|
"install-updates": "npm i --save",
|
|
48
47
|
"lint": "eslint .",
|
|
@@ -50,20 +49,19 @@
|
|
|
50
49
|
"release:patch": "node scripts/prepare-release.js patch",
|
|
51
50
|
"release:minor": "node scripts/prepare-release.js minor",
|
|
52
51
|
"release:major": "node scripts/prepare-release.js major",
|
|
53
|
-
"test:all": "npm run build:tests && npm run build:tsc && tsx --test test
|
|
52
|
+
"test:all": "npm run generate && npm run build:tests && npm run build:tsc && tsx --test test/*.test.ts",
|
|
54
53
|
"update": "updates --update ./"
|
|
55
54
|
},
|
|
56
55
|
"dependencies": {
|
|
57
|
-
"detect-libc": "^2.0.4"
|
|
58
|
-
"semver": "^7.7.2"
|
|
56
|
+
"detect-libc": "^2.0.4"
|
|
59
57
|
},
|
|
60
58
|
"optionalDependencies": {
|
|
61
|
-
"@seydx/node-av-darwin-arm64": "^
|
|
62
|
-
"@seydx/node-av-darwin-x64": "^
|
|
63
|
-
"@seydx/node-av-linux-arm64": "^
|
|
64
|
-
"@seydx/node-av-linux-x64": "^
|
|
65
|
-
"@seydx/node-av-win32-arm64": "^
|
|
66
|
-
"@seydx/node-av-win32-x64": "^
|
|
59
|
+
"@seydx/node-av-darwin-arm64": "^1.0.1",
|
|
60
|
+
"@seydx/node-av-darwin-x64": "^1.0.1",
|
|
61
|
+
"@seydx/node-av-linux-arm64": "^1.0.1",
|
|
62
|
+
"@seydx/node-av-linux-x64": "^1.0.1",
|
|
63
|
+
"@seydx/node-av-win32-arm64": "^1.0.1",
|
|
64
|
+
"@seydx/node-av-win32-x64": "^1.0.1"
|
|
67
65
|
},
|
|
68
66
|
"devDependencies": {
|
|
69
67
|
"@stylistic/eslint-plugin": "^5.2.3",
|
package/release_notes.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## node-av Release v1.0.1
|
|
2
|
+
|
|
3
|
+
### 📦 Updated Packages
|
|
4
|
+
|
|
5
|
+
The following platform packages have been updated to v1.0.1:
|
|
6
|
+
- `@seydx/node-av-darwin-arm64@v1.0.1`
|
|
7
|
+
- `@seydx/node-av-darwin-x64@v1.0.1`
|
|
8
|
+
- `@seydx/node-av-linux-arm64@v1.0.1`
|
|
9
|
+
- `@seydx/node-av-linux-x64@v1.0.1`
|
|
10
|
+
- `@seydx/node-av-win32-arm64@v1.0.1`
|
|
11
|
+
- `@seydx/node-av-win32-x64@v1.0.1`
|