ep_media_upload 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +50 -8
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -17,9 +17,9 @@ try {
17
17
  }
18
18
 
19
19
  // AWS SDK v3 for presigned URLs
20
- let S3Client, PutObjectCommand, GetObjectCommand, getSignedUrl;
20
+ let S3Client, PutObjectCommand, GetObjectCommand, HeadObjectCommand, getSignedUrl;
21
21
  try {
22
- ({ S3Client, PutObjectCommand, GetObjectCommand } = require('@aws-sdk/client-s3'));
22
+ ({ S3Client, PutObjectCommand, GetObjectCommand, HeadObjectCommand } = require('@aws-sdk/client-s3'));
23
23
  ({ getSignedUrl } = require('@aws-sdk/s3-request-presigner'));
24
24
  } catch (e) {
25
25
  console.warn('[ep_media_upload] AWS SDK not installed; s3_presigned storage will not work.');
@@ -477,21 +477,63 @@ exports.expressCreateServer = (hookName, context) => {
477
477
  Array.isArray(inlineExtensions) &&
478
478
  inlineExtensions.map(e => e.toLowerCase()).includes(fileExtension.toLowerCase());
479
479
 
480
+ // Try to retrieve original filename from S3 object metadata
481
+ // The original filename was stored in Content-Disposition during upload
482
+ const s3Client = new S3Client({ region });
483
+ let filename = fileId.replace(/[^\w\-_.]/g, '_'); // Default fallback to UUID-based name
484
+
485
+ try {
486
+ const headCommand = new HeadObjectCommand({ Bucket: bucket, Key: key });
487
+ const headResponse = await s3Client.send(headCommand);
488
+
489
+ // Parse original filename from stored Content-Disposition header
490
+ // Format: attachment; filename="original-name.pdf"
491
+ if (headResponse.ContentDisposition) {
492
+ const match = headResponse.ContentDisposition.match(/filename="([^"]+)"/);
493
+ if (match && match[1]) {
494
+ // Use the original filename, sanitize it for safety
495
+ filename = match[1].replace(/[^\w\-_.]/g, '_');
496
+ }
497
+ }
498
+ } catch (headErr) {
499
+ // If HeadObject fails (e.g., file doesn't exist), we'll catch it later
500
+ // or use the fallback filename. Log for debugging but don't fail yet.
501
+ if (headErr.name !== 'NotFound' && headErr.Code !== 'NoSuchKey') {
502
+ logger.warn(`[ep_media_upload] HeadObject warning for key="${key}": ${headErr.message}`);
503
+ }
504
+ }
505
+
480
506
  // Determine Content-Disposition based on extension config
481
- // Extract filename for Content-Disposition header (UUID.ext -> use as filename)
482
- const filename = fileId.replace(/[^\w\-_.]/g, '_'); // Sanitize for header
483
507
  const disposition = shouldOpenInline
484
508
  ? `inline; filename="${filename}"`
485
509
  : `attachment; filename="${filename}"`;
486
510
 
511
+ // Map extensions to canonical MIME types for consistent browser playback
512
+ const EXTENSION_CONTENT_TYPE = {
513
+ mp3: 'audio/mpeg',
514
+ wav: 'audio/wav',
515
+ mp4: 'video/mp4',
516
+ mov: 'video/quicktime',
517
+ webm: 'video/webm',
518
+ ogg: 'audio/ogg',
519
+ m4a: 'audio/mp4',
520
+ pdf: 'application/pdf',
521
+ };
522
+
487
523
  // Generate presigned GET URL with short expiry
488
- // Use ResponseContentDisposition to override the stored header
489
- const s3Client = new S3Client({ region });
490
- const getCommand = new GetObjectCommand({
524
+ // Use ResponseContentDisposition and ResponseContentType to override stored headers
525
+ const commandParams = {
491
526
  Bucket: bucket,
492
527
  Key: key,
493
528
  ResponseContentDisposition: disposition,
494
- });
529
+ };
530
+
531
+ // Set canonical Content-Type for inline extensions to ensure browser compatibility
532
+ if (shouldOpenInline && fileExtension && EXTENSION_CONTENT_TYPE[fileExtension.toLowerCase()]) {
533
+ commandParams.ResponseContentType = EXTENSION_CONTENT_TYPE[fileExtension.toLowerCase()];
534
+ }
535
+
536
+ const getCommand = new GetObjectCommand(commandParams);
495
537
 
496
538
  // Use downloadExpires from config, default to 300 seconds (5 minutes)
497
539
  const expiresIn = downloadExpires || 300;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ep_media_upload",
3
3
  "description": "beta - Upload files to S3 and insert hyperlinks into the pad. Requires ep_hyperlinked_text.",
4
- "version": "0.2.2",
4
+ "version": "0.2.4",
5
5
  "author": {
6
6
  "name": "DCastelone",
7
7
  "url": "https://github.com/dcastelone"