diff options
author | 2024-11-04 13:58:15 +0000 | |
---|---|---|
committer | 2024-11-04 14:58:15 +0100 | |
commit | 8f288f1689376a8cf6ab7f431e862eb870765342 (patch) | |
tree | 42442833af06948eb3ec9f7710ed35b809cd6992 /internal | |
parent | [chore]: Bump github.com/minio/minio-go/v7 from 7.0.79 to 7.0.80 (#3511) (diff) | |
download | gotosocial-8f288f1689376a8cf6ab7f431e862eb870765342.tar.xz |
[bugfix] determine mime-type to use during ffprobe evaluation stage, don't bother checking against file extension (#3506)
* determine mime-type to use during ffprobe evaluation stage, don't bother rechecking by file extension
* set mjpeg content-type
* fix up tests expecting differing default values
Diffstat (limited to 'internal')
-rw-r--r-- | internal/api/client/instance/instancepatch_test.go | 12 | ||||
-rw-r--r-- | internal/media/ffmpeg.go | 75 | ||||
-rw-r--r-- | internal/media/manager.go | 2 | ||||
-rw-r--r-- | internal/media/manager_test.go | 2 | ||||
-rw-r--r-- | internal/media/processingemoji.go | 9 | ||||
-rw-r--r-- | internal/media/processingmedia.go | 20 | ||||
-rw-r--r-- | internal/media/thumbnail.go | 24 | ||||
-rw-r--r-- | internal/media/util.go | 8 | ||||
-rw-r--r-- | internal/typeutils/internaltofrontend_test.go | 4 |
9 files changed, 85 insertions, 71 deletions
diff --git a/internal/api/client/instance/instancepatch_test.go b/internal/api/client/instance/instancepatch_test.go index 5c7923adc..504fd7eb9 100644 --- a/internal/api/client/instance/instancepatch_test.go +++ b/internal/api/client/instance/instancepatch_test.go @@ -120,7 +120,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch1() { "image/apng", "audio/ogg", "video/ogg", - "audio/x-m4a", + "audio/mp4", "video/mp4", "video/quicktime", "audio/x-ms-wma", @@ -261,7 +261,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch2() { "image/apng", "audio/ogg", "video/ogg", - "audio/x-m4a", + "audio/mp4", "video/mp4", "video/quicktime", "audio/x-ms-wma", @@ -402,7 +402,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch3() { "image/apng", "audio/ogg", "video/ogg", - "audio/x-m4a", + "audio/mp4", "video/mp4", "video/quicktime", "audio/x-ms-wma", @@ -594,7 +594,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch6() { "image/apng", "audio/ogg", "video/ogg", - "audio/x-m4a", + "audio/mp4", "video/mp4", "video/quicktime", "audio/x-ms-wma", @@ -757,7 +757,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch8() { "image/apng", "audio/ogg", "video/ogg", - "audio/x-m4a", + "audio/mp4", "video/mp4", "video/quicktime", "audio/x-ms-wma", @@ -939,7 +939,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch9() { "image/apng", "audio/ogg", "video/ogg", - "audio/x-m4a", + "audio/mp4", "video/mp4", "video/quicktime", "audio/x-ms-wma", diff --git a/internal/media/ffmpeg.go b/internal/media/ffmpeg.go index 976662e60..1d7b01905 100644 --- a/internal/media/ffmpeg.go +++ b/internal/media/ffmpeg.go @@ -323,14 +323,14 @@ type videoStream struct { // // Note the checks for (len(res.video) > 0) may catch some audio files with embedded // album art as video, but i blame that on the hellscape that is media filetypes. -// -// TODO: we can update this code to also return a mimetype and avoid later parsing! -func (res *result) GetFileType() (gtsmodel.FileType, string) { +func (res *result) GetFileType() (gtsmodel.FileType, string, string) { switch res.format { case "mpeg": - return gtsmodel.FileTypeVideo, "mpeg" + return gtsmodel.FileTypeVideo, + "video/mpeg", "mpeg" case "mjpeg": - return gtsmodel.FileTypeVideo, "mjpeg" + return gtsmodel.FileTypeVideo, + "video/x-motion-jpeg", "mjpeg" case "mov,mp4,m4a,3gp,3g2,mj2": switch { case len(res.video) > 0: @@ -338,55 +338,70 @@ func (res *result) GetFileType() (gtsmodel.FileType, string) { res.duration <= 30 { // Short, soundless // video file aka gifv. - return gtsmodel.FileTypeGifv, "mp4" + return gtsmodel.FileTypeGifv, + "video/mp4", "mp4" } else { // Video file (with or without audio). - return gtsmodel.FileTypeVideo, "mp4" + return gtsmodel.FileTypeVideo, + "video/mp4", "mp4" } case len(res.audio) > 0 && res.audio[0].codec == "aac": // m4a only supports [aac] audio. - return gtsmodel.FileTypeAudio, "m4a" + return gtsmodel.FileTypeAudio, + "audio/mp4", "m4a" } case "apng": - return gtsmodel.FileTypeImage, "apng" + return gtsmodel.FileTypeImage, + "image/apng", "apng" case "png_pipe": - return gtsmodel.FileTypeImage, "png" + return gtsmodel.FileTypeImage, + "image/png", "png" case "image2", "image2pipe", "jpeg_pipe": - return gtsmodel.FileTypeImage, "jpeg" + return gtsmodel.FileTypeImage, + "image/jpeg", "jpeg" case "webp", "webp_pipe": - return gtsmodel.FileTypeImage, "webp" + return gtsmodel.FileTypeImage, + "image/webp", "webp" case "gif": - return gtsmodel.FileTypeImage, "gif" + return gtsmodel.FileTypeImage, + "image/gif", "gif" case "mp3": if len(res.audio) > 0 { switch res.audio[0].codec { case "mp2": - return gtsmodel.FileTypeAudio, "mp2" + return gtsmodel.FileTypeAudio, + "audio/mp2", "mp2" case "mp3": - return gtsmodel.FileTypeAudio, "mp3" + return gtsmodel.FileTypeAudio, + "audio/mp3", "mp3" } } case "asf": switch { case len(res.video) > 0: - return gtsmodel.FileTypeVideo, "wmv" + return gtsmodel.FileTypeVideo, + "video/x-ms-wmv", "wmv" case len(res.audio) > 0: - return gtsmodel.FileTypeAudio, "wma" + return gtsmodel.FileTypeAudio, + "audio/x-ms-wma", "wma" } case "ogg": if len(res.video) > 0 { switch res.video[0].codec { case "theora", "dirac": // daala, tarkin - return gtsmodel.FileTypeVideo, "ogv" + return gtsmodel.FileTypeVideo, + "video/ogg", "ogv" } } if len(res.audio) > 0 { switch res.audio[0].codec { case "opus", "libopus": - return gtsmodel.FileTypeAudio, "opus" + return gtsmodel.FileTypeAudio, + "audio/opus", "opus" default: - return gtsmodel.FileTypeAudio, "ogg" + return gtsmodel.FileTypeAudio, + "audio/ogg", "ogg" } } case "matroska,webm": @@ -411,21 +426,27 @@ func (res *result) GetFileType() (gtsmodel.FileType, string) { } if isWebm { - // Check for valid webm codec config. - return gtsmodel.FileTypeVideo, "webm" + // Check valid webm codec config. + return gtsmodel.FileTypeVideo, + "video/webm", "webm" } // All else falls under generic mkv. - return gtsmodel.FileTypeVideo, "mkv" + return gtsmodel.FileTypeVideo, + "video/x-matroska", "mkv" case len(res.audio) > 0: - return gtsmodel.FileTypeAudio, "mka" + return gtsmodel.FileTypeAudio, + "audio/x-matroska", "mka" } case "avi": - return gtsmodel.FileTypeVideo, "avi" + return gtsmodel.FileTypeVideo, + "video/x-msvideo", "avi" case "flac": - return gtsmodel.FileTypeAudio, "flac" + return gtsmodel.FileTypeAudio, + "audio/flac", "flac" } - return gtsmodel.FileTypeUnknown, res.format + return gtsmodel.FileTypeUnknown, + "", res.format } // ImageMeta extracts image metadata contained within ffprobe'd media result streams. diff --git a/internal/media/manager.go b/internal/media/manager.go index 22afd0028..2807848bd 100644 --- a/internal/media/manager.go +++ b/internal/media/manager.go @@ -56,7 +56,7 @@ var SupportedMIMETypes = []string{ "video/ogg", // .ogv // mpeg4 types - "audio/x-m4a", // .m4a + "audio/mp4", // .m4a "video/mp4", // .mp4 "video/quicktime", // .mov diff --git a/internal/media/manager_test.go b/internal/media/manager_test.go index c281b1000..e175369f5 100644 --- a/internal/media/manager_test.go +++ b/internal/media/manager_test.go @@ -664,7 +664,7 @@ func (suite *ManagerTestSuite) TestOpusProcess() { Duration: util.Ptr(float32(122.10006)), Bitrate: util.Ptr(uint64(116426)), }, attachment.FileMeta.Original) - suite.Equal("audio/ogg", attachment.File.ContentType) + suite.Equal("audio/opus", attachment.File.ContentType) suite.Equal(1776956, attachment.File.FileSize) suite.Empty(attachment.Blurhash) diff --git a/internal/media/processingemoji.go b/internal/media/processingemoji.go index 750144296..95c224cda 100644 --- a/internal/media/processingemoji.go +++ b/internal/media/processingemoji.go @@ -163,9 +163,10 @@ func (p *ProcessingEmoji) store(ctx context.Context) error { } var ext string + var fileType gtsmodel.FileType - // Get type from ffprobe format data. - fileType, ext := result.GetFileType() + // Get abstract file type, mimetype and ext from ffprobe data. + fileType, p.emoji.ImageContentType, ext = result.GetFileType() if fileType != gtsmodel.FileTypeImage { return gtserror.Newf("unsupported emoji filetype: %s (%s)", fileType, ext) } @@ -216,10 +217,6 @@ func (p *ProcessingEmoji) store(ctx context.Context) error { "png", ) - // Get mimetype for the file container - // type, falling back to generic data. - p.emoji.ImageContentType = getMimeType(ext) - // Set the known emoji static content type. p.emoji.ImageStaticContentType = "image/png" diff --git a/internal/media/processingmedia.go b/internal/media/processingmedia.go index 4c6670b06..894975a1b 100644 --- a/internal/media/processingmedia.go +++ b/internal/media/processingmedia.go @@ -186,8 +186,8 @@ func (p *ProcessingMedia) store(ctx context.Context) error { p.media.FileMeta.Original.Duration = util.PtrIf(float32(result.duration)) p.media.FileMeta.Original.Bitrate = util.PtrIf(result.bitrate) - // Set media type from ffprobe format data. - p.media.Type, ext = result.GetFileType() + // Set generic media type and mimetype from ffprobe format data. + p.media.Type, p.media.File.ContentType, ext = result.GetFileType() // Add file extension to path. newpath := temppath + "." + ext @@ -236,10 +236,10 @@ func (p *ProcessingMedia) store(ctx context.Context) error { // Determine if blurhash needs generating. needBlurhash := (p.media.Blurhash == "") - var newBlurhash string + var newBlurhash, mimeType string - // Generate thumbnail, and new blurhash if need from media. - thumbpath, newBlurhash, err = generateThumb(ctx, temppath, + // Generate thumbnail, and new blurhash if needed from temp media. + thumbpath, mimeType, newBlurhash, err = generateThumb(ctx, temppath, thumbWidth, thumbHeight, result.orientation, @@ -250,6 +250,9 @@ func (p *ProcessingMedia) store(ctx context.Context) error { return gtserror.Newf("error generating image thumb: %w", err) } + // Set generated thumbnail's mimetype. + p.media.Thumbnail.ContentType = mimeType + if needBlurhash { // Set newly determined blurhash. p.media.Blurhash = newBlurhash @@ -265,10 +268,6 @@ func (p *ProcessingMedia) store(ctx context.Context) error { ext, ) - // Get mimetype for the file container - // type, falling back to generic data. - p.media.File.ContentType = getMimeType(ext) - // Copy temporary file into storage at path. filesz, err := p.mgr.state.Storage.PutFile(ctx, p.media.File.Path, @@ -295,9 +294,6 @@ func (p *ProcessingMedia) store(ctx context.Context) error { thumbExt, ) - // Determine thumbnail content-type from thumb ext. - p.media.Thumbnail.ContentType = getMimeType(thumbExt) - // Copy thumbnail file into storage at path. thumbsz, err := p.mgr.state.Storage.PutFile(ctx, p.media.Thumbnail.Path, diff --git a/internal/media/thumbnail.go b/internal/media/thumbnail.go index 322af8d7e..f1c7c678e 100644 --- a/internal/media/thumbnail.go +++ b/internal/media/thumbnail.go @@ -84,17 +84,21 @@ func generateThumb( needBlurhash bool, ) ( outpath string, + mimeType string, blurhash string, err error, ) { var ext string + // Default type is webp. + mimeType = "image/webp" + // Generate thumb output path REPLACING extension. if i := strings.IndexByte(filepath, '.'); i != -1 { outpath = filepath[:i] + "_thumb.webp" ext = filepath[i+1:] // old extension } else { - return "", "", gtserror.New("input file missing extension") + return "", "", "", gtserror.New("input file missing extension") } // Check for the few media types we @@ -106,6 +110,7 @@ func generateThumb( // Replace the "webp" with "jpeg", as we'll // use our native Go thumbnailing generation. outpath = outpath[:len(outpath)-4] + "jpeg" + mimeType = "image/jpeg" log.Debug(ctx, "generating thumb from jpeg") blurhash, err := generateNativeThumb( @@ -117,7 +122,7 @@ func generateThumb( jpeg.Decode, needBlurhash, ) - return outpath, blurhash, err + return outpath, mimeType, blurhash, err // We specifically only allow generating native // thumbnails from gif IF it doesn't contain an @@ -128,6 +133,7 @@ func generateThumb( // Replace the "webp" with "jpeg", as we'll // use our native Go thumbnailing generation. outpath = outpath[:len(outpath)-4] + "jpeg" + mimeType = "image/jpeg" log.Debug(ctx, "generating thumb from gif") blurhash, err := generateNativeThumb( @@ -139,7 +145,7 @@ func generateThumb( gif.Decode, needBlurhash, ) - return outpath, blurhash, err + return outpath, mimeType, blurhash, err // We specifically only allow generating native // thumbnails from png IF it doesn't contain an @@ -150,6 +156,7 @@ func generateThumb( // Replace the "webp" with "jpeg", as we'll // use our native Go thumbnailing generation. outpath = outpath[:len(outpath)-4] + "jpeg" + mimeType = "image/jpeg" log.Debug(ctx, "generating thumb from png") blurhash, err := generateNativeThumb( @@ -161,7 +168,7 @@ func generateThumb( png.Decode, needBlurhash, ) - return outpath, blurhash, err + return outpath, mimeType, blurhash, err // We specifically only allow generating native // thumbnails from webp IF it doesn't contain an @@ -172,6 +179,7 @@ func generateThumb( // Replace the "webp" with "jpeg", as we'll // use our native Go thumbnailing generation. outpath = outpath[:len(outpath)-4] + "jpeg" + mimeType = "image/jpeg" log.Debug(ctx, "generating thumb from webp") blurhash, err := generateNativeThumb( @@ -183,7 +191,7 @@ func generateThumb( webp.Decode, needBlurhash, ) - return outpath, blurhash, err + return outpath, mimeType, blurhash, err } // The fallback for thumbnail generation, which @@ -196,18 +204,18 @@ func generateThumb( height, pixfmt, ); err != nil { - return outpath, "", err + return outpath, "", "", err } if needBlurhash { // Generate new blurhash from webp output thumb. blurhash, err = generateWebpBlurhash(outpath) if err != nil { - return outpath, "", gtserror.Newf("error generating blurhash: %w", err) + return outpath, "", "", gtserror.Newf("error generating blurhash: %w", err) } } - return outpath, blurhash, err + return outpath, mimeType, blurhash, nil } // generateNativeThumb generates a thumbnail diff --git a/internal/media/util.go b/internal/media/util.go index f6bf06260..4e47955ad 100644 --- a/internal/media/util.go +++ b/internal/media/util.go @@ -18,7 +18,6 @@ package media import ( - "cmp" "errors" "fmt" "io" @@ -28,7 +27,6 @@ import ( "codeberg.org/gruf/go-bytesize" "codeberg.org/gruf/go-iotools" - "codeberg.org/gruf/go-mimetypes" "github.com/superseriousbusiness/gotosocial/internal/gtserror" ) @@ -87,12 +85,6 @@ func getExtension(path string) string { return "" } -// getMimeType returns a suitable mimetype for file extension. -func getMimeType(ext string) string { - const defaultType = "application/octet-stream" - return cmp.Or(mimetypes.MimeTypes[ext], defaultType) -} - // drainToTmp drains data from given reader into a new temp file // and closes it, returning the path of the resulting temp file. // diff --git a/internal/typeutils/internaltofrontend_test.go b/internal/typeutils/internaltofrontend_test.go index a01060ebc..cf11655ca 100644 --- a/internal/typeutils/internaltofrontend_test.go +++ b/internal/typeutils/internaltofrontend_test.go @@ -1958,7 +1958,7 @@ func (suite *InternalToFrontendTestSuite) TestInstanceV1ToFrontend() { "image/apng", "audio/ogg", "video/ogg", - "audio/x-m4a", + "audio/mp4", "video/mp4", "video/quicktime", "audio/x-ms-wma", @@ -2103,7 +2103,7 @@ func (suite *InternalToFrontendTestSuite) TestInstanceV2ToFrontend() { "image/apng", "audio/ogg", "video/ogg", - "audio/x-m4a", + "audio/mp4", "video/mp4", "video/quicktime", "audio/x-ms-wma", |