sync
This commit is contained in:
18
README.md
18
README.md
@@ -12,7 +12,7 @@ npx @grom13/dvc-cli video.mp4
|
||||
|
||||
# Или глобальная установка
|
||||
npm install -g @grom13/dvc-cli
|
||||
dvc video.mp4
|
||||
dvc-cli video.mp4
|
||||
```
|
||||
|
||||
**Системные требования:**
|
||||
@@ -32,7 +32,7 @@ brew install ffmpeg gpac
|
||||
## Параметры CLI
|
||||
|
||||
```bash
|
||||
dvc <input-video> [output-dir] [-r resolutions] [-p poster-timecode]
|
||||
dvc-cli <input-video> [output-dir] [-r resolutions] [-p poster-timecode]
|
||||
```
|
||||
|
||||
### Основные параметры
|
||||
@@ -53,25 +53,25 @@ dvc <input-video> [output-dir] [-r resolutions] [-p poster-timecode]
|
||||
|
||||
```bash
|
||||
# Базовая конвертация (результат в текущей папке)
|
||||
dvc video.mp4
|
||||
dvc-cli video.mp4
|
||||
|
||||
# Указать выходную директорию
|
||||
dvc video.mp4 ./output
|
||||
dvc-cli video.mp4 ./output
|
||||
|
||||
# Только выбранные разрешения
|
||||
dvc video.mp4 -r 720,1080,1440
|
||||
dvc-cli video.mp4 -r 720,1080,1440
|
||||
|
||||
# Высокий FPS для игровых стримов
|
||||
dvc video.mp4 -r 720@60,1080@60
|
||||
dvc-cli video.mp4 -r 720@60,1080@60
|
||||
|
||||
# Постер с 5-й секунды
|
||||
dvc video.mp4 -p 5
|
||||
dvc-cli video.mp4 -p 5
|
||||
|
||||
# Постер в формате времени
|
||||
dvc video.mp4 -p 00:01:30
|
||||
dvc-cli video.mp4 -p 00:01:30
|
||||
|
||||
# Комбинация параметров
|
||||
dvc video.mp4 ./output -r 720,1080@60,1440@60 -p 00:00:10
|
||||
dvc-cli video.mp4 ./output -r 720,1080@60,1440@60 -p 00:00:10
|
||||
```
|
||||
|
||||
### Поддерживаемые разрешения
|
||||
|
||||
30
bin/cli.js
30
bin/cli.js
File diff suppressed because one or more lines are too long
10
package.json
10
package.json
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@grom13/dvc-cli",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.3",
|
||||
"description": "Fast DASH video converter with NVENC acceleration and thumbnail sprites",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"bin": {
|
||||
"dvc": "./bin/cli.js"
|
||||
"dvc-cli": "./bin/cli.js"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
@@ -44,12 +44,12 @@
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/grom13/dvc-cli.git"
|
||||
"url": "https://gromlab.ru/gromov/dvc-cli.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/grom13/dvc-cli/issues"
|
||||
"url": "https://gromlab.ru/gromov/dvc-cli/issues"
|
||||
},
|
||||
"homepage": "https://github.com/grom13/dvc-cli#readme",
|
||||
"homepage": "https://gromlab.ru/gromov/dvc-cli#readme",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
|
||||
55
src/cli.ts
55
src/cli.ts
@@ -4,59 +4,64 @@
|
||||
* DASH Video Converter CLI
|
||||
*
|
||||
* Usage:
|
||||
* dvc <input-video> [output-dir]
|
||||
* dvc-cli <input-video> [output-dir] [-r resolutions] [-p poster-timecode]
|
||||
*
|
||||
* Example:
|
||||
* dvc ./video.mp4 ./output
|
||||
* dvc-cli ./video.mp4 ./output -r 720,1080
|
||||
*/
|
||||
|
||||
import { convertToDash, checkFFmpeg, checkNvenc, checkMP4Box, getVideoMetadata } from './index';
|
||||
import cliProgress from 'cli-progress';
|
||||
import { statSync } from 'node:fs';
|
||||
|
||||
const input = process.argv[2];
|
||||
const outputDir = process.argv[3] || '.'; // Текущая директория по умолчанию
|
||||
|
||||
// Parse optional -r or --resolutions argument
|
||||
// Parse arguments
|
||||
const args = process.argv.slice(2);
|
||||
let customProfiles: string[] | undefined;
|
||||
let posterTimecode: string | undefined;
|
||||
const positionalArgs: string[] = [];
|
||||
|
||||
for (let i = 4; i < process.argv.length; i++) {
|
||||
if (process.argv[i] === '-r' || process.argv[i] === '--resolutions') {
|
||||
// First pass: extract flags and their values
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (args[i] === '-r' || args[i] === '--resolutions') {
|
||||
// Collect all arguments after -r until next flag or end
|
||||
const profilesArgs: string[] = [];
|
||||
for (let j = i + 1; j < process.argv.length; j++) {
|
||||
for (let j = i + 1; j < args.length; j++) {
|
||||
// Stop if we hit another flag (starts with -)
|
||||
if (process.argv[j].startsWith('-')) {
|
||||
if (args[j].startsWith('-')) {
|
||||
break;
|
||||
}
|
||||
profilesArgs.push(process.argv[j]);
|
||||
profilesArgs.push(args[j]);
|
||||
i = j; // Skip these args in main loop
|
||||
}
|
||||
|
||||
// If there's only one arg, it might contain commas: "720,1080"
|
||||
// If there are multiple args, they might be: "720" "1080" or "720," "1080"
|
||||
// Solution: join with comma, then split by comma/space
|
||||
// Parse profiles
|
||||
const joinedArgs = profilesArgs.join(',');
|
||||
customProfiles = joinedArgs
|
||||
.split(/[,\s]+/) // Split by comma or whitespace
|
||||
.map(s => s.trim())
|
||||
.filter(s => s.length > 0);
|
||||
} else if (args[i] === '-p' || args[i] === '--poster') {
|
||||
posterTimecode = args[i + 1];
|
||||
i++; // Skip next arg
|
||||
} else if (!args[i].startsWith('-')) {
|
||||
// Positional argument
|
||||
positionalArgs.push(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.argv[i] === '-p' || process.argv[i] === '--poster') {
|
||||
posterTimecode = process.argv[i + 1];
|
||||
}
|
||||
}
|
||||
// Extract positional arguments
|
||||
const input = positionalArgs[0];
|
||||
const outputDir = positionalArgs[1] || '.'; // Текущая директория по умолчанию
|
||||
|
||||
if (!input) {
|
||||
console.error('❌ Usage: dvc <input-video> [output-dir] [-r resolutions] [-p poster-timecode]');
|
||||
console.error('❌ Usage: dvc-cli <input-video> [output-dir] [-r resolutions] [-p poster-timecode]');
|
||||
console.error('\nExamples:');
|
||||
console.error(' dvc video.mp4');
|
||||
console.error(' dvc video.mp4 ./output');
|
||||
console.error(' dvc video.mp4 -r 360,480,720');
|
||||
console.error(' dvc video.mp4 -r 720@60,1080@60,2160@60');
|
||||
console.error(' dvc video.mp4 -p 00:00:05');
|
||||
console.error(' dvc video.mp4 ./output -r 720,1080 -p 10');
|
||||
console.error(' dvc-cli video.mp4');
|
||||
console.error(' dvc-cli video.mp4 ./output');
|
||||
console.error(' dvc-cli video.mp4 -r 360,480,720');
|
||||
console.error(' dvc-cli video.mp4 -r 720@60,1080@60,2160@60');
|
||||
console.error(' dvc-cli video.mp4 -p 00:00:05');
|
||||
console.error(' dvc-cli video.mp4 ./output -r 720,1080 -p 10');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { join } from 'node:path';
|
||||
import type { ThumbnailConfig } from '../types';
|
||||
import { execFFmpeg, formatVttTime } from '../utils';
|
||||
import { exists, readdir, unlink, rmdir } from 'node:fs/promises';
|
||||
import { execFFmpeg, formatVttTime, ensureDir } from '../utils';
|
||||
import { readdir, unlink, rmdir, writeFile } from 'node:fs/promises';
|
||||
|
||||
/**
|
||||
* Generate poster image from video at specific timecode
|
||||
@@ -45,7 +45,8 @@ export async function generateThumbnailSprite(
|
||||
|
||||
// Create temp directory for individual thumbnails
|
||||
const tempDir = join(outputDir, '.thumbnails_temp');
|
||||
await Bun.write(join(tempDir, '.keep'), '');
|
||||
await ensureDir(tempDir);
|
||||
await writeFile(join(tempDir, '.keep'), '');
|
||||
|
||||
// Generate individual thumbnails
|
||||
const thumbnailPattern = join(tempDir, 'thumb_%04d.jpg');
|
||||
@@ -95,7 +96,7 @@ export async function generateThumbnailSprite(
|
||||
'thumbnails.jpg'
|
||||
);
|
||||
|
||||
await Bun.write(vttPath, vttContent);
|
||||
await writeFile(vttPath, vttContent);
|
||||
|
||||
// Clean up temp files
|
||||
for (const file of thumbFiles) {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { mkdir, exists } from 'node:fs/promises';
|
||||
import { mkdir, access, constants } from 'node:fs/promises';
|
||||
|
||||
/**
|
||||
* Ensure directory exists
|
||||
*/
|
||||
export async function ensureDir(dirPath: string): Promise<void> {
|
||||
if (!await exists(dirPath)) {
|
||||
try {
|
||||
await access(dirPath, constants.F_OK);
|
||||
} catch {
|
||||
await mkdir(dirPath, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user