Spaces:
Running
Running
File size: 3,385 Bytes
750bbe6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | package audio
import (
"io"
"os"
"path/filepath"
"strings"
"github.com/dhowden/tag"
"github.com/mudler/xlog"
)
// extensionFromFileType returns the file extension for tag.FileType.
func extensionFromFileType(ft tag.FileType) string {
switch ft {
case tag.FLAC:
return "flac"
case tag.MP3:
return "mp3"
case tag.OGG:
return "ogg"
case tag.M4A:
return "m4a"
case tag.M4B:
return "m4b"
case tag.M4P:
return "m4p"
case tag.ALAC:
return "m4a"
case tag.DSF:
return "dsf"
default:
return ""
}
}
// contentTypeFromFileType returns the MIME type for tag.FileType.
func contentTypeFromFileType(ft tag.FileType) string {
switch ft {
case tag.FLAC:
return "audio/flac"
case tag.MP3:
return "audio/mpeg"
case tag.OGG:
return "audio/ogg"
case tag.M4A, tag.M4B, tag.M4P, tag.ALAC:
return "audio/mp4"
case tag.DSF:
return "audio/dsd"
default:
return ""
}
}
// Identify reads from r and returns the detected audio extension and Content-Type.
// It uses github.com/dhowden/tag to identify the format from the stream.
// Returns ("", "", err) if the format could not be identified.
func Identify(r io.ReadSeeker) (ext string, contentType string, err error) {
_, fileType, err := tag.Identify(r)
if err != nil || fileType == tag.UnknownFileType {
return "", "", err
}
ext = extensionFromFileType(fileType)
contentType = contentTypeFromFileType(fileType)
if ext == "" || contentType == "" {
return "", "", nil
}
return ext, contentType, nil
}
// ContentTypeFromExtension returns the MIME type for common audio file extensions.
// Use as a fallback when Identify fails or when the file is not openable.
func ContentTypeFromExtension(path string) string {
ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(path), "."))
switch ext {
case "flac":
return "audio/flac"
case "mp3":
return "audio/mpeg"
case "wav":
return "audio/wav"
case "ogg":
return "audio/ogg"
case "m4a", "m4b", "m4p":
return "audio/mp4"
case "webm":
return "audio/webm"
default:
return ""
}
}
// NormalizeAudioFile opens the file at path, identifies its format with tag.Identify,
// and renames the file to have the correct extension if the current one does not match.
// It returns the path to use (possibly the renamed file) and the Content-Type to set.
// If identification fails, returns (path, ContentTypeFromExtension(path)).
func NormalizeAudioFile(path string) (finalPath string, contentType string) {
finalPath = path
f, err := os.Open(path)
if err != nil {
contentType = ContentTypeFromExtension(path)
return finalPath, contentType
}
defer f.Close()
ext, ct, identifyErr := Identify(f)
if identifyErr != nil || ext == "" || ct == "" {
contentType = ContentTypeFromExtension(path)
return finalPath, contentType
}
contentType = ct
currentExt := strings.ToLower(strings.TrimPrefix(filepath.Ext(path), "."))
if currentExt == ext {
return finalPath, contentType
}
dir := filepath.Dir(path)
base := filepath.Base(path)
baseNoExt := strings.TrimSuffix(base, filepath.Ext(base))
if baseNoExt == "" {
baseNoExt = base
}
newPath := filepath.Join(dir, baseNoExt+"."+ext)
if renameErr := os.Rename(path, newPath); renameErr != nil {
xlog.Debug("Could not rename audio file to match type", "from", path, "to", newPath, "error", renameErr)
return finalPath, contentType
}
return newPath, contentType
}
|