diff --git a/js/customFormats.ts b/js/customFormats.ts deleted file mode 100644 index f8d5c2e..0000000 --- a/js/customFormats.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Re-exports for backwards compatibility – canonical source is ffmpegFormats.ts -export { - type ProgressEvent, - type CustomFormat, - type ContainerFormat, - customFormats, - containerFormats, - isCustomFormat, - getCustomFormat, - getContainerFormat, - transcodeWithCustomFormat, - transcodeWithContainerFormat, -} from './ffmpegFormats'; diff --git a/js/ffmpegFormats.ts b/js/ffmpegFormats.ts index 0493993..5fa25b5 100644 --- a/js/ffmpegFormats.ts +++ b/js/ffmpegFormats.ts @@ -12,8 +12,6 @@ export interface ProgressEvent { export interface CustomFormat { /** Human-readable label shown in the UI */ displayName: string; - /** Internal identifier, must start with `FFMPEG_` */ - internalName: string; /** Arguments passed to ffmpeg (excluding input/output file args) */ ffmpegArgs: string[]; /** Output filename used when calling ffmpeg */ @@ -40,37 +38,33 @@ export interface ContainerFormat extends Omit { needsTranscode: (blob: Blob) => Promise; } -export const customFormats: CustomFormat[] = [ - { +export const customFormats: Record = { + FFMPEG_MP3_320: { displayName: 'MP3 320kbps', - internalName: 'FFMPEG_MP3_320', ffmpegArgs: ['-map_metadata', '-1', '-c:a', 'libmp3lame', '-b:a', '320k', '-ar', '44100'], outputFilename: 'output.mp3', outputMime: 'audio/mpeg', extension: 'mp3', category: 'MP3', }, - { + FFMPEG_MP3_256: { displayName: 'MP3 256kbps', - internalName: 'FFMPEG_MP3_256', ffmpegArgs: ['-map_metadata', '-1', '-c:a', 'libmp3lame', '-b:a', '256k', '-ar', '44100'], outputFilename: 'output.mp3', outputMime: 'audio/mpeg', extension: 'mp3', category: 'MP3', }, - { + FFMPEG_MP3_128: { displayName: 'MP3 128kbps', - internalName: 'FFMPEG_MP3_128', ffmpegArgs: ['-map_metadata', '-1', '-c:a', 'libmp3lame', '-b:a', '128k', '-ar', '44100'], outputFilename: 'output.mp3', outputMime: 'audio/mpeg', extension: 'mp3', category: 'MP3', }, - { + FFMPEG_OGG_320: { displayName: 'OGG 320kbps', - internalName: 'FFMPEG_OGG_320', ffmpegArgs: [ '-map_metadata', '-1', @@ -88,9 +82,8 @@ export const customFormats: CustomFormat[] = [ extension: 'ogg', category: 'OGG', }, - { + FFMPEG_OGG_256: { displayName: 'OGG 256kbps', - internalName: 'FFMPEG_OGG_256', ffmpegArgs: [ '-map_metadata', '-1', @@ -108,9 +101,8 @@ export const customFormats: CustomFormat[] = [ extension: 'ogg', category: 'OGG', }, - { + FFMPEG_OGG_128: { displayName: 'OGG 128kbps', - internalName: 'FFMPEG_OGG_128', ffmpegArgs: [ '-map_metadata', '-1', @@ -128,16 +120,15 @@ export const customFormats: CustomFormat[] = [ extension: 'ogg', category: 'OGG', }, - { + FFMPEG_AAC_256: { displayName: 'AAC 256kbps', - internalName: 'FFMPEG_AAC_256', ffmpegArgs: ['-map_metadata', '-1', '-c:a', 'aac', '-b:a', '256k'], outputFilename: 'output.m4a', outputMime: 'audio/mp4', extension: 'm4a', category: 'AAC', }, -]; +}; /** * Container format definitions for lossless re-muxing. Each entry describes @@ -145,10 +136,9 @@ export const customFormats: CustomFormat[] = [ * `needsTranscode` predicate so callers can skip the ffmpeg step when the * source is already in the correct container. */ -export const containerFormats: ContainerFormat[] = [ - { +export const containerFormats: Record = { + flac: { displayName: 'FLAC', - internalName: 'flac', ffmpegArgs: ['-vn', '-map_metadata', '-1', '-map', '0:a', '-c:a', 'flac'], outputFilename: 'output.flac', outputMime: 'audio/flac', @@ -156,25 +146,23 @@ export const containerFormats: ContainerFormat[] = [ // Only transcode when the source is NOT already a FLAC file. needsTranscode: async (blob) => (await getExtensionFromBlob(blob)) !== 'flac', }, - { + alac: { displayName: 'Apple Lossless', - internalName: 'alac', ffmpegArgs: ['-c:a', 'alac'], outputFilename: 'output.m4a', outputMime: 'audio/mp4', extension: 'm4a', needsTranscode: async () => true, }, - { + nochange: { displayName: "Don't change", - internalName: 'nochange', ffmpegArgs: ['-c:a', 'copy', '-strict', '-2'], outputFilename: 'output.mp4', outputMime: 'audio/mp4', extension: 'mp4', needsTranscode: async (blob) => (await getExtensionFromBlob(blob)) == 'm4a', }, -]; +}; /** Returns true if the quality string identifies a known custom ffmpeg-transcoded format */ export function isCustomFormat(quality: string): boolean { @@ -183,12 +171,12 @@ export function isCustomFormat(quality: string): boolean { /** Looks up a custom format by its internal name, or returns undefined */ export function getCustomFormat(internalName: string): CustomFormat | undefined { - return customFormats.find((f) => f.internalName === internalName); + return customFormats[internalName]; } /** Looks up a container format by its internal name, or returns undefined */ export function getContainerFormat(internalName: string): ContainerFormat | undefined { - return containerFormats.find((f) => f.internalName === internalName); + return containerFormats[internalName]; } /** diff --git a/js/settings.js b/js/settings.js index 8d7b1b0..8cbe240 100644 --- a/js/settings.js +++ b/js/settings.js @@ -816,8 +816,8 @@ export function initializeSettings(scrobbler, player, api, ui) { })); // Append custom (ffmpeg-transcoded) format options - for (const fmt of customFormats) { - allOptions.push({ value: fmt.internalName, text: fmt.displayName, category: fmt.category }); + for (const [key, fmt] of Object.entries(customFormats)) { + allOptions.push({ value: key, text: fmt.displayName, category: fmt.category }); } // Sort by category order first, then by bitrate descending within each category @@ -877,7 +877,7 @@ export function initializeSettings(scrobbler, player, api, ui) { } if (losslessContainerSetting) { - for (const { internalName, displayName } of containerFormats) { + for (const [internalName, { displayName }] of Object.entries(containerFormats)) { const option = document.createElement('option'); option.value = internalName; option.textContent = displayName;