@@ -3,7 +3,7 @@ import { verifyVideoAccessToken, detectHotlinking, trackVideoAccess, logSecurity
33import { getRedis } from '@/lib/redis'
44import { prisma } from '@/lib/db'
55import { createReadStream , existsSync , statSync , ReadStream } from 'fs'
6- import { getFilePath , sanitizeFilenameForHeader } from '@/lib/storage'
6+ import { getFilePath , sanitizeFilenameForHeader , getVideoContentType } from '@/lib/storage'
77import { rateLimit } from '@/lib/rate-limit'
88import { getClientIpAddress } from '@/lib/utils'
99import { getAuthContext } from '@/lib/auth'
@@ -202,7 +202,7 @@ export async function GET(
202202 const originalPath = video . originalStoragePath
203203 let filePath : string | null = null
204204 let filename : string | null = null
205- let contentType = ' video/mp4'
205+ let contentType = getVideoContentType ( video . originalFileName || '' )
206206
207207 // Handle asset download
208208 if ( assetId && isDownload ) {
@@ -278,12 +278,12 @@ export async function GET(
278278 // Use asset filename if available, otherwise generate from video info
279279 const rawFilename = filename || ( video . approved
280280 ? video . originalFileName
281- : `${ video . project . title . replace ( / [ ^ a - z 0 - 9 ] / gi, '_' ) } _${ verifiedToken . quality } . mp4` )
281+ : `${ video . project . title . replace ( / [ ^ a - z 0 - 9 ] / gi, '_' ) } _${ verifiedToken . quality } ${ ( video . originalFileName || '. mp4' ) . slice ( ( video . originalFileName || '.mp4' ) . lastIndexOf ( '.' ) ) } ` )
282282 const sanitizedFilename = sanitizeFilenameForHeader ( rawFilename )
283283
284- // For non-asset streams, determine Content-Type based on quality
284+ // For non-asset downloads, use original file's content type
285285 if ( ! assetId ) {
286- contentType = isThumbnail ? 'image/jpeg' : ' video/mp4'
286+ contentType = isThumbnail ? 'image/jpeg' : getVideoContentType ( video . originalFileName || '' )
287287 }
288288
289289 const trackDownloadOnce = async ( ) => {
@@ -371,9 +371,15 @@ export async function GET(
371371 const fileStream = createReadStream ( fullPath , { start, end, highWaterMark : STREAM_HIGH_WATER_MARK_BYTES } )
372372 const readableStream = createWebReadableStream ( fileStream )
373373
374- // For non-asset streams, determine Content-Type based on quality
374+ // For non-asset streams, determine Content-Type
375375 if ( ! assetId ) {
376- contentType = isThumbnail ? 'image/jpeg' : 'video/mp4'
376+ if ( isThumbnail ) {
377+ contentType = 'image/jpeg'
378+ } else if ( filePath === originalPath ) {
379+ contentType = getVideoContentType ( video . originalFileName || '' )
380+ } else {
381+ contentType = 'video/mp4' // transcoded previews are always mp4
382+ }
377383 }
378384
379385 return new NextResponse ( readableStream , {
@@ -395,9 +401,15 @@ export async function GET(
395401 const fileStream = createReadStream ( fullPath , { highWaterMark : STREAM_HIGH_WATER_MARK_BYTES } )
396402 const readableStream = createWebReadableStream ( fileStream )
397403
398- // For non-asset streams, determine Content-Type based on quality
404+ // For non-asset streams, determine Content-Type
399405 if ( ! assetId ) {
400- contentType = isThumbnail ? 'image/jpeg' : 'video/mp4'
406+ if ( isThumbnail ) {
407+ contentType = 'image/jpeg'
408+ } else if ( filePath === originalPath ) {
409+ contentType = getVideoContentType ( video . originalFileName || '' )
410+ } else {
411+ contentType = 'video/mp4' // transcoded previews are always mp4
412+ }
401413 }
402414
403415 return new NextResponse ( readableStream , {
0 commit comments