Skip to content

Conversation

@pixeru
Copy link

@pixeru pixeru commented Jul 24, 2025

Added -threads 0 for full CPU utilization, increased concurrency from 1 to dynamic CPU-based values for segment processing, and implemented throttled progress updates. Maintains lossless quality while significantly improving processing speed.

Summary by CodeRabbit

  • Performance Improvements

    • Enhanced FFmpeg operations with multi-threading, optimized command arguments, and improved memory management for faster processing.
    • Increased concurrency in file handling and segment processing, allowing more parallel operations for improved speed.
    • Throttled FFmpeg progress updates to reduce UI overhead and unnecessary updates.
    • Optimized error handling and logging to minimize performance impact.
  • New Features

    • Added adaptive quality selection and optimized codec presets for common video formats.
    • Introduced advanced batch and parallel processing utilities for efficient handling of multiple segments and files.

Added -threads 0 for full CPU utilization, increased concurrency from 1 to dynamic CPU-based values for segment processing, and implemented throttled progress updates. Maintains lossless quality while significantly improving processing speed.
@coderabbitai
Copy link

coderabbitai bot commented Jul 24, 2025

"""

Walkthrough

A new module introduces a suite of FFmpeg performance optimization utilities, focusing on argument tuning, concurrency, and memory management. Existing FFmpeg process and progress functions are enhanced with optimized arguments, throttled progress updates, and reduced memory overhead. The FFmpeg operations hook now increases concurrency for file and segment processing tasks.

Changes

File(s) Change Summary
FFmpeg optimization utilities
src/main/ffmpeg-optimizations.ts, src/main/ffmpeg-optimizations-fixed.ts
Added new files exporting multiple FFmpeg optimization utilities: argument tuning, batch/stream/segment processors, progress handlers, and quality detection.
FFmpeg core processing
src/main/ffmpeg.ts
Enhanced FFmpeg process and progress handling with optimized arguments, throttled progress updates, and memory improvements.
Renderer concurrency improvements
src/renderer/src/hooks/useFfmpegOperations.ts
Increased concurrency for file and segment operations by adjusting pMap concurrency based on hardware limits.

Sequence Diagram(s)

sequenceDiagram
    participant UI
    participant useFfmpegOperations
    participant ffmpeg-optimizations
    participant ffmpeg

    UI->>useFfmpegOperations: Request file/segment operation
    useFfmpegOperations->>ffmpeg-optimizations: Get optimized concurrency/config
    useFfmpegOperations->>ffmpeg: Run FFmpeg process with optimized args
    ffmpeg-->>useFfmpegOperations: Process result/progress
    useFfmpegOperations-->>UI: Report progress/result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Poem

In a warren of code, the rabbits convene,
To optimize FFmpeg—sleek, fast, and keen!
With threads and batches, they hop in delight,
Memory trimmed, concurrency just right.
Now video processing is snappy and bright—
A carrot for speed, and bugs out of sight!
🥕✨
"""

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (7)
src/renderer/src/hooks/useFfmpegOperations.ts (2)

75-80: Fix formatting issues

Remove trailing spaces to comply with code style guidelines.

 // Performance optimization: Improved file deletion with better concurrency
 async function tryDeleteFiles(paths: string[]) {
-  return pMap(paths, (path) => unlinkWithRetry(path).catch((err) => console.error('Failed to delete', path, err)), { 
-    concurrency: OPTIMIZED_CONCURRENCY 
-  });
+  return pMap(paths, (path) => unlinkWithRetry(path).catch((err) => console.error('Failed to delete', path, err)), {
+    concurrency: OPTIMIZED_CONCURRENCY,
+  });
 }

641-641: Consider resource constraints for parallel segment cutting

While increasing concurrency improves performance, cutting multiple segments simultaneously can be resource-intensive (CPU, memory, disk I/O). Consider monitoring system resources or implementing adaptive concurrency based on segment complexity.

src/main/ffmpeg.ts (4)

80-86: Good optimization for readline performance

Setting crlfDelay: Infinity and historySize: 0 reduces memory overhead. However, fix the formatting issues.

   // Performance optimization: Create readline interface with optimized settings
-  const rl = readline.createInterface({ 
+  const rl = readline.createInterface({
     input: process.stderr,
     // Optimize for performance
     crlfDelay: Infinity,
     historySize: 0, // Disable history to save memory
   });

88-107: Consider adjusting the progress throttle interval

While 50ms throttling reduces overhead, it might still be too frequent for UI updates. Consider increasing to 100-200ms for better performance without sacrificing user experience. Also fix formatting issues.

   // Throttle progress updates to reduce UI overhead
   let lastProgressTime = 0;
-  const progressThrottle = 50; // Update progress max every 50ms
+  const progressThrottle = 100; // Update progress max every 100ms
   let lastProgress = 0;

   rl.on('line', (line) => {
     // console.log('progress', line);

     try {
       const now = Date.now();
-      
+
       // Skip processing if too frequent (performance optimization)
       if (now - lastProgressTime < progressThrottle) return;

       const progress = parseFfmpegProgressLine({ line, customMatcher, duration });
       if (progress != null && Math.abs(progress - lastProgress) > 0.001) { // Only update if progress changed significantly
         onProgress(progress);
         lastProgressTime = now;
         lastProgress = progress;
       }

142-149: Excellent FFmpeg performance arguments

The added arguments effectively optimize FFmpeg:

  • -threads 0: Uses all available CPU cores
  • -fflags +discardcorrupt+genpts: Improves error handling and timestamp generation
  • -avioflags direct: Reduces I/O buffering overhead

Fix the formatting issue:

   const optimizedArgs = [
     '-threads', '0', // Use all available CPU cores
     '-fflags', '+discardcorrupt+genpts', // Improve error handling and timestamp generation
     '-avioflags', 'direct', // Reduce I/O overhead
-    ...args
+    ...args,
   ];

151-163: Good process optimization options

The execa options improve process management:

  • windowsHide: Prevents console window on Windows
  • cleanup: Ensures proper resource cleanup
  • maxBuffer: 64MB is reasonable for video processing

Fix formatting:

   const abortController = new AbortController();
-  
+
   // Optimize process creation options
   const optimizedExecaOptions = {
-    ...getExecaOptions({ 
-      ...customExecaOptions, 
+    ...getExecaOptions({
+      ...customExecaOptions,
       cancelSignal: abortController.signal,
       // Performance optimizations
       windowsHide: true,
       cleanup: true,
       maxBuffer: 1024 * 1024 * 64, // 64MB buffer
     }),
   };
src/main/ffmpeg-optimizations.ts (1)

125-151: Good stream processing configuration

The function provides sensible defaults for memory-efficient stream processing. Just fix the type assertion:

     execaOptions: {
       buffer: false,
       stdio: ['pipe', 'pipe', 'pipe'],
       maxBuffer: bufferSize,
-      encoding: 'buffer' as const,
+      encoding: 'buffer' as 'buffer',
       // Optimize child process creation
       windowsHide: true,
       // Reduce memory overhead
       cleanup: true,
       all: false,
     } as ExecaOptions,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2507240 and 1593903.

📒 Files selected for processing (3)
  • src/main/ffmpeg-optimizations.ts (1 hunks)
  • src/main/ffmpeg.ts (3 hunks)
  • src/renderer/src/hooks/useFfmpegOperations.ts (6 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/renderer/src/hooks/useFfmpegOperations.ts (2)
src/renderer/src/util.ts (1)
  • unlinkWithRetry (131-131)
src/main/ffmpeg.ts (1)
  • getDuration (575-577)
src/main/ffmpeg.ts (2)
src/main/progress.ts (1)
  • parseFfmpegProgressLine (2-46)
src/renderer/src/ffmpeg.ts (2)
  • getFfmpegPath (20-20)
  • getFfCommandLine (20-20)
🪛 ESLint
src/renderer/src/hooks/useFfmpegOperations.ts

[error] 17-17: 'optimizeFFmpegArgs' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 17-17: 'createOptimizedBatchProcessor' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 17-17: 'getOptimizedCodecArgs' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 26-26: 'SEGMENT_BATCH_SIZE' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)


[error] 77-77: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 78-78: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 78-78: Missing trailing comma.

(comma-dangle)

src/main/ffmpeg.ts

[error] 81-81: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 98-98: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 147-148: Missing trailing comma.

(comma-dangle)


[error] 151-151: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 154-154: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 155-155: Trailing spaces not allowed.

(no-trailing-spaces)

src/main/ffmpeg-optimizations.ts

[error] 1-1: Filename is not in camel case or pascal case. Rename it to ffmpegOptimizations.ts or FfmpegOptimizations.ts.

(unicorn/filename-case)


[error] 4-4: 'execa' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 37-37: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 38-38: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 50-50: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 53-53: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 64-64: Missing radix parameter.

(radix)


[error] 64-64: Missing radix parameter.

(radix)


[error] 66-66: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 67-67: Unexpected use of 'isNaN'. Use Number.isNaN instead https://github.com/airbnb/javascript#standard-library--isnan

(no-restricted-globals)


[error] 72-72: Remove unused catch binding err.

(unicorn/prefer-optional-catch-binding)


[error] 81-81: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 86-87: Missing trailing comma.

(comma-dangle)


[error] 89-89: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 91-91: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 93-93: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 97-97: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 99-108: Function declared in a loop contains unsafe references to variable(s) 'completed', 'completed', 'completed'.

(no-loop-func)


[error] 99-99: 'index' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 101-101: Unary operator '++' used.

(no-plusplus)


[error] 102-102: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 106-106: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 109-109: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 113-113: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 120-120: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 131-131: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 144-144: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 148-149: Missing trailing comma.

(comma-dangle)


[error] 155-155: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 164-164: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 169-169: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 176-180: Unnecessarily quoted property 'libx264' found.

(quote-props)


[error] 179-180: Missing trailing comma.

(comma-dangle)


[error] 181-185: Unnecessarily quoted property 'libx265' found.

(quote-props)


[error] 184-185: Missing trailing comma.

(comma-dangle)


[error] 186-190: Unnecessarily quoted property 'copy' found.

(quote-props)


[error] 189-190: Missing trailing comma.

(comma-dangle)


[error] 190-191: Missing trailing comma.

(comma-dangle)


[error] 192-192: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 197-197: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 199-199: Expected parentheses around arrow function argument.

(arrow-parens)


[error] 200-200: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 202-202: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 204-204: Missing radix parameter.

(radix)


[error] 205-205: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 210-210: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 215-215: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 221-221: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 226-226: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 227-227: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 227-227: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 228-228: Do not use new Array().

(unicorn/no-new-array)


[error] 230-230: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 231-231: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 234-234: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 235-235: Unary operator '++' used.

(no-plusplus)


[error] 237-237: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 244-244: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 250-250: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 253-253: Trailing spaces not allowed.

(no-trailing-spaces)

🔇 Additional comments (2)
src/renderer/src/hooks/useFfmpegOperations.ts (2)

143-143: Good optimization for parallel duration fetching

Using dynamic concurrency based on hardware capabilities instead of a fixed value improves performance scalability.


914-914: Effective optimization for stream extraction

Parallel stream extraction is a good optimization as these operations are typically I/O bound rather than CPU bound.

Also applies to: 950-950

@@ -0,0 +1,267 @@
// Performance optimizations for LosslessCut FFmpeg operations
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix filename to match project conventions

The filename should follow the project's naming convention.

Rename the file from ffmpeg-optimizations.ts to ffmpegOptimizations.ts to match the camelCase convention used in the project.

🧰 Tools
🪛 ESLint

[error] 1-1: Filename is not in camel case or pascal case. Rename it to ffmpegOptimizations.ts or FfmpegOptimizations.ts.

(unicorn/filename-case)

🤖 Prompt for AI Agents
In src/main/ffmpeg-optimizations.ts at line 1, the filename does not follow the
project's camelCase naming convention. Rename the file from
ffmpeg-optimizations.ts to ffmpegOptimizations.ts to align with the project's
standard.

// Performance optimizations for LosslessCut FFmpeg operations
// This file contains optimized versions of key functions to improve processing speed

import { execa, ExecaOptions } from 'execa';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove unused import

The execa import is not used in this file.

-import { execa, ExecaOptions } from 'execa';
+import { ExecaOptions } from 'execa';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { execa, ExecaOptions } from 'execa';
import { ExecaOptions } from 'execa';
🧰 Tools
🪛 ESLint

[error] 4-4: 'execa' is defined but never used.

(@typescript-eslint/no-unused-vars)

🤖 Prompt for AI Agents
In src/main/ffmpeg-optimizations.ts at line 4, remove the unused import of
`execa` while keeping the import of `ExecaOptions` since only `execa` is unused.
This cleans up the code by eliminating unnecessary imports.

Comment on lines 27 to 77
// Optimization 2: Improved progress handling with better performance
export function optimizedHandleProgress(
process: { stderr: Readable | null },
duration: number | undefined,
onProgress: (progress: number) => void,
customMatcher?: (line: string) => void,
) {
if (!onProgress || !process.stderr) return;

onProgress(0);

const rl = readline.createInterface({
input: process.stderr,
// Optimize readline performance
crlfDelay: Infinity,
historySize: 0, // Disable history to save memory
});

let lastProgressTime = 0;
const progressThrottle = 100; // Update progress max every 100ms

rl.on('line', (line) => {
const now = Date.now();

// Throttle progress updates to reduce UI overhead
if (now - lastProgressTime < progressThrottle) return;

try {
if (customMatcher) {
customMatcher(line);
return;
}

// Optimized regex for faster parsing
const timeMatch = line.match(/time=(\d{2}):(\d{2}):(\d{2}\.\d{2})/);
if (timeMatch && duration) {
const [, hours, minutes, seconds] = timeMatch;
const currentTime = parseInt(hours) * 3600 + parseInt(minutes) * 60 + parseFloat(seconds);
const progress = Math.min(currentTime / duration, 1);

if (!isNaN(progress)) {
onProgress(progress);
lastProgressTime = now;
}
}
} catch (err) {
// Silently ignore parsing errors to avoid performance impact
}
});
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use existing progress parsing function

This function duplicates the progress handling logic from ffmpeg.ts but with a less robust parsing implementation. Consider using the existing parseFfmpegProgressLine function from progress.ts instead of reimplementing the parsing logic.

+import { parseFfmpegProgressLine } from './progress.js';
+
 export function optimizedHandleProgress(
   process: { stderr: Readable | null },
   duration: number | undefined,
   onProgress: (progress: number) => void,
   customMatcher?: (line: string) => void,
 ) {
   if (!onProgress || !process.stderr) return;

   onProgress(0);
-  
+
   const rl = readline.createInterface({
     input: process.stderr,
     // Optimize readline performance
     crlfDelay: Infinity,
     historySize: 0, // Disable history to save memory
   });

   let lastProgressTime = 0;
   const progressThrottle = 100; // Update progress max every 100ms
+  let lastProgress = 0;

   rl.on('line', (line) => {
     const now = Date.now();
-    
+
     // Throttle progress updates to reduce UI overhead
     if (now - lastProgressTime < progressThrottle) return;
-    
+
     try {
-      if (customMatcher) {
-        customMatcher(line);
-        return;
-      }
-
-      // Optimized regex for faster parsing
-      const timeMatch = line.match(/time=(\d{2}):(\d{2}):(\d{2}\.\d{2})/);
-      if (timeMatch && duration) {
-        const [, hours, minutes, seconds] = timeMatch;
-        const currentTime = parseInt(hours) * 3600 + parseInt(minutes) * 60 + parseFloat(seconds);
-        const progress = Math.min(currentTime / duration, 1);
-        
-        if (!isNaN(progress)) {
-          onProgress(progress);
-          lastProgressTime = now;
-        }
+      const progress = parseFfmpegProgressLine({ line, customMatcher, duration });
+      if (progress != null && Math.abs(progress - lastProgress) > 0.001) {
+        onProgress(progress);
+        lastProgressTime = now;
+        lastProgress = progress;
       }
-    } catch (err) {
-      // Silently ignore parsing errors to avoid performance impact
+    } catch {
+      // Silently ignore parsing errors
     }
   });
 }
🧰 Tools
🪛 ESLint

[error] 37-37: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 38-38: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 50-50: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 53-53: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 64-64: Missing radix parameter.

(radix)


[error] 64-64: Missing radix parameter.

(radix)


[error] 66-66: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 67-67: Unexpected use of 'isNaN'. Use Number.isNaN instead https://github.com/airbnb/javascript#standard-library--isnan

(no-restricted-globals)


[error] 72-72: Remove unused catch binding err.

(unicorn/prefer-optional-catch-binding)

🤖 Prompt for AI Agents
In src/main/ffmpeg-optimizations.ts between lines 27 and 77, the
optimizedHandleProgress function duplicates progress parsing logic that exists
in progress.ts as parseFfmpegProgressLine. To fix this, import
parseFfmpegProgressLine from progress.ts and replace the manual regex parsing
inside the 'line' event handler with a call to parseFfmpegProgressLine. Use its
output to calculate progress and call onProgress accordingly, ensuring the
function leverages the more robust existing parser.

Comment on lines 78 to 124
// Optimization 3: Batch processing optimization
export function createOptimizedBatchProcessor<T>(
items: T[],
processor: (item: T) => Promise<any>,
options: {
concurrency?: number;
batchSize?: number;
progressCallback?: (completed: number, total: number) => void;
} = {}
) {
const { concurrency = 4, batchSize = 10, progressCallback } = options;

return async function processBatch() {
const results: any[] = [];
let completed = 0;

// Process in optimized batches
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);

// Process batch items with controlled concurrency
const batchPromises = batch.map(async (item, index) => {
const result = await processor(item);
completed++;

if (progressCallback && completed % Math.max(1, Math.floor(items.length / 100)) === 0) {
progressCallback(completed, items.length);
}

return result;
});

// Process with limited concurrency to avoid overwhelming the system
const batchResults = await Promise.all(batchPromises.slice(0, concurrency));
results.push(...batchResults);

// Process remaining items in the batch
if (batchPromises.length > concurrency) {
const remainingResults = await Promise.all(batchPromises.slice(concurrency));
results.push(...remainingResults);
}
}

return results;
};
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix batch processor implementation

The current implementation has several issues:

  1. It processes batches sequentially, not concurrently
  2. The Promise.all usage doesn't respect the concurrency limit
  3. Uses any types instead of generics properly
  4. The async map function captures variables unsafely

Consider using an existing library like p-map which is already used in the codebase and handles concurrency correctly:

import pMap from 'p-map';

export async function createOptimizedBatchProcessor<T, R>(
  items: T[],
  processor: (item: T) => Promise<R>,
  options: {
    concurrency?: number;
    progressCallback?: (completed: number, total: number) => void;
  } = {}
): Promise<R[]> {
  const { concurrency = 4, progressCallback } = options;
  let completed = 0;
  
  return pMap(items, async (item) => {
    const result = await processor(item);
    completed++;
    
    if (progressCallback && completed % Math.max(1, Math.floor(items.length / 100)) === 0) {
      progressCallback(completed, items.length);
    }
    
    return result;
  }, { concurrency });
}
🧰 Tools
🪛 ESLint

[error] 81-81: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 86-87: Missing trailing comma.

(comma-dangle)


[error] 89-89: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 91-91: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 93-93: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 97-97: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 99-108: Function declared in a loop contains unsafe references to variable(s) 'completed', 'completed', 'completed'.

(no-loop-func)


[error] 99-99: 'index' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 101-101: Unary operator '++' used.

(no-plusplus)


[error] 102-102: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 106-106: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 109-109: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 113-113: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 120-120: Trailing spaces not allowed.

(no-trailing-spaces)

🤖 Prompt for AI Agents
In src/main/ffmpeg-optimizations.ts around lines 78 to 124, the batch processor
implementation incorrectly processes batches sequentially and does not properly
enforce concurrency limits with Promise.all, also it uses any types instead of
generics and has unsafe async map usage. Replace the entire function with a
version that uses the existing p-map library to handle concurrency correctly,
remove batchSize since p-map manages concurrency, use proper generics for input
and output types, track progress safely inside the p-map iterator, and return
the final results as a Promise of the generic output array.

Comment on lines +152 to +172
// Optimization 5: Improved seeking performance
export function getOptimizedSeekArgs(from?: number, to?: number): string[] {
const args: string[] = [];

if (from != null) {
// Use precise seeking for better performance
args.push('-ss', from.toFixed(6));
// Enable fast seeking when possible
if (from > 1) {
args.push('-accurate_seek');
}
}

if (to != null && from != null) {
const duration = to - from;
args.push('-t', duration.toFixed(6));
}

return args;
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Questionable seeking logic

The -accurate_seek flag is added for seeks > 1 second, but accurate seeking is typically more important for small, precise seeks. For large seeks, keyframe seeking is usually sufficient and faster.

Consider inverting the logic or removing the conditional:

 export function getOptimizedSeekArgs(from?: number, to?: number): string[] {
   const args: string[] = [];
   
   if (from != null) {
     // Use precise seeking for better performance
     args.push('-ss', from.toFixed(6));
-    // Enable fast seeking when possible
-    if (from > 1) {
-      args.push('-accurate_seek');
-    }
   }
   
   if (to != null && from != null) {
     const duration = to - from;
     args.push('-t', duration.toFixed(6));
   }
   
   return args;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Optimization 5: Improved seeking performance
export function getOptimizedSeekArgs(from?: number, to?: number): string[] {
const args: string[] = [];
if (from != null) {
// Use precise seeking for better performance
args.push('-ss', from.toFixed(6));
// Enable fast seeking when possible
if (from > 1) {
args.push('-accurate_seek');
}
}
if (to != null && from != null) {
const duration = to - from;
args.push('-t', duration.toFixed(6));
}
return args;
}
export function getOptimizedSeekArgs(from?: number, to?: number): string[] {
const args: string[] = [];
if (from != null) {
// Use precise seeking for better performance
args.push('-ss', from.toFixed(6));
}
if (to != null && from != null) {
const duration = to - from;
args.push('-t', duration.toFixed(6));
}
return args;
}
🧰 Tools
🪛 ESLint

[error] 155-155: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 164-164: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 169-169: Trailing spaces not allowed.

(no-trailing-spaces)

🤖 Prompt for AI Agents
In src/main/ffmpeg-optimizations.ts between lines 152 and 172, the current logic
adds the '-accurate_seek' flag only when the seek start time is greater than 1
second, which is counterproductive since accurate seeking is more beneficial for
small, precise seeks. To fix this, invert the condition to add '-accurate_seek'
when the seek start time is less than or equal to 1 second, or consider removing
the conditional entirely to always include '-accurate_seek' for precise seeking.

Comment on lines 173 to 218
// Optimization 6: Codec-specific optimizations
export function getOptimizedCodecArgs(codec: string, quality: 'fast' | 'balanced' | 'quality' = 'balanced'): string[] {
const presets = {
'libx264': {
fast: ['-preset', 'ultrafast', '-tune', 'zerolatency'],
balanced: ['-preset', 'medium', '-crf', '23'],
quality: ['-preset', 'slow', '-crf', '18']
},
'libx265': {
fast: ['-preset', 'ultrafast', '-x265-params', 'log-level=error'],
balanced: ['-preset', 'medium', '-crf', '28'],
quality: ['-preset', 'slow', '-crf', '24']
},
'copy': {
fast: ['-c', 'copy'],
balanced: ['-c', 'copy'],
quality: ['-c', 'copy']
}
};

return presets[codec as keyof typeof presets]?.[quality] || ['-c', 'copy'];
}

// Optimization 7: Smart quality detection
export function detectOptimalQuality(inputFile: string, streams: any[]): 'fast' | 'balanced' | 'quality' {
// Analyze file characteristics to determine optimal quality setting
const videoStream = streams.find(s => s.codec_type === 'video');

if (!videoStream) return 'fast';

const resolution = (videoStream.width || 0) * (videoStream.height || 0);
const bitrate = parseInt(videoStream.bit_rate) || 0;

// HD+ content with high bitrate - use quality mode
if (resolution >= 1920 * 1080 && bitrate > 5000000) {
return 'quality';
}

// Standard definition or lower bitrate - use fast mode
if (resolution <= 720 * 480 || bitrate < 1000000) {
return 'fast';
}

// Default to balanced
return 'balanced';
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve type safety and fix parsing issues

  1. Add proper types instead of any
  2. Fix parseInt calls to include radix parameter
  3. Remove unnecessary quotes from object keys
+import { FFprobeStream } from '../../../../ffprobe';
+
 export function getOptimizedCodecArgs(codec: string, quality: 'fast' | 'balanced' | 'quality' = 'balanced'): string[] {
   const presets = {
-    'libx264': {
+    libx264: {
       fast: ['-preset', 'ultrafast', '-tune', 'zerolatency'],
       balanced: ['-preset', 'medium', '-crf', '23'],
-      quality: ['-preset', 'slow', '-crf', '18']
+      quality: ['-preset', 'slow', '-crf', '18'],
     },
-    'libx265': {
+    libx265: {
       fast: ['-preset', 'ultrafast', '-x265-params', 'log-level=error'],
       balanced: ['-preset', 'medium', '-crf', '28'],
-      quality: ['-preset', 'slow', '-crf', '24']
+      quality: ['-preset', 'slow', '-crf', '24'],
     },
-    'copy': {
+    copy: {
       fast: ['-c', 'copy'],
       balanced: ['-c', 'copy'],
-      quality: ['-c', 'copy']
-    }
+      quality: ['-c', 'copy'],
+    },
   };
   
   return presets[codec as keyof typeof presets]?.[quality] || ['-c', 'copy'];
 }

 // Optimization 7: Smart quality detection
-export function detectOptimalQuality(inputFile: string, streams: any[]): 'fast' | 'balanced' | 'quality' {
+export function detectOptimalQuality(inputFile: string, streams: FFprobeStream[]): 'fast' | 'balanced' | 'quality' {
   // Analyze file characteristics to determine optimal quality setting
   const videoStream = streams.find(s => s.codec_type === 'video');
   
   if (!videoStream) return 'fast';
   
   const resolution = (videoStream.width || 0) * (videoStream.height || 0);
-  const bitrate = parseInt(videoStream.bit_rate) || 0;
+  const bitrate = parseInt(videoStream.bit_rate || '0', 10) || 0;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Optimization 6: Codec-specific optimizations
export function getOptimizedCodecArgs(codec: string, quality: 'fast' | 'balanced' | 'quality' = 'balanced'): string[] {
const presets = {
'libx264': {
fast: ['-preset', 'ultrafast', '-tune', 'zerolatency'],
balanced: ['-preset', 'medium', '-crf', '23'],
quality: ['-preset', 'slow', '-crf', '18']
},
'libx265': {
fast: ['-preset', 'ultrafast', '-x265-params', 'log-level=error'],
balanced: ['-preset', 'medium', '-crf', '28'],
quality: ['-preset', 'slow', '-crf', '24']
},
'copy': {
fast: ['-c', 'copy'],
balanced: ['-c', 'copy'],
quality: ['-c', 'copy']
}
};
return presets[codec as keyof typeof presets]?.[quality] || ['-c', 'copy'];
}
// Optimization 7: Smart quality detection
export function detectOptimalQuality(inputFile: string, streams: any[]): 'fast' | 'balanced' | 'quality' {
// Analyze file characteristics to determine optimal quality setting
const videoStream = streams.find(s => s.codec_type === 'video');
if (!videoStream) return 'fast';
const resolution = (videoStream.width || 0) * (videoStream.height || 0);
const bitrate = parseInt(videoStream.bit_rate) || 0;
// HD+ content with high bitrate - use quality mode
if (resolution >= 1920 * 1080 && bitrate > 5000000) {
return 'quality';
}
// Standard definition or lower bitrate - use fast mode
if (resolution <= 720 * 480 || bitrate < 1000000) {
return 'fast';
}
// Default to balanced
return 'balanced';
}
import { FFprobeStream } from '../../../../ffprobe';
// Optimization 6: Codec-specific optimizations
export function getOptimizedCodecArgs(
codec: string,
quality: 'fast' | 'balanced' | 'quality' = 'balanced'
): string[] {
const presets = {
libx264: {
fast: ['-preset', 'ultrafast', '-tune', 'zerolatency'],
balanced: ['-preset', 'medium', '-crf', '23'],
quality: ['-preset', 'slow', '-crf', '18'],
},
libx265: {
fast: ['-preset', 'ultrafast', '-x265-params', 'log-level=error'],
balanced: ['-preset', 'medium', '-crf', '28'],
quality: ['-preset', 'slow', '-crf', '24'],
},
copy: {
fast: ['-c', 'copy'],
balanced: ['-c', 'copy'],
quality: ['-c', 'copy'],
},
};
return presets[codec as keyof typeof presets]?.[quality] || ['-c', 'copy'];
}
// Optimization 7: Smart quality detection
export function detectOptimalQuality(
inputFile: string,
streams: FFprobeStream[]
): 'fast' | 'balanced' | 'quality' {
// Analyze file characteristics to determine optimal quality setting
const videoStream = streams.find(s => s.codec_type === 'video');
if (!videoStream) return 'fast';
const resolution = (videoStream.width || 0) * (videoStream.height || 0);
const bitrate = parseInt(videoStream.bit_rate || '0', 10) || 0;
// HD+ content with high bitrate - use quality mode
if (resolution >= 1920 * 1080 && bitrate > 5_000_000) {
return 'quality';
}
// Standard definition or lower bitrate - use fast mode
if (resolution <= 720 * 480 || bitrate < 1_000_000) {
return 'fast';
}
// Default to balanced
return 'balanced';
}
🧰 Tools
🪛 ESLint

[error] 176-180: Unnecessarily quoted property 'libx264' found.

(quote-props)


[error] 179-180: Missing trailing comma.

(comma-dangle)


[error] 181-185: Unnecessarily quoted property 'libx265' found.

(quote-props)


[error] 184-185: Missing trailing comma.

(comma-dangle)


[error] 186-190: Unnecessarily quoted property 'copy' found.

(quote-props)


[error] 189-190: Missing trailing comma.

(comma-dangle)


[error] 190-191: Missing trailing comma.

(comma-dangle)


[error] 192-192: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 197-197: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 199-199: Expected parentheses around arrow function argument.

(arrow-parens)


[error] 200-200: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 202-202: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 204-204: Missing radix parameter.

(radix)


[error] 205-205: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 210-210: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 215-215: Trailing spaces not allowed.

(no-trailing-spaces)

🤖 Prompt for AI Agents
In src/main/ffmpeg-optimizations.ts around lines 173 to 218, improve type safety
by replacing the use of 'any' for the streams parameter with a proper interface
or type describing the expected stream object structure. Fix the parseInt call
by adding the radix parameter 10 to ensure correct parsing of bit_rate. Also,
remove unnecessary quotes from object keys in the presets object since they are
valid identifiers and do not require quotes.

Comment on lines +220 to +257
// Optimization 8: Parallel processing for multiple segments
export function createParallelSegmentProcessor(segments: any[], options: {
maxConcurrency?: number;
resourceLimit?: number;
} = {}) {
const { maxConcurrency = 2, resourceLimit = 4 } = options;

return async function processSegments(processor: (segment: any, index: number) => Promise<any>) {
const semaphore = new Array(Math.min(maxConcurrency, resourceLimit)).fill(null);
let segmentIndex = 0;
const results: any[] = [];

const processNext = async () => {
if (segmentIndex >= segments.length) return;

const currentIndex = segmentIndex++;
const segment = segments[currentIndex];

try {
const result = await processor(segment, currentIndex);
results[currentIndex] = result;
} catch (error) {
results[currentIndex] = { error };
}

// Continue processing if there are more segments
if (segmentIndex < segments.length) {
await processNext();
}
};

// Start parallel processing
await Promise.all(semaphore.map(() => processNext()));

return results;
};
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify parallel processing implementation

The current implementation is overly complex and doesn't properly control concurrency. Since the project already uses p-map, leverage it for simpler and more reliable parallel processing.

+import pMap from 'p-map';
+
-export function createParallelSegmentProcessor(segments: any[], options: {
+export async function processSegmentsInParallel<T, R>(
+  segments: T[],
+  processor: (segment: T, index: number) => Promise<R>,
+  options: {
   maxConcurrency?: number;
-  resourceLimit?: number;
-} = {}) {
-  const { maxConcurrency = 2, resourceLimit = 4 } = options;
+  } = {}
+): Promise<R[]> {
+  const { maxConcurrency = 2 } = options;
   
-  return async function processSegments(processor: (segment: any, index: number) => Promise<any>) {
-    const semaphore = new Array(Math.min(maxConcurrency, resourceLimit)).fill(null);
-    let segmentIndex = 0;
-    const results: any[] = [];
-    
-    const processNext = async () => {
-      if (segmentIndex >= segments.length) return;
-      
-      const currentIndex = segmentIndex++;
-      const segment = segments[currentIndex];
-      
-      try {
-        const result = await processor(segment, currentIndex);
-        results[currentIndex] = result;
-      } catch (error) {
-        results[currentIndex] = { error };
-      }
-      
-      // Continue processing if there are more segments
-      if (segmentIndex < segments.length) {
-        await processNext();
-      }
-    };
-    
-    // Start parallel processing
-    await Promise.all(semaphore.map(() => processNext()));
-    
-    return results;
-  };
+  return pMap(
+    segments,
+    async (segment, index) => processor(segment, index),
+    { concurrency: maxConcurrency }
+  );
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Optimization 8: Parallel processing for multiple segments
export function createParallelSegmentProcessor(segments: any[], options: {
maxConcurrency?: number;
resourceLimit?: number;
} = {}) {
const { maxConcurrency = 2, resourceLimit = 4 } = options;
return async function processSegments(processor: (segment: any, index: number) => Promise<any>) {
const semaphore = new Array(Math.min(maxConcurrency, resourceLimit)).fill(null);
let segmentIndex = 0;
const results: any[] = [];
const processNext = async () => {
if (segmentIndex >= segments.length) return;
const currentIndex = segmentIndex++;
const segment = segments[currentIndex];
try {
const result = await processor(segment, currentIndex);
results[currentIndex] = result;
} catch (error) {
results[currentIndex] = { error };
}
// Continue processing if there are more segments
if (segmentIndex < segments.length) {
await processNext();
}
};
// Start parallel processing
await Promise.all(semaphore.map(() => processNext()));
return results;
};
}
import pMap from 'p-map';
// Optimization 8: Parallel processing for multiple segments
export async function processSegmentsInParallel<T, R>(
segments: T[],
processor: (segment: T, index: number) => Promise<R>,
options: {
maxConcurrency?: number;
} = {}
): Promise<R[]> {
const { maxConcurrency = 2 } = options;
return pMap(
segments,
async (segment, index) => processor(segment, index),
{ concurrency: maxConcurrency }
);
}
🧰 Tools
🪛 ESLint

[error] 221-221: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 226-226: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 227-227: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 227-227: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 228-228: Do not use new Array().

(unicorn/no-new-array)


[error] 230-230: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 231-231: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 234-234: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 235-235: Unary operator '++' used.

(no-plusplus)


[error] 237-237: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 244-244: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 250-250: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 253-253: Trailing spaces not allowed.

(no-trailing-spaces)

🤖 Prompt for AI Agents
In src/main/ffmpeg-optimizations.ts between lines 220 and 257, the current
parallel segment processing function manually manages concurrency with a
semaphore array and recursive calls, which is complex and error-prone. Replace
this implementation by using the existing p-map library to handle concurrency
control more simply and reliably. Refactor the function to call p-map on the
segments array with the processor function and set concurrency to
maxConcurrency, removing manual semaphore and recursion logic.

- Remove unused execa import and ExecaOptions type reference
- Simplify optimizedHandleProgress function to avoid dependency issues
- Fix unused parameter 'index' in batch processor map function
- Mark unused 'inputFile' parameter with underscore prefix
- Remove unused import of optimization functions from useFfmpegOperations
- Remove unused SEGMENT_BATCH_SIZE constant

Fixes GitHub Actions build failure on ubuntu-latest due to:
- TS6133: unused variable declarations
- TS2305: missing module exports
- TS2345: type assignment issues
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🔭 Outside diff range comments (1)
src/main/ffmpeg-optimizations.ts (1)

1-228: Remove duplicate FFmpeg optimizations file

Both src/main/ffmpeg-optimizations.ts and src/main/ffmpeg-optimizations-fixed.ts have identical content (MD5: 6920ea257e0746ba7707be7fb2f4894a). Keeping both violates DRY and causes confusion.

• Decide which file to keep:

  • src/main/ffmpeg-optimizations.ts
  • src/main/ffmpeg-optimizations-fixed.ts
    • Delete the other file.
    • Update any imports (e.g., in useFfmpegOperations.ts) to reference the remaining file.

Please confirm which filename should remain.

♻️ Duplicate comments (1)
src/main/ffmpeg-optimizations-fixed.ts (1)

1-1: Fix filename to match project conventions.

Rename the file from ffmpeg-optimizations-fixed.ts to ffmpegOptimizationsFixed.ts to match the camelCase convention used in the project.

🧹 Nitpick comments (3)
src/renderer/src/hooks/useFfmpegOperations.ts (1)

70-74: Fix trailing spaces.

The concurrency optimization is good, but there are formatting issues.

 async function tryDeleteFiles(paths: string[]) {
-  return pMap(paths, (path) => unlinkWithRetry(path).catch((err) => console.error('Failed to delete', path, err)), { 
-    concurrency: OPTIMIZED_CONCURRENCY 
+  return pMap(paths, (path) => unlinkWithRetry(path).catch((err) => console.error('Failed to delete', path, err)), {
+    concurrency: OPTIMIZED_CONCURRENCY,
   });
 }
src/main/ffmpeg-optimizations-fixed.ts (2)

86-110: Add missing trailing comma.

The function logic is good for memory-efficient processing.

     streamOptions: {
       highWaterMark,
       objectMode: false,
-    }
+    },
   };
 }

134-154: Fix formatting issues.

Remove unnecessary quotes and add trailing commas.

 export function getOptimizedCodecArgs(codec: string, quality: 'fast' | 'balanced' | 'quality' = 'balanced'): string[] {
   const presets = {
-    'libx264': {
+    libx264: {
       fast: ['-preset', 'ultrafast', '-tune', 'zerolatency'],
       balanced: ['-preset', 'medium', '-crf', '23'],
-      quality: ['-preset', 'slow', '-crf', '18']
+      quality: ['-preset', 'slow', '-crf', '18'],
     },
-    'libx265': {
+    libx265: {
       fast: ['-preset', 'ultrafast', '-x265-params', 'log-level=error'],
       balanced: ['-preset', 'medium', '-crf', '28'],
-      quality: ['-preset', 'slow', '-crf', '24']
+      quality: ['-preset', 'slow', '-crf', '24'],
     },
-    'copy': {
+    copy: {
       fast: ['-c', 'copy'],
       balanced: ['-c', 'copy'],
-      quality: ['-c', 'copy']
-    }
+      quality: ['-c', 'copy'],
+    },
   };
   
   return presets[codec as keyof typeof presets]?.[quality] || ['-c', 'copy'];
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1593903 and 679d527.

📒 Files selected for processing (3)
  • src/main/ffmpeg-optimizations-fixed.ts (1 hunks)
  • src/main/ffmpeg-optimizations.ts (1 hunks)
  • src/renderer/src/hooks/useFfmpegOperations.ts (6 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/main/ffmpeg-optimizations-fixed.ts (1)
src/main/ffmpeg-optimizations.ts (8)
  • optimizeFFmpegArgs (5-21)
  • optimizedHandleProgress (24-36)
  • createOptimizedBatchProcessor (39-83)
  • createOptimizedStreamProcessor (86-110)
  • getOptimizedSeekArgs (113-131)
  • getOptimizedCodecArgs (134-154)
  • detectOptimalQuality (157-178)
  • createParallelSegmentProcessor (181-216)
src/renderer/src/hooks/useFfmpegOperations.ts (3)
src/renderer/src/util.ts (1)
  • unlinkWithRetry (131-131)
src/main/ffmpeg.ts (1)
  • getDuration (575-577)
src/renderer/src/ffmpeg.ts (1)
  • getDuration (20-20)
🪛 ESLint
src/main/ffmpeg-optimizations-fixed.ts

[error] 1-1: Filename is not in camel case or pascal case. Rename it to ffmpegOptimizationsFixed.ts or FfmpegOptimizationsFixed.ts.

(unicorn/filename-case)


[error] 25-25: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 28-28: 'customMatcher' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 33-33: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 41-41: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 46-47: Missing trailing comma.

(comma-dangle)


[error] 49-49: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 51-51: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 53-53: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 57-57: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 59-68: Function declared in a loop contains unsafe references to variable(s) 'completed', 'completed', 'completed'.

(no-loop-func)


[error] 61-61: Unary operator '++' used.

(no-plusplus)


[error] 62-62: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 66-66: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 69-69: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 73-73: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 80-80: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 91-91: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 104-104: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 108-109: Missing trailing comma.

(comma-dangle)


[error] 115-115: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 124-124: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 129-129: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 136-140: Unnecessarily quoted property 'libx264' found.

(quote-props)


[error] 139-140: Missing trailing comma.

(comma-dangle)


[error] 141-145: Unnecessarily quoted property 'libx265' found.

(quote-props)


[error] 144-145: Missing trailing comma.

(comma-dangle)


[error] 146-150: Unnecessarily quoted property 'copy' found.

(quote-props)


[error] 149-150: Missing trailing comma.

(comma-dangle)


[error] 150-151: Missing trailing comma.

(comma-dangle)


[error] 152-152: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 157-157: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 159-159: Expected parentheses around arrow function argument.

(arrow-parens)


[error] 160-160: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 162-162: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 164-164: Missing radix parameter.

(radix)


[error] 165-165: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 170-170: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 175-175: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 181-181: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 186-186: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 187-187: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 187-187: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 188-188: Do not use new Array().

(unicorn/no-new-array)


[error] 190-190: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 191-191: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 194-194: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 195-195: Unary operator '++' used.

(no-plusplus)


[error] 197-197: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 204-204: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 210-210: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 213-213: Trailing spaces not allowed.

(no-trailing-spaces)

src/main/ffmpeg-optimizations.ts

[error] 1-1: Filename is not in camel case or pascal case. Rename it to ffmpegOptimizations.ts or FfmpegOptimizations.ts.

(unicorn/filename-case)


[error] 25-25: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 28-28: 'customMatcher' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 33-33: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 41-41: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 46-47: Missing trailing comma.

(comma-dangle)


[error] 49-49: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 51-51: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 53-53: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 57-57: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 59-68: Function declared in a loop contains unsafe references to variable(s) 'completed', 'completed', 'completed'.

(no-loop-func)


[error] 61-61: Unary operator '++' used.

(no-plusplus)


[error] 62-62: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 66-66: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 69-69: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 73-73: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 80-80: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 91-91: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 104-104: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 108-109: Missing trailing comma.

(comma-dangle)


[error] 115-115: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 124-124: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 129-129: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 136-140: Unnecessarily quoted property 'libx264' found.

(quote-props)


[error] 139-140: Missing trailing comma.

(comma-dangle)


[error] 141-145: Unnecessarily quoted property 'libx265' found.

(quote-props)


[error] 144-145: Missing trailing comma.

(comma-dangle)


[error] 146-150: Unnecessarily quoted property 'copy' found.

(quote-props)


[error] 149-150: Missing trailing comma.

(comma-dangle)


[error] 150-151: Missing trailing comma.

(comma-dangle)


[error] 152-152: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 157-157: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 159-159: Expected parentheses around arrow function argument.

(arrow-parens)


[error] 160-160: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 162-162: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 164-164: Missing radix parameter.

(radix)


[error] 165-165: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 170-170: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 175-175: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 181-181: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 186-186: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 187-187: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 187-187: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 188-188: Do not use new Array().

(unicorn/no-new-array)


[error] 190-190: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 191-191: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 194-194: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 195-195: Unary operator '++' used.

(no-plusplus)


[error] 197-197: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 204-204: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 210-210: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 213-213: Trailing spaces not allowed.

(no-trailing-spaces)

src/renderer/src/hooks/useFfmpegOperations.ts

[error] 71-71: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 72-72: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 72-72: Missing trailing comma.

(comma-dangle)

🔇 Additional comments (5)
src/renderer/src/hooks/useFfmpegOperations.ts (5)

19-21: LGTM! Good performance optimization.

The dynamic concurrency calculation based on hardware capabilities is a solid improvement. The bounds (2-8) are reasonable to ensure efficient parallel processing without overwhelming the system.


137-137: Good optimization for duration fetching.

Using dynamic concurrency for getting file durations improves performance, especially when concatenating many files.


635-635: Excellent optimization for segment processing.

This is a key performance improvement. Processing multiple segments in parallel with hardware-aware concurrency will significantly speed up batch operations.


908-908: Good concurrency control for stream extraction.

Applying dynamic concurrency to stream extraction operations ensures efficient resource utilization.


944-944: Consistent concurrency optimization.

Good to see the same optimization applied to attachment stream extraction for consistency.

@mifi
Copy link
Owner

mifi commented Aug 8, 2025

thanks for your pr. I don't under stand what the new files ffmpeg-optimizations and ffmpeg-optimizations-fixed are for? I don't see them being referenced from anywhere.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants