diff --git a/thumbnailing/i/flac.go b/thumbnailing/i/flac.go
index c7f73995d2e1ad03e8ec9386debe4a14c3834824..213511cdd31ab1cb7dd70022a3c92f7b6cde6493 100644
--- a/thumbnailing/i/flac.go
+++ b/thumbnailing/i/flac.go
@@ -3,6 +3,7 @@ package i
 import (
 	"errors"
 
+	"github.com/faiface/beep"
 	"github.com/faiface/beep/flac"
 	"github.com/turt2live/matrix-media-repo/common/rcontext"
 	"github.com/turt2live/matrix-media-repo/thumbnailing/m"
@@ -24,10 +25,18 @@ func (d flacGenerator) matches(img []byte, contentType string) bool {
 	return contentType == "audio/flac"
 }
 
-func (d flacGenerator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) {
+func (d flacGenerator) decode(b []byte) (beep.StreamSeekCloser, beep.Format, error) {
 	audio, format, err := flac.Decode(util.ByteCloser(b))
 	if err != nil {
-		return nil, errors.New("flac: error decoding audio: " + err.Error())
+		return audio, format, errors.New("flac: error decoding audio: " + err.Error())
+	}
+	return audio, format, nil
+}
+
+func (d flacGenerator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) {
+	audio, format, err := d.decode(b)
+	if err != nil {
+		return nil, err
 	}
 
 	defer audio.Close()
@@ -35,9 +44,9 @@ func (d flacGenerator) GenerateThumbnail(b []byte, contentType string, width int
 }
 
 func (d flacGenerator) GetAudioData(b []byte, nKeys int, ctx rcontext.RequestContext) (*m.AudioInfo, error) {
-	audio, format, err := flac.Decode(util.ByteCloser(b))
+	audio, format, err := d.decode(b)
 	if err != nil {
-		return nil, errors.New("flac: error decoding audio: " + err.Error())
+		return nil, err
 	}
 
 	defer audio.Close()
diff --git a/thumbnailing/i/mp3.go b/thumbnailing/i/mp3.go
index c25c3d77259d94addd9902887089c7b6650cccf0..2a9c8eb9724f01afc73e1aacf5365fb0465053db 100644
--- a/thumbnailing/i/mp3.go
+++ b/thumbnailing/i/mp3.go
@@ -32,10 +32,18 @@ func (d mp3Generator) matches(img []byte, contentType string) bool {
 	return contentType == "audio/mpeg"
 }
 
-func (d mp3Generator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) {
+func (d mp3Generator) decode(b []byte) (beep.StreamSeekCloser, beep.Format, error) {
 	audio, format, err := mp3.Decode(util.ByteCloser(b))
 	if err != nil {
-		return nil, errors.New("mp3: error decoding audio: " + err.Error())
+		return audio, format, errors.New("mp3: error decoding audio: " + err.Error())
+	}
+	return audio, format, nil
+}
+
+func (d mp3Generator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) {
+	audio, format, err := d.decode(b)
+	if err != nil {
+		return nil, err
 	}
 
 	defer audio.Close()
@@ -43,9 +51,9 @@ func (d mp3Generator) GenerateThumbnail(b []byte, contentType string, width int,
 }
 
 func (d mp3Generator) GetAudioData(b []byte, nKeys int, ctx rcontext.RequestContext) (*m.AudioInfo, error) {
-	audio, format, err := mp3.Decode(util.ByteCloser(b))
+	audio, format, err := d.decode(b)
 	if err != nil {
-		return nil, errors.New("mp3: error decoding audio: " + err.Error())
+		return nil, err
 	}
 
 	defer audio.Close()
diff --git a/thumbnailing/i/ogg.go b/thumbnailing/i/ogg.go
index dec2d9696869d75803f84819360098bdfdba94cb..18c29d0f77deac72e337dab6c32de14730452b11 100644
--- a/thumbnailing/i/ogg.go
+++ b/thumbnailing/i/ogg.go
@@ -3,6 +3,7 @@ package i
 import (
 	"errors"
 
+	"github.com/faiface/beep"
 	"github.com/faiface/beep/vorbis"
 	"github.com/turt2live/matrix-media-repo/common/rcontext"
 	"github.com/turt2live/matrix-media-repo/thumbnailing/m"
@@ -24,10 +25,18 @@ func (d oggGenerator) matches(img []byte, contentType string) bool {
 	return contentType == "audio/ogg"
 }
 
-func (d oggGenerator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) {
+func (d oggGenerator) decode(b []byte) (beep.StreamSeekCloser, beep.Format, error) {
 	audio, format, err := vorbis.Decode(util.ByteCloser(b))
 	if err != nil {
-		return nil, errors.New("ogg: error decoding audio: " + err.Error())
+		return audio, format, errors.New("ogg: error decoding audio: " + err.Error())
+	}
+	return audio, format, nil
+}
+
+func (d oggGenerator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) {
+	audio, format, err := d.decode(b)
+	if err != nil {
+		return nil, err
 	}
 
 	defer audio.Close()
@@ -35,9 +44,9 @@ func (d oggGenerator) GenerateThumbnail(b []byte, contentType string, width int,
 }
 
 func (d oggGenerator) GetAudioData(b []byte, nKeys int, ctx rcontext.RequestContext) (*m.AudioInfo, error) {
-	audio, format, err := vorbis.Decode(util.ByteCloser(b))
+	audio, format, err := d.decode(b)
 	if err != nil {
-		return nil, errors.New("ogg: error decoding audio: " + err.Error())
+		return nil, err
 	}
 
 	defer audio.Close()
diff --git a/thumbnailing/i/wav.go b/thumbnailing/i/wav.go
index ac34f2140fe58b8025816a7a12f9c153354bc9f1..677375fbe9a57be8005f917425e37eca11f588dc 100644
--- a/thumbnailing/i/wav.go
+++ b/thumbnailing/i/wav.go
@@ -3,6 +3,7 @@ package i
 import (
 	"errors"
 
+	"github.com/faiface/beep"
 	"github.com/faiface/beep/wav"
 	"github.com/turt2live/matrix-media-repo/common/rcontext"
 	"github.com/turt2live/matrix-media-repo/thumbnailing/m"
@@ -24,10 +25,18 @@ func (d wavGenerator) matches(img []byte, contentType string) bool {
 	return contentType == "audio/wav"
 }
 
-func (d wavGenerator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) {
+func (d wavGenerator) decode(b []byte) (beep.StreamSeekCloser, beep.Format, error) {
 	audio, format, err := wav.Decode(util.ByteCloser(b))
 	if err != nil {
-		return nil, errors.New("wav: error decoding audio: " + err.Error())
+		return audio, format, errors.New("wav: error decoding audio: " + err.Error())
+	}
+	return audio, format, nil
+}
+
+func (d wavGenerator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) {
+	audio, format, err := d.decode(b)
+	if err != nil {
+		return nil, err
 	}
 
 	defer audio.Close()
@@ -35,9 +44,9 @@ func (d wavGenerator) GenerateThumbnail(b []byte, contentType string, width int,
 }
 
 func (d wavGenerator) GetAudioData(b []byte, nKeys int, ctx rcontext.RequestContext) (*m.AudioInfo, error) {
-	audio, format, err := wav.Decode(util.ByteCloser(b))
+	audio, format, err := d.decode(b)
 	if err != nil {
-		return nil, errors.New("wav: error decoding audio: " + err.Error())
+		return nil, err
 	}
 
 	defer audio.Close()