Skip to content

Commit

Permalink
[feature/frontend] Add player for audio files; use thumbnail for `pos…
Browse files Browse the repository at this point in the history
…ter` (#3099)

* [feature/frontend] Audio player for audio media types

* use video preview images for previews instead of video itself

* don't preload

* update tests for new zork status

* collapse media gallery into single row when small
  • Loading branch information
tsmethurst authored Jul 15, 2024
1 parent 16421f7 commit 9efb11d
Show file tree
Hide file tree
Showing 26 changed files with 327 additions and 95 deletions.
6 changes: 3 additions & 3 deletions internal/api/activitypub/users/outboxget_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (suite *OutboxGetTestSuite) TestGetOutbox() {
"@context": "https://www.w3.org/ns/activitystreams",
"first": "http://localhost:8080/users/the_mighty_zork/outbox?limit=40",
"id": "http://localhost:8080/users/the_mighty_zork/outbox",
"totalItems": 7,
"totalItems": 8,
"type": "OrderedCollection"
}`, dst.String())

Expand Down Expand Up @@ -161,7 +161,7 @@ func (suite *OutboxGetTestSuite) TestGetOutboxFirstPage() {
],
"partOf": "http://localhost:8080/users/the_mighty_zork/outbox",
"prev": "http://localhost:8080/users/the_mighty_zork/outbox?limit=40\u0026min_id=01HH9KYNQPA416TNJ53NSATP40",
"totalItems": 7,
"totalItems": 8,
"type": "OrderedCollectionPage"
}`, dst.String())

Expand Down Expand Up @@ -224,7 +224,7 @@ func (suite *OutboxGetTestSuite) TestGetOutboxNextPage() {
"id": "http://localhost:8080/users/the_mighty_zork/outbox?limit=40&max_id=01F8MHAMCHF6Y650WCRSCP4WMY",
"orderedItems": [],
"partOf": "http://localhost:8080/users/the_mighty_zork/outbox",
"totalItems": 7,
"totalItems": 8,
"type": "OrderedCollectionPage"
}`, dst.String())

Expand Down
2 changes: 1 addition & 1 deletion internal/api/client/accounts/accountverify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (suite *AccountVerifyTestSuite) TestAccountVerifyGet() {
suite.Equal("http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", apimodelAccount.HeaderStatic)
suite.Equal(2, apimodelAccount.FollowersCount)
suite.Equal(2, apimodelAccount.FollowingCount)
suite.Equal(7, apimodelAccount.StatusesCount)
suite.Equal(8, apimodelAccount.StatusesCount)
suite.EqualValues(gtsmodel.VisibilityPublic, apimodelAccount.Source.Privacy)
suite.Equal(testAccount.Settings.Language, apimodelAccount.Source.Language)
suite.Equal(testAccount.NoteRaw, apimodelAccount.Source.Note)
Expand Down
4 changes: 2 additions & 2 deletions internal/api/client/admin/accountsgetv2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,8 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"followers_count": 2,
"following_count": 2,
"statuses_count": 7,
"last_status_at": "2023-12-10T09:24:00.000Z",
"statuses_count": 8,
"last_status_at": "2024-01-10T09:24:00.000Z",
"emojis": [],
"fields": [],
"enable_rss": true,
Expand Down
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 @@ -135,7 +135,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch1() {
},
"stats": {
"domain_count": 2,
"status_count": 19,
"status_count": 20,
"user_count": 4
},
"thumbnail": "http://localhost:8080/assets/logo.png",
Expand Down Expand Up @@ -256,7 +256,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch2() {
},
"stats": {
"domain_count": 2,
"status_count": 19,
"status_count": 20,
"user_count": 4
},
"thumbnail": "http://localhost:8080/assets/logo.png",
Expand Down Expand Up @@ -377,7 +377,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch3() {
},
"stats": {
"domain_count": 2,
"status_count": 19,
"status_count": 20,
"user_count": 4
},
"thumbnail": "http://localhost:8080/assets/logo.png",
Expand Down Expand Up @@ -549,7 +549,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch6() {
},
"stats": {
"domain_count": 2,
"status_count": 19,
"status_count": 20,
"user_count": 4
},
"thumbnail": "http://localhost:8080/assets/logo.png",
Expand Down Expand Up @@ -692,7 +692,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch8() {
},
"stats": {
"domain_count": 2,
"status_count": 19,
"status_count": 20,
"user_count": 4
},
"thumbnail": "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/attachment/original/`+instanceAccount.AvatarMediaAttachment.ID+`.gif",`+`
Expand Down Expand Up @@ -850,7 +850,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch9() {
},
"stats": {
"domain_count": 2,
"status_count": 19,
"status_count": 20,
"user_count": 4
},
"thumbnail": "http://localhost:8080/assets/logo.png",
Expand Down
6 changes: 3 additions & 3 deletions internal/api/client/search/searchget_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ func (suite *SearchGetTestSuite) TestSearchAAny() {
}

suite.Len(searchResult.Accounts, 5)
suite.Len(searchResult.Statuses, 6)
suite.Len(searchResult.Statuses, 7)
suite.Len(searchResult.Hashtags, 0)
}

Expand Down Expand Up @@ -959,7 +959,7 @@ func (suite *SearchGetTestSuite) TestSearchAAnyFollowingOnly() {
}

suite.Len(searchResult.Accounts, 2)
suite.Len(searchResult.Statuses, 6)
suite.Len(searchResult.Statuses, 7)
suite.Len(searchResult.Hashtags, 0)
}

Expand Down Expand Up @@ -1002,7 +1002,7 @@ func (suite *SearchGetTestSuite) TestSearchAStatuses() {
}

suite.Len(searchResult.Accounts, 0)
suite.Len(searchResult.Statuses, 6)
suite.Len(searchResult.Statuses, 7)
suite.Len(searchResult.Hashtags, 0)
}

Expand Down
4 changes: 2 additions & 2 deletions internal/api/client/statuses/statushistory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ func (suite *StatusHistoryTestSuite) TestGetHistory() {
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"followers_count": 2,
"following_count": 2,
"statuses_count": 7,
"last_status_at": "2023-12-10T09:24:00.000Z",
"statuses_count": 8,
"last_status_at": "2024-01-10T09:24:00.000Z",
"emojis": [],
"fields": [],
"enable_rss": true,
Expand Down
8 changes: 4 additions & 4 deletions internal/api/client/statuses/statusmute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ func (suite *StatusMuteTestSuite) TestMuteUnmuteStatus() {
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"followers_count": 2,
"following_count": 2,
"statuses_count": 7,
"last_status_at": "2023-12-10T09:24:00.000Z",
"statuses_count": 8,
"last_status_at": "2024-01-10T09:24:00.000Z",
"emojis": [],
"fields": [],
"enable_rss": true,
Expand Down Expand Up @@ -197,8 +197,8 @@ func (suite *StatusMuteTestSuite) TestMuteUnmuteStatus() {
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"followers_count": 2,
"following_count": 2,
"statuses_count": 7,
"last_status_at": "2023-12-10T09:24:00.000Z",
"statuses_count": 8,
"last_status_at": "2024-01-10T09:24:00.000Z",
"emojis": [],
"fields": [],
"enable_rss": true,
Expand Down
19 changes: 15 additions & 4 deletions internal/api/model/attachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,23 @@ type Attachment struct {
// A hash computed by the BlurHash algorithm, for generating colorful preview thumbnails when media has not been downloaded yet.
// See https://github.com/woltapp/blurhash
Blurhash *string `json:"blurhash"`
}

// WebAttachment is like Attachment, but with
// additional fields not exposed via JSON;
// used only internally for templating etc.
//
// swagger:ignore
type WebAttachment struct {
*Attachment

// Additional fields not exposed via JSON
// (used only internally for templating etc).
// Parent status of this
// media is sensitive.
Sensitive bool

// Parent status of this media is sensitive.
Sensitive bool `json:"-"`
// MIME type of
// the attachment.
MIMEType string
}

// MediaMeta models media metadata.
Expand Down
4 changes: 4 additions & 0 deletions internal/api/model/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ type Status struct {
type WebStatus struct {
*Status

// Web version of media
// attached to this status.
MediaAttachments []*WebAttachment `json:"media_attachments"`

// Template-ready language tag and
// string, based on *status.Language.
LanguageTag *language.Language
Expand Down
6 changes: 3 additions & 3 deletions internal/db/bundb/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type AccountTestSuite struct {
func (suite *AccountTestSuite) TestGetAccountStatuses() {
statuses, err := suite.db.GetAccountStatuses(context.Background(), suite.testAccounts["local_account_1"].ID, 20, false, false, "", "", false, false)
suite.NoError(err)
suite.Len(statuses, 7)
suite.Len(statuses, 8)
}

func (suite *AccountTestSuite) TestGetAccountStatusesPageDown() {
Expand All @@ -69,7 +69,7 @@ func (suite *AccountTestSuite) TestGetAccountStatusesPageDown() {
if err != nil {
suite.FailNow(err.Error())
}
suite.Len(statuses, 1)
suite.Len(statuses, 2)

// try to get the last page (should be empty)
statuses, err = suite.db.GetAccountStatuses(context.Background(), suite.testAccounts["local_account_1"].ID, 3, false, false, statuses[len(statuses)-1].ID, "", false, false)
Expand Down Expand Up @@ -187,7 +187,7 @@ func (suite *AccountTestSuite) TestGetAccountStatusesExcludeRepliesExcludesSelfR
func (suite *AccountTestSuite) TestGetAccountStatusesMediaOnly() {
statuses, err := suite.db.GetAccountStatuses(context.Background(), suite.testAccounts["local_account_1"].ID, 20, false, false, "", "", true, false)
suite.NoError(err)
suite.Len(statuses, 1)
suite.Len(statuses, 2)
}

func (suite *AccountTestSuite) TestGetAccountBy() {
Expand Down
2 changes: 1 addition & 1 deletion internal/db/bundb/basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func (suite *BasicTestSuite) TestGetAllStatuses() {
s := []*gtsmodel.Status{}
err := suite.db.GetAll(context.Background(), &s)
suite.NoError(err)
suite.Len(s, 23)
suite.Len(s, 24)
}

func (suite *BasicTestSuite) TestGetAllNotNull() {
Expand Down
2 changes: 1 addition & 1 deletion internal/db/bundb/instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (suite *InstanceTestSuite) TestCountInstanceUsersRemote() {
func (suite *InstanceTestSuite) TestCountInstanceStatuses() {
count, err := suite.db.CountInstanceStatuses(context.Background(), config.GetHost())
suite.NoError(err)
suite.Equal(19, count)
suite.Equal(20, count)
}

func (suite *InstanceTestSuite) TestCountInstanceStatusesRemote() {
Expand Down
7 changes: 1 addition & 6 deletions internal/db/bundb/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,7 @@ func (suite *StatusTestSuite) TestGetStatusChildren() {
targetStatus := suite.testStatuses["local_account_1_status_1"]
children, err := suite.db.GetStatusChildren(context.Background(), targetStatus.ID)
suite.NoError(err)
suite.Len(children, 2)
for _, c := range children {
suite.Equal(targetStatus.URI, c.InReplyToURI)
suite.Equal(targetStatus.AccountID, c.InReplyToAccountID)
suite.Equal(targetStatus.ID, c.InReplyToID)
}
suite.Len(children, 3)
}

func (suite *StatusTestSuite) TestDeleteStatus() {
Expand Down
10 changes: 5 additions & 5 deletions internal/db/bundb/timeline_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ func (suite *TimelineTestSuite) TestGetHomeTimeline() {
suite.FailNow(err.Error())
}

suite.checkStatuses(s, id.Highest, id.Lowest, 19)
suite.checkStatuses(s, id.Highest, id.Lowest, 20)
}

func (suite *TimelineTestSuite) TestGetHomeTimelineNoFollowing() {
Expand Down Expand Up @@ -187,7 +187,7 @@ func (suite *TimelineTestSuite) TestGetHomeTimelineNoFollowing() {
suite.FailNow(err.Error())
}

suite.checkStatuses(s, id.Highest, id.Lowest, 7)
suite.checkStatuses(s, id.Highest, id.Lowest, 8)
}

func (suite *TimelineTestSuite) TestGetHomeTimelineWithFutureStatus() {
Expand All @@ -209,7 +209,7 @@ func (suite *TimelineTestSuite) TestGetHomeTimelineWithFutureStatus() {
}

suite.NotContains(s, futureStatus)
suite.checkStatuses(s, id.Highest, id.Lowest, 19)
suite.checkStatuses(s, id.Highest, id.Lowest, 20)
}

func (suite *TimelineTestSuite) TestGetHomeTimelineBackToFront() {
Expand Down Expand Up @@ -240,8 +240,8 @@ func (suite *TimelineTestSuite) TestGetHomeTimelineFromHighest() {
}

suite.checkStatuses(s, id.Highest, id.Lowest, 5)
suite.Equal("01HH9KYNQPA416TNJ53NSATP40", s[0].ID)
suite.Equal("01G20ZM733MGN8J344T4ZDDFY1", s[len(s)-1].ID)
suite.Equal("01J2M1HPFSS54S60Y0KYV23KJE", s[0].ID)
suite.Equal("01G36SF3V6Y6V5BF9P4R7PQG7G", s[len(s)-1].ID)
}

func (suite *TimelineTestSuite) TestGetListTimelineNoParams() {
Expand Down
50 changes: 47 additions & 3 deletions internal/media/ffmpeg.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package media

import (
"cmp"
"context"
"encoding/json"
"errors"
Expand Down Expand Up @@ -198,6 +199,30 @@ func (res *ffprobeResult) ImageMeta() (width int, height int, err error) {
return
}

// EmbeddedImageMeta extracts embedded image metadata contained within ffprobe'd media result
// streams, should be used for pulling album image (can be animated image) from audio files.
func (res *ffprobeResult) EmbeddedImageMeta() (width int, height int, framerate float32, err error) {
for _, stream := range res.Streams {
if stream.Width > width {
width = stream.Width
}
if stream.Height > height {
height = stream.Height
}
if fr := stream.GetFrameRate(); fr > 0 {
if framerate == 0 || fr < framerate {
framerate = fr
}
}
}
// Need width + height but
// no framerate is fine.
if width == 0 || height == 0 {
err = errors.New("invalid image stream(s)")
}
return
}

// VideoMeta extracts video metadata contained within ffprobe'd media result streams.
func (res *ffprobeResult) VideoMeta() (width, height int, framerate float32, err error) {
for _, stream := range res.Streams {
Expand All @@ -222,14 +247,15 @@ func (res *ffprobeResult) VideoMeta() (width, height int, framerate float32, err
type ffprobeStream struct {
CodecName string `json:"codec_name"`
AvgFrameRate string `json:"avg_frame_rate"`
RFrameRate string `json:"r_frame_rate"`
Width int `json:"width"`
Height int `json:"height"`
// + unused fields.
}

// GetFrameRate calculates float32 framerate value from stream json string.
func (str *ffprobeStream) GetFrameRate() float32 {
if str.AvgFrameRate != "" {
numDen := func(strFR string) (float32, float32) {
var (
// numerator
num float32
Expand All @@ -239,7 +265,7 @@ func (str *ffprobeStream) GetFrameRate() float32 {
)

// Check for a provided inequality, i.e. numerator / denominator.
if p := strings.SplitN(str.AvgFrameRate, "/", 2); len(p) == 2 {
if p := strings.SplitN(strFR, "/", 2); len(p) == 2 {
n, _ := strconv.ParseFloat(p[0], 32)
d, _ := strconv.ParseFloat(p[1], 32)
num, den = float32(n), float32(d)
Expand All @@ -248,8 +274,26 @@ func (str *ffprobeStream) GetFrameRate() float32 {
num = float32(n)
}

return num / den
return num, den
}

var num, den float32
if str.AvgFrameRate != "" {
// Check if we have avg_frame_rate.
num, den = numDen(str.AvgFrameRate)
}

if num == 0 && str.RFrameRate != "" {
// Check if we have r_frame_rate.
num, den = numDen(str.RFrameRate)
}

if num != 0 {
// Found it.
// Avoid divide by zero.
return num / cmp.Or(den, 1)
}

return 0
}

Expand Down
Loading

0 comments on commit 9efb11d

Please sign in to comment.