feat: release v0.1.3 chat, profiles, and media
Keep read receipts for the other person only, and let photos, voice, and files stay cached until they are actually replaced.
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package storage
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestVoiceNoteContentType(t *testing.T) {
|
||||
if got := mimeType("chats/2-1.weba"); got != "audio/webm" {
|
||||
t.Fatalf("weba: %s", got)
|
||||
}
|
||||
if got := mediaContentType("chats/2-1.weba", "application/octet-stream"); got != "audio/webm" {
|
||||
t.Fatalf("generic store type must not hide the voice type: %s", got)
|
||||
}
|
||||
if got := mediaContentType("chats/2-1.bin", "application/pdf"); got != "application/pdf" {
|
||||
t.Fatalf("unknown extension keeps the stored type: %s", got)
|
||||
}
|
||||
}
|
||||
@@ -243,10 +243,11 @@ func (s *S3) Serve(w http.ResponseWriter, r *http.Request, key string) error {
|
||||
}
|
||||
defer result.Body.Close()
|
||||
|
||||
ct := mimeType(key)
|
||||
if result.ContentType != nil && *result.ContentType != "" {
|
||||
ct = *result.ContentType
|
||||
stored := ""
|
||||
if result.ContentType != nil {
|
||||
stored = *result.ContentType
|
||||
}
|
||||
ct := mediaContentType(key, stored)
|
||||
w.Header().Set("Content-Type", ct)
|
||||
setInlineMediaHeaders(w, ct)
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
@@ -290,8 +291,20 @@ func mimeType(key string) string {
|
||||
return "video/mp4"
|
||||
case ".webm":
|
||||
return "video/webm"
|
||||
case ".weba":
|
||||
return "audio/webm"
|
||||
case ".mp3":
|
||||
return "audio/mpeg"
|
||||
case ".wav":
|
||||
return "audio/wav"
|
||||
case ".ogg", ".opus":
|
||||
return "audio/ogg"
|
||||
case ".m4a", ".aac":
|
||||
return "audio/mp4"
|
||||
case ".mov":
|
||||
return "video/quicktime"
|
||||
case ".m4v":
|
||||
return "video/mp4"
|
||||
case ".pdf":
|
||||
return "application/pdf"
|
||||
default:
|
||||
@@ -299,6 +312,23 @@ func mimeType(key string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// mediaContentType keeps a known extension ahead of a generic object-store type.
|
||||
// Voice notes are stored as .weba; a default octet-stream plus nosniff stops playback.
|
||||
func mediaContentType(key, stored string) string {
|
||||
guessed := mimeType(key)
|
||||
if guessed != "application/octet-stream" {
|
||||
return guessed
|
||||
}
|
||||
stored = strings.TrimSpace(stored)
|
||||
if i := strings.Index(stored, ";"); i >= 0 {
|
||||
stored = strings.TrimSpace(stored[:i])
|
||||
}
|
||||
if stored != "" {
|
||||
return stored
|
||||
}
|
||||
return guessed
|
||||
}
|
||||
|
||||
// setInlineMediaHeaders discourages "Save as" download UX while keeping streaming/Range intact.
|
||||
func setInlineMediaHeaders(w http.ResponseWriter, contentType string) {
|
||||
if contentType != "" {
|
||||
|
||||
Reference in New Issue
Block a user