Skip to content

Commit

Permalink
[bugfix] determine mime-type to use during ffprobe evaluation stage, …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
NyaaaWhatsUpDoc authored Nov 4, 2024
1 parent d2820a1 commit 8f288f1
Show file tree
Hide file tree
Showing 16 changed files with 85 additions and 1,378 deletions.
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ require (
codeberg.org/gruf/go-kv v1.6.5
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760
codeberg.org/gruf/go-mimetypes v1.2.0
codeberg.org/gruf/go-mutexes v1.5.1
codeberg.org/gruf/go-runners v1.6.3
codeberg.org/gruf/go-sched v1.2.4
Expand Down
2 changes: 0 additions & 2 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions internal/api/client/instance/instancepatch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
75 changes: 48 additions & 27 deletions internal/media/ffmpeg.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,70 +323,85 @@ 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:
if len(res.audio) == 0 &&
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":
Expand All @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion internal/media/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion internal/media/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
9 changes: 3 additions & 6 deletions internal/media/processingemoji.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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"

Expand Down
20 changes: 8 additions & 12 deletions internal/media/processingmedia.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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,
Expand All @@ -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,
Expand Down
Loading

0 comments on commit 8f288f1

Please sign in to comment.