Skip to content

Commit 17c2d01

Browse files
authored
feat: add customizable suffix env vars for synced subtitle filenames (fixes #25) (#58)
Add FFSUBSYNC_SUFFIX, AUTOSUBSYNC_SUFFIX, and ALASS_SUFFIX env vars so users can control the output filename suffix for Bazarr compatibility. Includes duplicate suffix prevention (e.g., movie.en.cc.srt won't become movie.en.cc.cc.srt when suffix is "cc").
1 parent 631f633 commit 17c2d01

7 files changed

Lines changed: 48 additions & 23 deletions

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ docker run -d \
105105
| `CRON_SCHEDULE` | `0 0 * * *` | Cron expression for sync schedule (daily at midnight), or `disabled` to turn off |
106106
| `MAX_CONCURRENT_SYNC_TASKS` | `1` | Number of subtitle files to process in parallel (higher = faster but more CPU) |
107107
| `INCLUDE_ENGINES` | `ffsubsync,autosubsync,alass` | Which sync engines to use (comma-separated) |
108+
| `FFSUBSYNC_SUFFIX` | `ffsubsync` | Custom suffix for ffsubsync output files (e.g., `sdh` → `movie.en.sdh.srt`) |
109+
| `AUTOSUBSYNC_SUFFIX` | `autosubsync` | Custom suffix for autosubsync output files (e.g., `cc` → `movie.en.cc.srt`) |
110+
| `ALASS_SUFFIX` | `alass` | Custom suffix for alass output files (e.g., `forced` → `movie.en.forced.srt`) |
108111
| `SYNC_TIMEOUT` | _(none)_ | Timeout in seconds per sync operation (overrides SYNC_ENGINE_TIMEOUT_MS) |
109112
| `SYNC_ENGINE_TIMEOUT_MS` | `1800000` | Timeout for each sync engine in milliseconds (30 min default) |
110113
| `NODE_OPTIONS` | `--max-old-space-size=512` | Node.js options, used here to set memory limit (in MB) |

src/config.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@ export interface ScanConfig {
33
excludePaths: string[];
44
}
55

6+
export interface SuffixConfig {
7+
ffsubsync: string;
8+
autosubsync: string;
9+
alass: string;
10+
}
11+
12+
export function getSuffixConfig(): SuffixConfig {
13+
return {
14+
ffsubsync: process.env.FFSUBSYNC_SUFFIX || 'ffsubsync',
15+
autosubsync: process.env.AUTOSUBSYNC_SUFFIX || 'autosubsync',
16+
alass: process.env.ALASS_SUFFIX || 'alass',
17+
};
18+
}
19+
620
export interface RetentionConfig {
721
keepRunsDays: number; // Keep complete runs for N days
822
trimLogsDays: number; // Trim logs after N days

src/findAllSrtFiles.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import { readdir } from 'fs/promises';
2-
import { basename, dirname, extname, join } from 'path';
2+
import { basename, extname, join } from 'path';
33
import { existsSync } from 'fs';
4-
import { ScanConfig } from './config';
4+
import { getSuffixConfig, ScanConfig } from './config';
5+
import { buildOutputPath } from './helpers';
56

67
function isAlreadySynced(srtPath: string, engines: string[]): boolean {
7-
const directory = dirname(srtPath);
8-
const srtBaseName = basename(srtPath, '.srt');
8+
const suffixConfig = getSuffixConfig();
99

1010
return engines.every((engine) => {
11-
const outputPath = join(directory, `${srtBaseName}.${engine}.srt`);
11+
const suffix = suffixConfig[engine as keyof typeof suffixConfig] || engine;
12+
const outputPath = buildOutputPath(srtPath, suffix);
1213
return existsSync(outputPath);
1314
});
1415
}
@@ -39,6 +40,11 @@ export async function findAllSrtFiles(config: ScanConfig): Promise<ScanResult> {
3940
console.log(`${new Date().toLocaleString()} Language filter active: ${languages.join(', ')}`);
4041
}
4142

43+
const suffixConfig = getSuffixConfig();
44+
const syncedSuffixes = engines.map(
45+
(engine) => `.${suffixConfig[engine as keyof typeof suffixConfig] || engine}.`,
46+
);
47+
4248
async function scan(directory: string): Promise<void> {
4349
// Check if this directory should be excluded
4450
if (config.excludePaths.some((excludePath) => directory.startsWith(excludePath))) {
@@ -55,9 +61,7 @@ export async function findAllSrtFiles(config: ScanConfig): Promise<ScanResult> {
5561
} else if (
5662
entry.isFile() &&
5763
extname(entry.name).toLowerCase() === '.srt' &&
58-
!entry.name.includes('.ffsubsync.') &&
59-
!entry.name.includes('.alass.') &&
60-
!entry.name.includes('.autosubsync.') &&
64+
!syncedSuffixes.some((suffix) => entry.name.includes(suffix)) &&
6165
matchesLanguageFilter(entry.name, languages)
6266
) {
6367
if (isAlreadySynced(fullPath, engines)) {

src/generateAlassSubtitles.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { basename, dirname, join } from 'path';
2-
import { execPromise, ProcessingResult } from './helpers';
1+
import { buildOutputPath, execPromise, ProcessingResult } from './helpers';
32
import { existsSync } from 'fs';
3+
import { getSuffixConfig } from './config';
44

55
export async function generateAlassSubtitles(srtPath: string, videoPath: string): Promise<ProcessingResult> {
6-
const directory = dirname(srtPath);
7-
const srtBaseName = basename(srtPath, '.srt');
8-
const outputPath = join(directory, `${srtBaseName}.alass.srt`);
6+
const outputPath = buildOutputPath(srtPath, getSuffixConfig().alass);
97

108
const exists = existsSync(outputPath);
119
if (exists) {

src/generateAutosubsyncSubtitles.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { basename, dirname, join } from 'path';
2-
import { execPromise, ProcessingResult } from './helpers';
1+
import { buildOutputPath, execPromise, ProcessingResult } from './helpers';
32
import { existsSync } from 'fs';
3+
import { getSuffixConfig } from './config';
44

55
export async function generateAutosubsyncSubtitles(srtPath: string, videoPath: string): Promise<ProcessingResult> {
6-
const directory = dirname(srtPath);
7-
const srtBaseName = basename(srtPath, '.srt');
8-
const outputPath = join(directory, `${srtBaseName}.autosubsync.srt`);
6+
const outputPath = buildOutputPath(srtPath, getSuffixConfig().autosubsync);
97

108
const exists = existsSync(outputPath);
119
if (exists) {

src/generateFfsubsyncSubtitles.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { basename, dirname, join } from 'path';
2-
import { execPromise, ProcessingResult } from './helpers';
1+
import { buildOutputPath, execPromise, ProcessingResult } from './helpers';
32
import { existsSync } from 'fs';
3+
import { getSuffixConfig } from './config';
44

55
export async function generateFfsubsyncSubtitles(srtPath: string, videoPath: string): Promise<ProcessingResult> {
6-
const directory = dirname(srtPath);
7-
const srtBaseName = basename(srtPath, '.srt');
8-
const outputPath = join(directory, `${srtBaseName}.ffsubsync.srt`);
6+
const outputPath = buildOutputPath(srtPath, getSuffixConfig().ffsubsync);
97

108
// Check if synced subtitle already exists
119
const exists = existsSync(outputPath);

src/helpers.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
import { exec } from 'child_process';
2+
import { basename, dirname, join } from 'path';
3+
4+
export function buildOutputPath(srtPath: string, suffix: string): string {
5+
const directory = dirname(srtPath);
6+
let srtBaseName = basename(srtPath, '.srt');
7+
if (srtBaseName.endsWith(`.${suffix}`)) {
8+
srtBaseName = srtBaseName.slice(0, -(suffix.length + 1));
9+
}
10+
return join(directory, `${srtBaseName}.${suffix}.srt`);
11+
}
212

313
export interface ProcessingResult {
414
success: boolean;

0 commit comments

Comments
 (0)