Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 100,
"printWidth": 120,
"tabWidth": 4,
"useTabs": false,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf"
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"overrides": [
{
"files": "*.yaml",
"options": {
"tabWidth": 4
}
},
{
"files": "*.yml",
"options": {
"tabWidth": 4
}
}
]
}
Binary file modified .yarn/install-state.gz
Binary file not shown.
46 changes: 46 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,53 @@ module.exports = [
},
},
{
// Browser/Renderer JavaScript files (Electron renderer process)
files: ['packages/mac/src/renderer/**/*.js'],
languageOptions: {
ecmaVersion: 2020,
sourceType: 'script', // Renderer files use script mode
globals: {
// Browser globals
window: 'readonly',
document: 'readonly',
console: 'readonly',
setTimeout: 'readonly',
clearTimeout: 'readonly',
setInterval: 'readonly',
clearInterval: 'readonly',
alert: 'readonly',
confirm: 'readonly',
prompt: 'readonly',
// DOM globals
Element: 'readonly',
HTMLElement: 'readonly',
Event: 'readonly',
MouseEvent: 'readonly',
KeyboardEvent: 'readonly',
// Additional browser APIs
fetch: 'readonly',
localStorage: 'readonly',
sessionStorage: 'readonly',
},
},
plugins: {
prettier,
},
rules: {
'prettier/prettier': [
'error',
{
tabWidth: 4,
},
],
// Relax some rules for renderer files
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
},
},
{
// Node.js JavaScript files
files: ['**/*.js', '**/*.mjs', '**/*.cjs'],
ignores: ['packages/mac/src/renderer/**/*.js'], // Exclude renderer files
languageOptions: {
ecmaVersion: 2020,
sourceType: 'module',
Expand Down
6 changes: 1 addition & 5 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,7 @@ module.exports = {
],

// Global settings
collectCoverageFrom: [
'packages/*/src/**/*.ts',
'!packages/*/src/**/*.d.ts',
'!packages/*/src/**/index.ts',
],
collectCoverageFrom: ['packages/*/src/**/*.ts', '!packages/*/src/**/*.d.ts', '!packages/*/src/**/index.ts'],

coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov', 'html'],
Expand Down
20 changes: 9 additions & 11 deletions packages/cli/__tests__/commands/convert-command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,10 @@ describe('ConvertCommandCreator', () => {

// Setup mocks
const { SubtitleProcessor, ConfigManager } = require('@subzilla/core');
const mockProcessFile = jest
.fn<() => Promise<{ outputPath: string; backupPath: string }>>()
.mockResolvedValue({
outputPath: '/mock/output.srt',
backupPath: '/mock/backup.srt',
});
const mockProcessFile = jest.fn<() => Promise<{ outputPath: string; backupPath: string }>>().mockResolvedValue({
outputPath: '/mock/output.srt',
backupPath: '/mock/backup.srt',
});

(SubtitleProcessor as any).mockImplementation(() => ({
processFile: mockProcessFile,
Expand Down Expand Up @@ -152,7 +150,7 @@ describe('ConvertCommandCreator', () => {
html: true,
colors: true,
}),
})
}),
);
});

Expand All @@ -169,7 +167,7 @@ describe('ConvertCommandCreator', () => {
expect.objectContaining({
retryCount: 3,
retryDelay: 2000,
})
}),
);
});

Expand All @@ -190,7 +188,7 @@ describe('ConvertCommandCreator', () => {
overwriteInput: true,
overwriteExisting: true,
overwriteBackup: false,
})
}),
);
});

Expand All @@ -213,7 +211,7 @@ describe('ConvertCommandCreator', () => {
expect.objectContaining({
backupOriginal: true,
bom: false,
})
}),
);
});

Expand Down Expand Up @@ -242,7 +240,7 @@ describe('ConvertCommandCreator', () => {
'🧬 Output options:',
expect.objectContaining({
lineEndings: 'lf',
})
}),
);
});
});
Expand Down
24 changes: 7 additions & 17 deletions packages/cli/src/commands/batch-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@ export class BatchCommandCreator extends BaseCommandCreator<IBatchCommandOptions
common: {
strip: createStripOptions(options, config),
backupOriginal: options.backup ?? config.output?.createBackup,
overwriteBackup:
options.overwriteBackup ?? config.output?.overwriteBackup,
overwriteBackup: options.overwriteBackup ?? config.output?.overwriteBackup,
bom: options.bom ?? config.output?.bom,
lineEndings: options.lineEndings ?? config.output?.lineEndings,
overwriteInput: options.overwriteInput ?? config.output?.overwriteInput,
overwriteExisting:
options.overwriteExisting ?? config.output?.overwriteExisting,
overwriteExisting: options.overwriteExisting ?? config.output?.overwriteExisting,
retryCount: options.retryCount
? parseInt(options.retryCount, 10)
: config.batch?.retryCount,
Expand All @@ -43,19 +41,11 @@ export class BatchCommandCreator extends BaseCommandCreator<IBatchCommandOptions
outputDir: options.outputDir ?? config.output?.directory,
recursive: options.recursive ?? config.batch?.recursive ?? false,
parallel: options.parallel ?? config.batch?.parallel ?? false,
skipExisting:
options.skipExisting ?? config.batch?.skipExisting ?? false,
maxDepth: options.maxDepth
? parseInt(options.maxDepth, 10)
: config.batch?.maxDepth,
includeDirectories:
options.includeDirs ?? config.batch?.includeDirectories,
excludeDirectories:
options.excludeDirs ?? config.batch?.excludeDirectories,
preserveStructure:
options.preserveStructure ??
config.batch?.preserveStructure ??
false,
skipExisting: options.skipExisting ?? config.batch?.skipExisting ?? false,
maxDepth: options.maxDepth ? parseInt(options.maxDepth, 10) : config.batch?.maxDepth,
includeDirectories: options.includeDirs ?? config.batch?.includeDirectories,
excludeDirectories: options.excludeDirs ?? config.batch?.excludeDirectories,
preserveStructure: options.preserveStructure ?? config.batch?.preserveStructure ?? false,
chunkSize: options.chunkSize ?? config.batch?.chunkSize,
},
};
Expand Down
15 changes: 4 additions & 11 deletions packages/cli/src/commands/convert-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,9 @@ export class ConvertCommandCreator extends BaseCommandCreator<IConvertCommandOpt
bom: options.bom ?? config.output?.bom,
lineEndings: options.lineEndings ?? config.output?.lineEndings,
overwriteInput: options.overwriteInput ?? config.output?.overwriteInput,
overwriteExisting:
options.overwriteExisting ?? config.output?.overwriteExisting,
retryCount: options.retryCount
? parseInt(options.retryCount, 10)
: config.batch?.retryCount,
retryDelay: options.retryDelay
? parseInt(options.retryDelay, 10)
: config.batch?.retryDelay,
overwriteExisting: options.overwriteExisting ?? config.output?.overwriteExisting,
retryCount: options.retryCount ? parseInt(options.retryCount, 10) : config.batch?.retryCount,
retryDelay: options.retryDelay ? parseInt(options.retryDelay, 10) : config.batch?.retryDelay,
};

console.log('🧬 Output options:', outputOptions);
Expand All @@ -45,9 +40,7 @@ export class ConvertCommandCreator extends BaseCommandCreator<IConvertCommandOpt

console.log('✨ Conversion successful!');
console.log(`Input file: ${inputFile}`);
console.log(
`Output file: ${options.output || this.getDefaultOutputPath(inputFile)}`
);
console.log(`Output file: ${options.output || this.getDefaultOutputPath(inputFile)}`);

if (options.backup || config.output?.createBackup) {
console.log(`Backup file: ${inputFile}.bak`);
Expand Down
12 changes: 3 additions & 9 deletions packages/cli/src/commands/info-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,15 @@ export class InfoCommandCreator extends BaseCommandCreator<IInfoCommandOptions>
const fileBuffer = await fs.readFile(inputFile);

// Detect encoding
const detectedEncoding =
await EncodingDetectionService.detectEncoding(inputFile);
const detectedEncoding = await EncodingDetectionService.detectEncoding(inputFile);

// Check for BOM
const hasBOM = fileBuffer.slice(0, 3).equals(Buffer.from([0xef, 0xbb, 0xbf]));

// Count lines and entries
const content = fileBuffer.toString(detectedEncoding as NodeJS.BufferEncoding);
const lines = content.split(/\r?\n/);
const entries = content
.split(/\r?\n\r?\n/)
.filter((entry) => entry.trim()).length;
const entries = content.split(/\r?\n\r?\n/).filter((entry) => entry.trim()).length;

// Detect line endings
const hasCarriageReturn = content.includes('\r\n');
Expand All @@ -63,10 +60,7 @@ export class InfoCommandCreator extends BaseCommandCreator<IInfoCommandOptions>
console.log(` • Total Lines: ${chalk.yellow(lines.length)}`);
console.log(` • Subtitle Entries: ${chalk.yellow(entries)}`);
} catch (error) {
console.error(
chalk.red('❌ Error analyzing subtitle file:'),
(error as Error).message
);
console.error(chalk.red('❌ Error analyzing subtitle file:'), (error as Error).message);
process.exit(1);
}
},
Expand Down
5 changes: 1 addition & 4 deletions packages/cli/src/utils/strip-options.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { IStripOptions, IStripCommandOptions, IConfig } from '@subzilla/types';

export function createStripOptions(
options: IStripCommandOptions,
config: IConfig
): IStripOptions | undefined {
export function createStripOptions(options: IStripCommandOptions, config: IConfig): IStripOptions | undefined {
const stripOptions: IStripOptions = options.stripAll
? {
html: true,
Expand Down
4 changes: 2 additions & 2 deletions packages/core/__tests__/EncodingConversionService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ describe('EncodingConversionService', () => {
const content = 'Smart quotes: "Hello"';
// Create buffer with Windows-1252 specific characters
const buffer = Buffer.from([
0x53, 0x6d, 0x61, 0x72, 0x74, 0x20, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x3a, 0x20,
0x93, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x94,
0x53, 0x6d, 0x61, 0x72, 0x74, 0x20, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x3a, 0x20, 0x93, 0x48, 0x65,
0x6c, 0x6c, 0x6f, 0x94,
]);

const result = EncodingConversionService.convertToUtf8(buffer, 'windows-1252');
Expand Down
4 changes: 1 addition & 3 deletions packages/core/__tests__/EncodingDetectionService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,7 @@ describe('EncodingDetectionService', () => {
it('should reject when file does not exist', async () => {
const nonExistentPath = path.join(tempDir, 'nonexistent.srt');

await expect(
EncodingDetectionService.detectEncoding(nonExistentPath)
).rejects.toThrow();
await expect(EncodingDetectionService.detectEncoding(nonExistentPath)).rejects.toThrow();
});

it('should handle Windows-1252 encoded content', async () => {
Expand Down
31 changes: 9 additions & 22 deletions packages/core/src/BatchProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default class BatchProcessor {
hideCursor: true,
clearOnComplete: false,
},
Presets.shades_classic
Presets.shades_classic,
);

this.directoryBars = new Map();
Expand Down Expand Up @@ -62,9 +62,7 @@ export default class BatchProcessor {
}

this.stats.total = files.length;
console.log(
`🔍 Found ${files.length} files in ${this.countDirectories(files)} directories...`
);
console.log(`🔍 Found ${files.length} files in ${this.countDirectories(files)} directories...`);

// Create output directory if specified
if (options.common.outputDir) {
Expand All @@ -90,8 +88,7 @@ export default class BatchProcessor {

// Finalize statistics
this.stats.timeTaken = (Date.now() - this.startTime) / 1000;
this.stats.averageTimePerFile =
this.stats.timeTaken / (this.stats.successful + this.stats.failed);
this.stats.averageTimePerFile = this.stats.timeTaken / (this.stats.successful + this.stats.failed);

// Stop progress bars
this.multiBar.stop();
Expand Down Expand Up @@ -157,39 +154,33 @@ export default class BatchProcessor {

return acc;
},
{} as Record<string, string[]>
{} as Record<string, string[]>,
);
}

private async processDirectoriesParallel(
filesByDir: Record<string, string[]>,
options: IBatchOptions
options: IBatchOptions,
): Promise<void> {
const directories = Object.entries(filesByDir);
const chunks = this.chunkArray(directories, options.batch.chunkSize || 3); // Use configured chunk size

for (const chunk of chunks) {
if (this.shouldStop) break;
await Promise.all(
chunk.map(([dir, files]) => this.processDirectory(dir, files, options))
);
await Promise.all(chunk.map(([dir, files]) => this.processDirectory(dir, files, options)));
}
}

private async processDirectoriesSequential(
filesByDir: Record<string, string[]>,
options: IBatchOptions
options: IBatchOptions,
): Promise<void> {
for (const [dir, files] of Object.entries(filesByDir)) {
await this.processDirectory(dir, files, options);
}
}

private async processDirectory(
dir: string,
files: string[],
options: IBatchOptions
): Promise<void> {
private async processDirectory(dir: string, files: string[], options: IBatchOptions): Promise<void> {
if (this.shouldStop) return;

// Create directory progress bar
Expand Down Expand Up @@ -240,11 +231,7 @@ export default class BatchProcessor {
if (this.shouldStop) return;

try {
if (
options.batch.skipExisting &&
outputPath &&
(await this.fileExists(outputPath))
) {
if (options.batch.skipExisting && outputPath && (await this.fileExists(outputPath))) {
dirStats.skipped++;
this.stats.skipped++;

Expand Down
Loading
Loading