feat(downloads): preserve original camera filenames on download (opt-in) (#493)
New Settings → General toggle `Use original filenames on download` (off by default). When on, single-photo downloads, bulk/selection zips, and per-event archive zips surface `photos.original_filename` instead of the sanitized storage filename. Storage paths are unchanged. - Content-Disposition uses RFC 5987 (`filename=` ASCII + `filename*=UTF-8''…`) so unicode camera filenames survive while header-injection bytes are stripped. - Zip entries are deduplicated with a deterministic `_1` / `_2` suffix on collision (folder structure preserved in archive zips). - Pre-generated download-all zips and the in-memory setting cache are invalidated when the toggle flips so the next download rebuilds with the new names. - Falls back to the storage filename whenever `original_filename` is null (legacy uploads predating migration 062).
This commit is contained in:
@@ -20,6 +20,7 @@ export interface GeneralSettings {
|
||||
enable_registration: boolean;
|
||||
maintenance_mode: boolean;
|
||||
short_gallery_urls: boolean;
|
||||
use_original_filenames_for_downloads: boolean;
|
||||
default_language: string;
|
||||
date_format: { format: string; locale: string };
|
||||
}
|
||||
@@ -94,6 +95,7 @@ export function useSettingsState() {
|
||||
enable_registration: false,
|
||||
maintenance_mode: false,
|
||||
short_gallery_urls: false,
|
||||
use_original_filenames_for_downloads: false,
|
||||
default_language: 'en',
|
||||
date_format: { format: 'dd/MM/yyyy', locale: 'en-GB' }
|
||||
});
|
||||
@@ -179,6 +181,10 @@ export function useSettingsState() {
|
||||
enable_registration: toBoolean(settings.general_enable_registration, false),
|
||||
maintenance_mode: toBoolean(settings.general_maintenance_mode, false),
|
||||
short_gallery_urls: toBoolean(settings.general_short_gallery_urls, false),
|
||||
use_original_filenames_for_downloads: toBoolean(
|
||||
settings.general_use_original_filenames_for_downloads,
|
||||
false
|
||||
),
|
||||
default_language: settings.general_default_language || 'en',
|
||||
date_format: settings.general_date_format
|
||||
? (typeof settings.general_date_format === 'string'
|
||||
|
||||
@@ -229,6 +229,21 @@ export const GeneralTab: React.FC<GeneralTabProps> = ({
|
||||
{t('settings.general.enableShortGalleryUrlsHelp')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={generalSettings.use_original_filenames_for_downloads}
|
||||
onChange={(e) => setGeneralSettings(prev => ({ ...prev, use_original_filenames_for_downloads: e.target.checked }))}
|
||||
className="w-4 h-4 text-primary-600 rounded focus:ring-primary-500"
|
||||
/>
|
||||
<span className="ml-2 text-sm text-neutral-700 dark:text-neutral-300">{t('settings.general.useOriginalFilenames')}</span>
|
||||
</label>
|
||||
<p className="text-xs text-neutral-500 dark:text-neutral-400 ml-6 mt-1">
|
||||
{t('settings.general.useOriginalFilenamesHelp')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
|
||||
@@ -1038,6 +1038,8 @@
|
||||
"enableRegistration": "Selbstregistrierung für Admins erlauben",
|
||||
"enableShortGalleryUrls": "Kurze Galerie-Links verwenden",
|
||||
"enableShortGalleryUrlsHelp": "Entfernt den Veranstaltungs-Slug aus neuen Freigabelinks und lässt bestehende Links weiterhin funktionieren.",
|
||||
"useOriginalFilenames": "Originale Dateinamen beim Download verwenden",
|
||||
"useOriginalFilenamesHelp": "Wenn aktiviert, verwenden Einzel- und ZIP-Downloads den Original-Dateinamen der Kamera (z. B. DSC_1234.jpg) statt des umbenannten Namens. Der Speicher bleibt unverändert; Duplikate innerhalb einer Veranstaltung erhalten ein numerisches Suffix.",
|
||||
"maintenanceMode": "Wartungsmodus aktivieren",
|
||||
"language": "Sprache",
|
||||
"defaultLanguageHelp": "Sprache, die Gästen vor der Anmeldung angezeigt wird",
|
||||
|
||||
@@ -677,6 +677,8 @@
|
||||
"enableRegistration": "Allow self-registration for admins",
|
||||
"enableShortGalleryUrls": "Use short gallery URLs",
|
||||
"enableShortGalleryUrlsHelp": "Removes the event slug from new share links while keeping existing links working.",
|
||||
"useOriginalFilenames": "Use original filenames on download",
|
||||
"useOriginalFilenamesHelp": "When on, single-photo and ZIP downloads use the original camera filename (e.g. DSC_1234.jpg) instead of the sanitized name. Storage is unchanged; duplicates in the same event get a numeric suffix.",
|
||||
"maintenanceMode": "Enable maintenance mode",
|
||||
"language": "Language",
|
||||
"defaultLanguageHelp": "Language shown to guests before login",
|
||||
|
||||
Reference in New Issue
Block a user