[feature] use webp for thumbnails (#3116)
* update to use webp for thumbnails * bump webp quality up to 40% from 12% (it's a bit different to jpeg quality setting) * update to use yuva colorspace, and use thumbnail=n=10 to select frame * fix missing comma in ffmpeg args * add links to appropriate ffmpeg docs * update tests * add file size tests for thumbnails --------- Co-authored-by: tobi <tobi.smethurst@protonmail.com>
|
|
@ -382,7 +382,7 @@ func (suite *AccountUpdateTestSuite) TestUpdateAccountWithImageFormData() {
|
|||
// Can't predict IDs generated for new media
|
||||
// so just ensure it's different than before.
|
||||
suite.NotEqual("http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", apimodelAccount.Header)
|
||||
suite.NotEqual("http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", apimodelAccount.HeaderStatic)
|
||||
suite.NotEqual("http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp", apimodelAccount.HeaderStatic)
|
||||
}
|
||||
|
||||
func (suite *AccountUpdateTestSuite) TestUpdateAccountEmptyForm() {
|
||||
|
|
|
|||
|
|
@ -74,9 +74,9 @@ func (suite *AccountVerifyTestSuite) TestAccountVerifyGet() {
|
|||
suite.WithinDuration(testAccount.CreatedAt, createdAt, 30*time.Second) // we lose a bit of accuracy serializing so fuzz this a bit
|
||||
suite.Equal(testAccount.URL, apimodelAccount.URL)
|
||||
suite.Equal("http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg", apimodelAccount.Avatar)
|
||||
suite.Equal("http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg", apimodelAccount.AvatarStatic)
|
||||
suite.Equal("http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp", apimodelAccount.AvatarStatic)
|
||||
suite.Equal("http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", apimodelAccount.Header)
|
||||
suite.Equal("http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", apimodelAccount.HeaderStatic)
|
||||
suite.Equal("http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp", apimodelAccount.HeaderStatic)
|
||||
suite.Equal(2, apimodelAccount.FollowersCount)
|
||||
suite.Equal(2, apimodelAccount.FollowingCount)
|
||||
suite.Equal(8, apimodelAccount.StatusesCount)
|
||||
|
|
|
|||
|
|
@ -233,10 +233,10 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
|
|||
"note": "<p>hey yo this is my profile!</p>",
|
||||
"url": "http://localhost:8080/@the_mighty_zork",
|
||||
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
|
||||
"avatar_description": "a green goblin looking nasty",
|
||||
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
|
||||
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
|
||||
"followers_count": 2,
|
||||
"following_count": 2,
|
||||
|
|
@ -410,7 +410,7 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
|
|||
"avatar": "",
|
||||
"avatar_static": "",
|
||||
"header": "http://localhost:8080/fileserver/062G5WYKY35KKD12EMSM3F8PJ8/header/original/01PFPMWK2FF0D9WMHEJHR07C3R.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/062G5WYKY35KKD12EMSM3F8PJ8/header/small/01PFPMWK2FF0D9WMHEJHR07C3R.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/062G5WYKY35KKD12EMSM3F8PJ8/header/small/01PFPMWK2FF0D9WMHEJHR07C3R.webp",
|
||||
"header_description": "tweet from thoughts of dog: i drank. all the water. in my bowl. earlier. but just now. i returned. to the same bowl. and it was. full again.. the bowl. is haunted",
|
||||
"followers_count": 0,
|
||||
"following_count": 0,
|
||||
|
|
|
|||
|
|
@ -499,9 +499,9 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() {
|
|||
"type": "image",
|
||||
"url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"text_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.webp",
|
||||
"remote_url": "http://fossbros-anonymous.io/attachments/original/13bbc3f8-2b5e-46ea-9531-40b4974d9912.jpg",
|
||||
"preview_remote_url": "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpg",
|
||||
"preview_remote_url": null,
|
||||
"meta": {
|
||||
"original": {
|
||||
"width": 472,
|
||||
|
|
@ -521,7 +521,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() {
|
|||
}
|
||||
},
|
||||
"description": "tweet from thoughts of dog: i drank. all the water. in my bowl. earlier. but just now. i returned. to the same bowl. and it was. full again.. the bowl. is haunted",
|
||||
"blurhash": "LARysgM_IU_3~pD%M_Rj_39FIAt6"
|
||||
"blurhash": "L3Q9_@4n9E?axW4mD$Mx~q00Di%L"
|
||||
}
|
||||
],
|
||||
"mentions": [],
|
||||
|
|
@ -741,9 +741,9 @@ func (suite *ReportsGetTestSuite) TestReportsGetCreatedByAccount() {
|
|||
"type": "image",
|
||||
"url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"text_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.webp",
|
||||
"remote_url": "http://fossbros-anonymous.io/attachments/original/13bbc3f8-2b5e-46ea-9531-40b4974d9912.jpg",
|
||||
"preview_remote_url": "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpg",
|
||||
"preview_remote_url": null,
|
||||
"meta": {
|
||||
"original": {
|
||||
"width": 472,
|
||||
|
|
@ -763,7 +763,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetCreatedByAccount() {
|
|||
}
|
||||
},
|
||||
"description": "tweet from thoughts of dog: i drank. all the water. in my bowl. earlier. but just now. i returned. to the same bowl. and it was. full again.. the bowl. is haunted",
|
||||
"blurhash": "LARysgM_IU_3~pD%M_Rj_39FIAt6"
|
||||
"blurhash": "L3Q9_@4n9E?axW4mD$Mx~q00Di%L"
|
||||
}
|
||||
],
|
||||
"mentions": [],
|
||||
|
|
@ -983,9 +983,9 @@ func (suite *ReportsGetTestSuite) TestReportsGetTargetAccount() {
|
|||
"type": "image",
|
||||
"url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"text_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.webp",
|
||||
"remote_url": "http://fossbros-anonymous.io/attachments/original/13bbc3f8-2b5e-46ea-9531-40b4974d9912.jpg",
|
||||
"preview_remote_url": "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpg",
|
||||
"preview_remote_url": null,
|
||||
"meta": {
|
||||
"original": {
|
||||
"width": 472,
|
||||
|
|
@ -1005,7 +1005,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetTargetAccount() {
|
|||
}
|
||||
},
|
||||
"description": "tweet from thoughts of dog: i drank. all the water. in my bowl. earlier. but just now. i returned. to the same bowl. and it was. full again.. the bowl. is haunted",
|
||||
"blurhash": "LARysgM_IU_3~pD%M_Rj_39FIAt6"
|
||||
"blurhash": "L3Q9_@4n9E?axW4mD$Mx~q00Di%L"
|
||||
}
|
||||
],
|
||||
"mentions": [],
|
||||
|
|
|
|||
|
|
@ -819,7 +819,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch8() {
|
|||
"url": "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/attachment/original/`+instanceAccount.AvatarMediaAttachment.ID+`.gif",`+`
|
||||
"thumbnail_type": "image/gif",
|
||||
"thumbnail_description": "A bouncing little green peglin.",
|
||||
"blurhash": "LtJ[eKxu_4xt9Yj]M{WBt8WBM{WB"
|
||||
"blurhash": "LE9kG#M}4YtO%dRkWEt5Dmoxx?WC"
|
||||
}`, string(instanceV2ThumbnailJson))
|
||||
|
||||
// double extra special bonus: now update the image description without changing the image
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ func (suite *MediaCreateTestSuite) TestMediaCreateSuccessful() {
|
|||
Y: 0.5,
|
||||
},
|
||||
}, *attachmentReply.Meta)
|
||||
suite.Equal("LjCGfG#6RkRn_NvzRjWF?urqV@a$", *attachmentReply.Blurhash)
|
||||
suite.Equal("LcBzLU#6RkRn~qvzRjWF?urqV@jc", *attachmentReply.Blurhash)
|
||||
suite.NotEmpty(attachmentReply.ID)
|
||||
suite.NotEmpty(attachmentReply.URL)
|
||||
suite.NotEmpty(attachmentReply.PreviewURL)
|
||||
|
|
@ -291,7 +291,7 @@ func (suite *MediaCreateTestSuite) TestMediaCreateSuccessfulV2() {
|
|||
Y: 0.5,
|
||||
},
|
||||
}, *attachmentReply.Meta)
|
||||
suite.Equal("LjCGfG#6RkRn_NvzRjWF?urqV@a$", *attachmentReply.Blurhash)
|
||||
suite.Equal("LcBzLU#6RkRn~qvzRjWF?urqV@jc", *attachmentReply.Blurhash)
|
||||
suite.NotEmpty(attachmentReply.ID)
|
||||
suite.Nil(attachmentReply.URL)
|
||||
suite.NotEmpty(attachmentReply.PreviewURL)
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ func (suite *MediaUpdateTestSuite) TestUpdateImage() {
|
|||
suite.EqualValues("image", attachmentReply.Type)
|
||||
suite.EqualValues(apimodel.MediaMeta{
|
||||
Original: apimodel.MediaDimensions{Width: 800, Height: 450, FrameRate: "", Duration: 0, Bitrate: 0, Size: "800x450", Aspect: 1.7777778},
|
||||
Small: apimodel.MediaDimensions{Width: 256, Height: 144, FrameRate: "", Duration: 0, Bitrate: 0, Size: "256x144", Aspect: 1.7777778},
|
||||
Small: apimodel.MediaDimensions{Width: 512, Height: 288, FrameRate: "", Duration: 0, Bitrate: 0, Size: "512x288", Aspect: 1.7777778},
|
||||
Focus: &apimodel.MediaFocus{X: -0.1, Y: 0.3},
|
||||
}, *attachmentReply.Meta)
|
||||
suite.Equal(toUpdate.Blurhash, *attachmentReply.Blurhash)
|
||||
|
|
|
|||
|
|
@ -107,10 +107,10 @@ func (suite *StatusHistoryTestSuite) TestGetHistory() {
|
|||
"note": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e",
|
||||
"url": "http://localhost:8080/@the_mighty_zork",
|
||||
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
|
||||
"avatar_description": "a green goblin looking nasty",
|
||||
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
|
||||
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
|
||||
"followers_count": 2,
|
||||
"following_count": 2,
|
||||
|
|
|
|||
|
|
@ -125,10 +125,10 @@ func (suite *StatusMuteTestSuite) TestMuteUnmuteStatus() {
|
|||
"note": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e",
|
||||
"url": "http://localhost:8080/@the_mighty_zork",
|
||||
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
|
||||
"avatar_description": "a green goblin looking nasty",
|
||||
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
|
||||
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
|
||||
"followers_count": 2,
|
||||
"following_count": 2,
|
||||
|
|
@ -210,10 +210,10 @@ func (suite *StatusMuteTestSuite) TestMuteUnmuteStatus() {
|
|||
"note": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e",
|
||||
"url": "http://localhost:8080/@the_mighty_zork",
|
||||
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
|
||||
"avatar_description": "a green goblin looking nasty",
|
||||
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
|
||||
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
|
||||
"followers_count": 2,
|
||||
"following_count": 2,
|
||||
|
|
|
|||
|
|
@ -122,11 +122,11 @@ func (suite *ServeFileTestSuite) TestServeSmallLocalFileOK() {
|
|||
targetAttachment.AccountID,
|
||||
media.TypeAttachment,
|
||||
media.SizeSmall,
|
||||
targetAttachment.ID+".jpg",
|
||||
targetAttachment.ID+".webp",
|
||||
)
|
||||
|
||||
suite.Equal(http.StatusOK, code)
|
||||
suite.Equal("image/jpeg", headers.Get("content-type"))
|
||||
suite.Equal("image/webp", headers.Get("content-type"))
|
||||
suite.Equal(fileInStorage, body)
|
||||
}
|
||||
|
||||
|
|
@ -162,11 +162,11 @@ func (suite *ServeFileTestSuite) TestServeSmallRemoteFileOK() {
|
|||
targetAttachment.AccountID,
|
||||
media.TypeAttachment,
|
||||
media.SizeSmall,
|
||||
targetAttachment.ID+".jpg",
|
||||
targetAttachment.ID+".webp",
|
||||
)
|
||||
|
||||
suite.Equal(http.StatusOK, code)
|
||||
suite.Equal("image/jpeg", headers.Get("content-type"))
|
||||
suite.Equal("image/webp", headers.Get("content-type"))
|
||||
suite.Equal(fileInStorage, body)
|
||||
}
|
||||
|
||||
|
|
@ -208,11 +208,11 @@ func (suite *ServeFileTestSuite) TestServeSmallRemoteFileRecache() {
|
|||
targetAttachment.AccountID,
|
||||
media.TypeAttachment,
|
||||
media.SizeSmall,
|
||||
targetAttachment.ID+".jpg",
|
||||
targetAttachment.ID+".webp",
|
||||
)
|
||||
|
||||
suite.Equal(http.StatusOK, code)
|
||||
suite.Equal("image/jpeg", headers.Get("content-type"))
|
||||
suite.Equal("image/webp", headers.Get("content-type"))
|
||||
suite.Equal(fileInStorage, body)
|
||||
}
|
||||
|
||||
|
|
@ -252,7 +252,7 @@ func (suite *ServeFileTestSuite) TestServeSmallRemoteFileRecacheNotFound() {
|
|||
targetAttachment.AccountID,
|
||||
media.TypeAttachment,
|
||||
media.SizeSmall,
|
||||
targetAttachment.ID+".jpg",
|
||||
targetAttachment.ID+".webp",
|
||||
)
|
||||
|
||||
suite.Equal(http.StatusNotFound, code)
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ const (
|
|||
"content": "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://example.net/@nityosan\" class=\"u-url mention\">@<span>nityosan</span></a></span><br /><span class=\"h-card\" translate=\"no\"><a href=\"https://a.misskey.instance.com/@FIzxive\" class=\"u-url mention\">@<span>FIzxive</span></a></span><br /><span class=\"h-card\" translate=\"no\"><a href=\"https://another.misskey.instance.com/@mendako\" class=\"u-url mention\">@<span>mendako</span></a></span><br /><span class=\"h-card\" translate=\"no\"><a href=\"http://localhost:8080/@the_mighty_zork\" class=\"u-url mention\">@<span>the_mighty_zork</span></a></span></p>",
|
||||
"attachment": [
|
||||
{
|
||||
"blurhash": "LNJRdVM{00Rj%Mayt7j[4nWBofRj",
|
||||
"blurhash": "LIIE|gRj00WB-;j[t7j[4nWBj[Rj",
|
||||
"mediaType": "image/jpeg",
|
||||
"name": "",
|
||||
"type": "Document",
|
||||
|
|
|
|||
|
|
@ -47,10 +47,21 @@ func ffmpegClearMetadata(ctx context.Context, filepath string, ext string) error
|
|||
// Clear metadata with ffmpeg.
|
||||
if err := ffmpeg(ctx, dirpath,
|
||||
"-loglevel", "error",
|
||||
|
||||
// Input file.
|
||||
"-i", filepath,
|
||||
|
||||
// Drop all metadata.
|
||||
"-map_metadata", "-1",
|
||||
|
||||
// Copy input codecs,
|
||||
// i.e. no transcode.
|
||||
"-codec", "copy",
|
||||
|
||||
// Overwrite.
|
||||
"-y",
|
||||
|
||||
// Output.
|
||||
outpath,
|
||||
); err != nil {
|
||||
return err
|
||||
|
|
@ -64,23 +75,54 @@ func ffmpegClearMetadata(ctx context.Context, filepath string, ext string) error
|
|||
return nil
|
||||
}
|
||||
|
||||
// ffmpegGenerateThumb generates a thumbnail jpeg from input media of any type, useful for any media.
|
||||
// ffmpegGenerateThumb generates a thumbnail webp from input media of any type, useful for any media.
|
||||
func ffmpegGenerateThumb(ctx context.Context, filepath string, width, height int) (string, error) {
|
||||
|
||||
// Get directory from filepath.
|
||||
dirpath := path.Dir(filepath)
|
||||
|
||||
// Generate output frame file path.
|
||||
outpath := filepath + "_thumb.jpg"
|
||||
outpath := filepath + "_thumb.webp"
|
||||
|
||||
// Thumbnail size scaling argument.
|
||||
scale := strconv.Itoa(width) + ":" +
|
||||
strconv.Itoa(height)
|
||||
|
||||
// Generate thumb with ffmpeg.
|
||||
if err := ffmpeg(ctx, dirpath,
|
||||
"-loglevel", "error",
|
||||
|
||||
// Input file.
|
||||
"-i", filepath,
|
||||
"-filter:v", "thumbnail=n=10",
|
||||
"-filter:v", "scale="+strconv.Itoa(width)+":"+strconv.Itoa(height),
|
||||
"-qscale:v", "12", // ~ 70% quality
|
||||
|
||||
// Encode using libwebp.
|
||||
// (NOT as libwebp_anim).
|
||||
"-codec:v", "libwebp",
|
||||
|
||||
// Select thumb from first 10 frames
|
||||
// (thumb filter: https://ffmpeg.org/ffmpeg-filters.html#thumbnail)
|
||||
"-filter:v", "thumbnail=n=10,"+
|
||||
|
||||
// scale to dimensions
|
||||
// (scale filter: https://ffmpeg.org/ffmpeg-filters.html#scale)
|
||||
"scale="+scale+","+
|
||||
|
||||
// YUVA 4:2:0 pixel format
|
||||
// (format filter: https://ffmpeg.org/ffmpeg-filters.html#format)
|
||||
"format=pix_fmts=yuva420p",
|
||||
|
||||
// Only one frame
|
||||
"-frames:v", "1",
|
||||
|
||||
// ~40% webp quality
|
||||
// (codec options: https://ffmpeg.org/ffmpeg-codecs.html#toc-Codec-Options)
|
||||
// (libwebp codec: https://ffmpeg.org/ffmpeg-codecs.html#Options-36)
|
||||
"-qscale:v", "40",
|
||||
|
||||
// Overwrite.
|
||||
"-y",
|
||||
|
||||
// Output.
|
||||
outpath,
|
||||
); err != nil {
|
||||
return "", err
|
||||
|
|
@ -100,10 +142,21 @@ func ffmpegGenerateStatic(ctx context.Context, filepath string) (string, error)
|
|||
// Generate static with ffmpeg.
|
||||
if err := ffmpeg(ctx, dirpath,
|
||||
"-loglevel", "error",
|
||||
|
||||
// Input file.
|
||||
"-i", filepath,
|
||||
"-codec:v", "png", // specifically NOT 'apng'
|
||||
"-frames:v", "1", // in case animated, only take 1 frame
|
||||
|
||||
// Only first frame.
|
||||
"-frames:v", "1",
|
||||
|
||||
// Encode using png.
|
||||
// (NOT as apng).
|
||||
"-codec:v", "png",
|
||||
|
||||
// Overwrite.
|
||||
"-y",
|
||||
|
||||
// Output.
|
||||
outpath,
|
||||
); err != nil {
|
||||
return "", err
|
||||
|
|
|
|||
|
|
@ -273,9 +273,10 @@ func (suite *ManagerTestSuite) TestSimpleJpegProcess() {
|
|||
Width: 512, Height: 288, Size: 147456, Aspect: 1.7777777777777777,
|
||||
}, attachment.FileMeta.Small)
|
||||
suite.Equal("image/jpeg", attachment.File.ContentType)
|
||||
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
||||
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
||||
suite.Equal(269739, attachment.File.FileSize)
|
||||
suite.Equal("LjCGfG#6RkRn_NvzRjWF?urqV@a$", attachment.Blurhash)
|
||||
suite.Equal(8536, attachment.Thumbnail.FileSize)
|
||||
suite.Equal("LcBzLU#6RkRn~qvzRjWF?urqV@jc", attachment.Blurhash)
|
||||
|
||||
// now make sure the attachment is in the database
|
||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||
|
|
@ -284,7 +285,7 @@ func (suite *ManagerTestSuite) TestSimpleJpegProcess() {
|
|||
|
||||
// ensure the files contain the expected data.
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.File.Path, "./test/test-jpeg-processed.jpg")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/test-jpeg-thumbnail.jpg")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/test-jpeg-thumbnail.webp")
|
||||
}
|
||||
|
||||
func (suite *ManagerTestSuite) TestSimpleJpegProcessTooLarge() {
|
||||
|
|
@ -425,9 +426,10 @@ func (suite *ManagerTestSuite) TestSlothVineProcess() {
|
|||
Width: 338, Height: 240, Size: 81120, Aspect: 1.4083333333333334,
|
||||
}, attachment.FileMeta.Small)
|
||||
suite.Equal("video/mp4", attachment.File.ContentType)
|
||||
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
||||
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
||||
suite.Equal(312453, attachment.File.FileSize)
|
||||
suite.Equal("LrJuJat6NZkBt7ayW.j[_4WBsWoL", attachment.Blurhash)
|
||||
suite.Equal(3746, attachment.Thumbnail.FileSize)
|
||||
suite.Equal("LhIrNMt6Nsj[t7aybFj[_4WBspoe", attachment.Blurhash)
|
||||
|
||||
// now make sure the attachment is in the database
|
||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||
|
|
@ -436,7 +438,7 @@ func (suite *ManagerTestSuite) TestSlothVineProcess() {
|
|||
|
||||
// ensure the files contain the expected data.
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.File.Path, "./test/test-mp4-processed.mp4")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/test-mp4-thumbnail.jpg")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/test-mp4-thumbnail.webp")
|
||||
}
|
||||
|
||||
func (suite *ManagerTestSuite) TestLongerMp4Process() {
|
||||
|
|
@ -484,9 +486,10 @@ func (suite *ManagerTestSuite) TestLongerMp4Process() {
|
|||
Width: 512, Height: 281, Size: 143872, Aspect: 1.822064,
|
||||
}, attachment.FileMeta.Small)
|
||||
suite.Equal("video/mp4", attachment.File.ContentType)
|
||||
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
||||
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
||||
suite.Equal(109569, attachment.File.FileSize)
|
||||
suite.Equal("LASY{q~qD%_3~qD%ofRjM{ofofRj", attachment.Blurhash)
|
||||
suite.Equal(2128, attachment.Thumbnail.FileSize)
|
||||
suite.Equal("L8Q0aP~qnM_3~qD%ozRjRiofWXRj", attachment.Blurhash)
|
||||
|
||||
// now make sure the attachment is in the database
|
||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||
|
|
@ -495,7 +498,7 @@ func (suite *ManagerTestSuite) TestLongerMp4Process() {
|
|||
|
||||
// ensure the files contain the expected data.
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.File.Path, "./test/longer-mp4-processed.mp4")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/longer-mp4-thumbnail.jpg")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/longer-mp4-thumbnail.webp")
|
||||
}
|
||||
|
||||
func (suite *ManagerTestSuite) TestBirdnestMp4Process() {
|
||||
|
|
@ -543,9 +546,10 @@ func (suite *ManagerTestSuite) TestBirdnestMp4Process() {
|
|||
Width: 287, Height: 512, Size: 146944, Aspect: 0.5605469,
|
||||
}, attachment.FileMeta.Small)
|
||||
suite.Equal("video/mp4", attachment.File.ContentType)
|
||||
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
||||
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
||||
suite.Equal(1409625, attachment.File.FileSize)
|
||||
suite.Equal("LOGb||RjRO.99DRORPaetkV?afMw", attachment.Blurhash)
|
||||
suite.Equal(9446, attachment.Thumbnail.FileSize)
|
||||
suite.Equal("LKF~w1RjRO.99DRORPaetkV?WCMw", attachment.Blurhash)
|
||||
|
||||
// now make sure the attachment is in the database
|
||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||
|
|
@ -554,7 +558,7 @@ func (suite *ManagerTestSuite) TestBirdnestMp4Process() {
|
|||
|
||||
// ensure the files contain the expected data.
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.File.Path, "./test/birdnest-processed.mp4")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/birdnest-thumbnail.jpg")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/birdnest-thumbnail.webp")
|
||||
}
|
||||
|
||||
func (suite *ManagerTestSuite) TestOpusProcess() {
|
||||
|
|
@ -650,9 +654,10 @@ func (suite *ManagerTestSuite) TestPngNoAlphaChannelProcess() {
|
|||
Width: 186, Height: 187, Size: 34782, Aspect: 0.9946524064171123,
|
||||
}, attachment.FileMeta.Small)
|
||||
suite.Equal("image/png", attachment.File.ContentType)
|
||||
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
||||
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
||||
suite.Equal(17471, attachment.File.FileSize)
|
||||
suite.Equal("LDQJl?%i-?WG%go#RURP~of3~UxV", attachment.Blurhash)
|
||||
suite.Equal(2630, attachment.Thumbnail.FileSize)
|
||||
suite.Equal("LBOW$@%i-=aj%go#RSRP_1av~Tt2", attachment.Blurhash)
|
||||
|
||||
// now make sure the attachment is in the database
|
||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||
|
|
@ -661,7 +666,7 @@ func (suite *ManagerTestSuite) TestPngNoAlphaChannelProcess() {
|
|||
|
||||
// ensure the files contain the expected data.
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.File.Path, "./test/test-png-noalphachannel-processed.png")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/test-png-noalphachannel-thumbnail.jpg")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/test-png-noalphachannel-thumbnail.webp")
|
||||
}
|
||||
|
||||
func (suite *ManagerTestSuite) TestPngAlphaChannelProcess() {
|
||||
|
|
@ -705,9 +710,10 @@ func (suite *ManagerTestSuite) TestPngAlphaChannelProcess() {
|
|||
Width: 186, Height: 187, Size: 34782, Aspect: 0.9946524064171123,
|
||||
}, attachment.FileMeta.Small)
|
||||
suite.Equal("image/png", attachment.File.ContentType)
|
||||
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
||||
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
||||
suite.Equal(18904, attachment.File.FileSize)
|
||||
suite.Equal("LDQJl?%i-?WG%go#RURP~of3~UxV", attachment.Blurhash)
|
||||
suite.Equal(2630, attachment.Thumbnail.FileSize)
|
||||
suite.Equal("LBOW$@%i-=aj%go#RSRP_1av~Tt2", attachment.Blurhash)
|
||||
|
||||
// now make sure the attachment is in the database
|
||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||
|
|
@ -716,7 +722,7 @@ func (suite *ManagerTestSuite) TestPngAlphaChannelProcess() {
|
|||
|
||||
// ensure the files contain the expected data.
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.File.Path, "./test/test-png-alphachannel-processed.png")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/test-png-alphachannel-thumbnail.jpg")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/test-png-alphachannel-thumbnail.webp")
|
||||
}
|
||||
|
||||
func (suite *ManagerTestSuite) TestSimpleJpegProcessWithCallback() {
|
||||
|
|
@ -760,9 +766,10 @@ func (suite *ManagerTestSuite) TestSimpleJpegProcessWithCallback() {
|
|||
Width: 512, Height: 288, Size: 147456, Aspect: 1.7777777777777777,
|
||||
}, attachment.FileMeta.Small)
|
||||
suite.Equal("image/jpeg", attachment.File.ContentType)
|
||||
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
||||
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
||||
suite.Equal(269739, attachment.File.FileSize)
|
||||
suite.Equal("LjCGfG#6RkRn_NvzRjWF?urqV@a$", attachment.Blurhash)
|
||||
suite.Equal(8536, attachment.Thumbnail.FileSize)
|
||||
suite.Equal("LcBzLU#6RkRn~qvzRjWF?urqV@jc", attachment.Blurhash)
|
||||
|
||||
// now make sure the attachment is in the database
|
||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||
|
|
@ -771,7 +778,7 @@ func (suite *ManagerTestSuite) TestSimpleJpegProcessWithCallback() {
|
|||
|
||||
// ensure the files contain the expected data.
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.File.Path, "./test/test-jpeg-processed.jpg")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/test-jpeg-thumbnail.jpg")
|
||||
equalFiles(suite.T(), suite.state.Storage, dbAttachment.Thumbnail.Path, "./test/test-jpeg-thumbnail.webp")
|
||||
}
|
||||
|
||||
func (suite *ManagerTestSuite) TestSimpleJpegProcessWithDiskStorage() {
|
||||
|
|
@ -837,9 +844,10 @@ func (suite *ManagerTestSuite) TestSimpleJpegProcessWithDiskStorage() {
|
|||
Width: 512, Height: 288, Size: 147456, Aspect: 1.7777777777777777,
|
||||
}, attachment.FileMeta.Small)
|
||||
suite.Equal("image/jpeg", attachment.File.ContentType)
|
||||
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
||||
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
||||
suite.Equal(269739, attachment.File.FileSize)
|
||||
suite.Equal("LjCGfG#6RkRn_NvzRjWF?urqV@a$", attachment.Blurhash)
|
||||
suite.Equal(8536, attachment.Thumbnail.FileSize)
|
||||
suite.Equal("LcBzLU#6RkRn~qvzRjWF?urqV@jc", attachment.Blurhash)
|
||||
|
||||
// now make sure the attachment is in the database
|
||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||
|
|
@ -848,7 +856,7 @@ func (suite *ManagerTestSuite) TestSimpleJpegProcessWithDiskStorage() {
|
|||
|
||||
// ensure the files contain the expected data.
|
||||
equalFiles(suite.T(), storage, dbAttachment.File.Path, "./test/test-jpeg-processed.jpg")
|
||||
equalFiles(suite.T(), storage, dbAttachment.Thumbnail.Path, "./test/test-jpeg-thumbnail.jpg")
|
||||
equalFiles(suite.T(), storage, dbAttachment.Thumbnail.Path, "./test/test-jpeg-thumbnail.webp")
|
||||
}
|
||||
|
||||
func (suite *ManagerTestSuite) TestSmallSizedMediaTypeDetection_issue2263() {
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
|
|||
string(TypeAttachment),
|
||||
string(SizeSmall),
|
||||
p.media.ID,
|
||||
"jpeg",
|
||||
"webp",
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -309,7 +309,7 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
|
|||
string(TypeAttachment),
|
||||
string(SizeSmall),
|
||||
p.media.ID,
|
||||
"jpeg",
|
||||
"webp",
|
||||
)
|
||||
|
||||
// Get mimetype for the file container
|
||||
|
|
@ -317,7 +317,7 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
|
|||
p.media.File.ContentType = getMimeType(ext)
|
||||
|
||||
// Set the known thumbnail content type.
|
||||
p.media.Thumbnail.ContentType = "image/jpeg"
|
||||
p.media.Thumbnail.ContentType = "image/webp"
|
||||
|
||||
// We can now consider this cached.
|
||||
p.media.Cached = util.Ptr(true)
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 9.9 KiB |
BIN
internal/media/test/birdnest-thumbnail.webp
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
BIN
internal/media/test/longer-mp4-thumbnail.webp
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
internal/media/test/not-an-processed.mp4
Normal file
BIN
internal/media/test/not-an-thumbnail.webp
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
internal/media/test/test-jpeg-1x1px-white-thumbnail.webp
Normal file
|
After Width: | Height: | Size: 44 B |
|
Before Width: | Height: | Size: 11 KiB |
BIN
internal/media/test/test-jpeg-thumbnail.webp
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
BIN
internal/media/test/test-mp4-thumbnail.webp
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 7.8 KiB |
BIN
internal/media/test/test-png-alphachannel-thumbnail.webp
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
BIN
internal/media/test/test-png-noalphachannel-thumbnail.webp
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
|
|
@ -22,13 +22,15 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/image/webp"
|
||||
|
||||
"codeberg.org/gruf/go-bytesize"
|
||||
"codeberg.org/gruf/go-iotools"
|
||||
"codeberg.org/gruf/go-mimetypes"
|
||||
|
||||
"github.com/buckket/go-blurhash"
|
||||
"github.com/disintegration/imaging"
|
||||
)
|
||||
|
|
@ -63,8 +65,8 @@ func thumbSize(width, height int) (int, int) {
|
|||
}
|
||||
}
|
||||
|
||||
// jpegDecode decodes the JPEG at filepath into parsed image.Image.
|
||||
func jpegDecode(filepath string) (image.Image, error) {
|
||||
// webpDecode decodes the WebP at filepath into parsed image.Image.
|
||||
func webpDecode(filepath string) (image.Image, error) {
|
||||
// Open the file at given path.
|
||||
file, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
|
|
@ -72,7 +74,7 @@ func jpegDecode(filepath string) (image.Image, error) {
|
|||
}
|
||||
|
||||
// Decode image from file.
|
||||
img, err := jpeg.Decode(file)
|
||||
img, err := webp.Decode(file)
|
||||
|
||||
// Done with file.
|
||||
_ = file.Close()
|
||||
|
|
@ -83,7 +85,7 @@ func jpegDecode(filepath string) (image.Image, error) {
|
|||
// generateBlurhash generates a blurhash for JPEG at filepath.
|
||||
func generateBlurhash(filepath string) (string, error) {
|
||||
// Decode JPEG file at given path.
|
||||
img, err := jpegDecode(filepath)
|
||||
img, err := webpDecode(filepath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ func (suite *GetRSSTestSuite) TestGetAccountRSSZork() {
|
|||
|
||||
feed, err := getFeed()
|
||||
suite.NoError(err)
|
||||
suite.Equal("<?xml version=\"1.0\" encoding=\"UTF-8\"?><rss version=\"2.0\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\">\n <channel>\n <title>Posts from @the_mighty_zork@localhost:8080</title>\n <link>http://localhost:8080/@the_mighty_zork</link>\n <description>Posts from @the_mighty_zork@localhost:8080</description>\n <pubDate>Wed, 10 Jan 2024 09:24:00 +0000</pubDate>\n <lastBuildDate>Wed, 10 Jan 2024 09:24:00 +0000</lastBuildDate>\n <image>\n <url>http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg</url>\n <title>Avatar for @the_mighty_zork@localhost:8080</title>\n <link>http://localhost:8080/@the_mighty_zork</link>\n </image>\n <item>\n <title>HTML in post</title>\n <link>http://localhost:8080/@the_mighty_zork/statuses/01HH9KYNQPA416TNJ53NSATP40</link>\n <description>@the_mighty_zork@localhost:8080 made a new post: "Here's a bunch of HTML, read it and weep, weep then!

```html
<section class="about-user">
 <div class="col-header">
 <h2>About</h2>
 </div> 
 <div class="fields">
 <h3 class="sr-only">Fields</h3>
 <dl>
...</description>\n <content:encoded><![CDATA[<p>Here's a bunch of HTML, read it and weep, weep then!</p><pre><code class=\"language-html\"><section class="about-user">\n <div class="col-header">\n <h2>About</h2>\n </div> \n <div class="fields">\n <h3 class="sr-only">Fields</h3>\n <dl>\n <div class="field">\n <dt>should you follow me?</dt>\n <dd>maybe!</dd>\n </div>\n <div class="field">\n <dt>age</dt>\n <dd>120</dd>\n </div>\n </dl>\n </div>\n <div class="bio">\n <h3 class="sr-only">Bio</h3>\n <p>i post about things that concern me</p>\n </div>\n <div class="sr-only" role="group">\n <h3 class="sr-only">Stats</h3>\n <span>Joined in Jun, 2022.</span>\n <span>8 posts.</span>\n <span>Followed by 1.</span>\n <span>Following 1.</span>\n </div>\n <div class="accountstats" aria-hidden="true">\n <b>Joined</b><time datetime="2022-06-04T13:12:00.000Z">Jun, 2022</time>\n <b>Posts</b><span>8</span>\n <b>Followed by</b><span>1</span>\n <b>Following</b><span>1</span>\n </div>\n</section>\n</code></pre><p>There, hope you liked that!</p>]]></content:encoded>\n <author>@the_mighty_zork@localhost:8080</author>\n <guid isPermaLink=\"true\">http://localhost:8080/@the_mighty_zork/statuses/01HH9KYNQPA416TNJ53NSATP40</guid>\n <pubDate>Sun, 10 Dec 2023 09:24:00 +0000</pubDate>\n <source>http://localhost:8080/@the_mighty_zork/feed.rss</source>\n </item>\n <item>\n <title>introduction post</title>\n <link>http://localhost:8080/@the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY</link>\n <description>@the_mighty_zork@localhost:8080 made a new post: "hello everyone!"</description>\n <content:encoded><![CDATA[hello everyone!]]></content:encoded>\n <author>@the_mighty_zork@localhost:8080</author>\n <guid isPermaLink=\"true\">http://localhost:8080/@the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY</guid>\n <pubDate>Wed, 20 Oct 2021 10:40:37 +0000</pubDate>\n <source>http://localhost:8080/@the_mighty_zork/feed.rss</source>\n </item>\n </channel>\n</rss>", feed)
|
||||
suite.Equal("<?xml version=\"1.0\" encoding=\"UTF-8\"?><rss version=\"2.0\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\">\n <channel>\n <title>Posts from @the_mighty_zork@localhost:8080</title>\n <link>http://localhost:8080/@the_mighty_zork</link>\n <description>Posts from @the_mighty_zork@localhost:8080</description>\n <pubDate>Wed, 10 Jan 2024 09:24:00 +0000</pubDate>\n <lastBuildDate>Wed, 10 Jan 2024 09:24:00 +0000</lastBuildDate>\n <image>\n <url>http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp</url>\n <title>Avatar for @the_mighty_zork@localhost:8080</title>\n <link>http://localhost:8080/@the_mighty_zork</link>\n </image>\n <item>\n <title>HTML in post</title>\n <link>http://localhost:8080/@the_mighty_zork/statuses/01HH9KYNQPA416TNJ53NSATP40</link>\n <description>@the_mighty_zork@localhost:8080 made a new post: "Here's a bunch of HTML, read it and weep, weep then!

```html
<section class="about-user">
 <div class="col-header">
 <h2>About</h2>
 </div> 
 <div class="fields">
 <h3 class="sr-only">Fields</h3>
 <dl>
...</description>\n <content:encoded><![CDATA[<p>Here's a bunch of HTML, read it and weep, weep then!</p><pre><code class=\"language-html\"><section class="about-user">\n <div class="col-header">\n <h2>About</h2>\n </div> \n <div class="fields">\n <h3 class="sr-only">Fields</h3>\n <dl>\n <div class="field">\n <dt>should you follow me?</dt>\n <dd>maybe!</dd>\n </div>\n <div class="field">\n <dt>age</dt>\n <dd>120</dd>\n </div>\n </dl>\n </div>\n <div class="bio">\n <h3 class="sr-only">Bio</h3>\n <p>i post about things that concern me</p>\n </div>\n <div class="sr-only" role="group">\n <h3 class="sr-only">Stats</h3>\n <span>Joined in Jun, 2022.</span>\n <span>8 posts.</span>\n <span>Followed by 1.</span>\n <span>Following 1.</span>\n </div>\n <div class="accountstats" aria-hidden="true">\n <b>Joined</b><time datetime="2022-06-04T13:12:00.000Z">Jun, 2022</time>\n <b>Posts</b><span>8</span>\n <b>Followed by</b><span>1</span>\n <b>Following</b><span>1</span>\n </div>\n</section>\n</code></pre><p>There, hope you liked that!</p>]]></content:encoded>\n <author>@the_mighty_zork@localhost:8080</author>\n <guid isPermaLink=\"true\">http://localhost:8080/@the_mighty_zork/statuses/01HH9KYNQPA416TNJ53NSATP40</guid>\n <pubDate>Sun, 10 Dec 2023 09:24:00 +0000</pubDate>\n <source>http://localhost:8080/@the_mighty_zork/feed.rss</source>\n </item>\n <item>\n <title>introduction post</title>\n <link>http://localhost:8080/@the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY</link>\n <description>@the_mighty_zork@localhost:8080 made a new post: "hello everyone!"</description>\n <content:encoded><![CDATA[hello everyone!]]></content:encoded>\n <author>@the_mighty_zork@localhost:8080</author>\n <guid isPermaLink=\"true\">http://localhost:8080/@the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY</guid>\n <pubDate>Wed, 20 Oct 2021 10:40:37 +0000</pubDate>\n <source>http://localhost:8080/@the_mighty_zork/feed.rss</source>\n </item>\n </channel>\n</rss>", feed)
|
||||
}
|
||||
|
||||
func (suite *GetRSSTestSuite) TestGetAccountRSSZorkNoPosts() {
|
||||
|
|
@ -70,7 +70,7 @@ func (suite *GetRSSTestSuite) TestGetAccountRSSZorkNoPosts() {
|
|||
|
||||
feed, err := getFeed()
|
||||
suite.NoError(err)
|
||||
suite.Equal("<?xml version=\"1.0\" encoding=\"UTF-8\"?><rss version=\"2.0\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\">\n <channel>\n <title>Posts from @the_mighty_zork@localhost:8080</title>\n <link>http://localhost:8080/@the_mighty_zork</link>\n <description>Posts from @the_mighty_zork@localhost:8080</description>\n <pubDate>Fri, 20 May 2022 11:09:18 +0000</pubDate>\n <lastBuildDate>Fri, 20 May 2022 11:09:18 +0000</lastBuildDate>\n <image>\n <url>http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg</url>\n <title>Avatar for @the_mighty_zork@localhost:8080</title>\n <link>http://localhost:8080/@the_mighty_zork</link>\n </image>\n </channel>\n</rss>", feed)
|
||||
suite.Equal("<?xml version=\"1.0\" encoding=\"UTF-8\"?><rss version=\"2.0\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\">\n <channel>\n <title>Posts from @the_mighty_zork@localhost:8080</title>\n <link>http://localhost:8080/@the_mighty_zork</link>\n <description>Posts from @the_mighty_zork@localhost:8080</description>\n <pubDate>Fri, 20 May 2022 11:09:18 +0000</pubDate>\n <lastBuildDate>Fri, 20 May 2022 11:09:18 +0000</lastBuildDate>\n <image>\n <url>http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp</url>\n <title>Avatar for @the_mighty_zork@localhost:8080</title>\n <link>http://localhost:8080/@the_mighty_zork</link>\n </image>\n </channel>\n</rss>", feed)
|
||||
}
|
||||
|
||||
func TestGetRSSTestSuite(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ func (suite *GetFileTestSuite) TestGetRemoteFileThumbnailUncached() {
|
|||
suite.NoError(content.Content.Close())
|
||||
|
||||
suite.Equal(thumbnailBytes, b)
|
||||
suite.Equal("image/jpeg", content.ContentType)
|
||||
suite.Equal("image/webp", content.ContentType)
|
||||
suite.EqualValues(testAttachment.Thumbnail.FileSize, content.ContentLength)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,9 +100,9 @@ func (suite *StatusUpdateTestSuite) TestStreamNotification() {
|
|||
"type": "image",
|
||||
"url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"text_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.webp",
|
||||
"remote_url": "http://fossbros-anonymous.io/attachments/original/13bbc3f8-2b5e-46ea-9531-40b4974d9912.jpg",
|
||||
"preview_remote_url": "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpg",
|
||||
"preview_remote_url": null,
|
||||
"meta": {
|
||||
"original": {
|
||||
"width": 472,
|
||||
|
|
@ -122,7 +122,7 @@ func (suite *StatusUpdateTestSuite) TestStreamNotification() {
|
|||
}
|
||||
},
|
||||
"description": "tweet from thoughts of dog: i drank. all the water. in my bowl. earlier. but just now. i returned. to the same bowl. and it was. full again.. the bowl. is haunted",
|
||||
"blurhash": "LARysgM_IU_3~pD%M_Rj_39FIAt6"
|
||||
"blurhash": "L3Q9_@4n9E?axW4mD$Mx~q00Di%L"
|
||||
}
|
||||
],
|
||||
"mentions": [],
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ func (suite *InternalToASTestSuite) TestStatusWithTagsToASWithIDs() {
|
|||
trimmed := strings.SplitAfter(string(bytes), `"attachment":`)[1]
|
||||
suite.Equal(` [
|
||||
{
|
||||
"blurhash": "LNJRdVM{00Rj%Mayt7j[4nWBofRj",
|
||||
"blurhash": "LIIE|gRj00WB-;j[t7j[4nWBj[Rj",
|
||||
"mediaType": "image/jpeg",
|
||||
"name": "Black and white image of some 50's style text saying: Welcome On Board",
|
||||
"type": "Document",
|
||||
|
|
@ -501,7 +501,7 @@ func (suite *InternalToASTestSuite) TestStatusWithTagsToASFromDB() {
|
|||
trimmed := strings.SplitAfter(string(bytes), `"attachment":`)[1]
|
||||
suite.Equal(` [
|
||||
{
|
||||
"blurhash": "LNJRdVM{00Rj%Mayt7j[4nWBofRj",
|
||||
"blurhash": "LIIE|gRj00WB-;j[t7j[4nWBj[Rj",
|
||||
"mediaType": "image/jpeg",
|
||||
"name": "Black and white image of some 50's style text saying: Welcome On Board",
|
||||
"type": "Document",
|
||||
|
|
|
|||
|
|
@ -56,10 +56,10 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontend() {
|
|||
"note": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e",
|
||||
"url": "http://localhost:8080/@the_mighty_zork",
|
||||
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
|
||||
"avatar_description": "a green goblin looking nasty",
|
||||
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
|
||||
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
|
||||
"followers_count": 2,
|
||||
"following_count": 2,
|
||||
|
|
@ -109,10 +109,10 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontendAliasedAndMoved()
|
|||
"note": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e",
|
||||
"url": "http://localhost:8080/@the_mighty_zork",
|
||||
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
|
||||
"avatar_description": "a green goblin looking nasty",
|
||||
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
|
||||
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
|
||||
"followers_count": 2,
|
||||
"following_count": 2,
|
||||
|
|
@ -202,10 +202,10 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontendWithEmojiStruct()
|
|||
"note": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e",
|
||||
"url": "http://localhost:8080/@the_mighty_zork",
|
||||
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
|
||||
"avatar_description": "a green goblin looking nasty",
|
||||
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
|
||||
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
|
||||
"followers_count": 2,
|
||||
"following_count": 2,
|
||||
|
|
@ -252,10 +252,10 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontendWithEmojiIDs() {
|
|||
"note": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e",
|
||||
"url": "http://localhost:8080/@the_mighty_zork",
|
||||
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
|
||||
"avatar_description": "a green goblin looking nasty",
|
||||
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
|
||||
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
|
||||
"followers_count": 2,
|
||||
"following_count": 2,
|
||||
|
|
@ -298,10 +298,10 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontendSensitive() {
|
|||
"note": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e",
|
||||
"url": "http://localhost:8080/@the_mighty_zork",
|
||||
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
|
||||
"avatar_description": "a green goblin looking nasty",
|
||||
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
|
||||
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
|
||||
"followers_count": 2,
|
||||
"following_count": 2,
|
||||
|
|
@ -503,7 +503,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontend() {
|
|||
"type": "image",
|
||||
"url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
||||
"text_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.webp",
|
||||
"remote_url": null,
|
||||
"preview_remote_url": null,
|
||||
"meta": {
|
||||
|
|
@ -514,9 +514,9 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontend() {
|
|||
"aspect": 1.9047619
|
||||
},
|
||||
"small": {
|
||||
"width": 256,
|
||||
"height": 134,
|
||||
"size": "256x134",
|
||||
"width": 512,
|
||||
"height": 268,
|
||||
"size": "512x268",
|
||||
"aspect": 1.9104477
|
||||
},
|
||||
"focus": {
|
||||
|
|
@ -525,7 +525,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontend() {
|
|||
}
|
||||
},
|
||||
"description": "Black and white image of some 50's style text saying: Welcome On Board",
|
||||
"blurhash": "LNJRdVM{00Rj%Mayt7j[4nWBofRj"
|
||||
"blurhash": "LIIE|gRj00WB-;j[t7j[4nWBj[Rj"
|
||||
}
|
||||
],
|
||||
"mentions": [],
|
||||
|
|
@ -652,7 +652,7 @@ func (suite *InternalToFrontendTestSuite) TestWarnFilteredStatusToFrontend() {
|
|||
"type": "image",
|
||||
"url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
||||
"text_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.webp",
|
||||
"remote_url": null,
|
||||
"preview_remote_url": null,
|
||||
"meta": {
|
||||
|
|
@ -663,9 +663,9 @@ func (suite *InternalToFrontendTestSuite) TestWarnFilteredStatusToFrontend() {
|
|||
"aspect": 1.9047619
|
||||
},
|
||||
"small": {
|
||||
"width": 256,
|
||||
"height": 134,
|
||||
"size": "256x134",
|
||||
"width": 512,
|
||||
"height": 268,
|
||||
"size": "512x268",
|
||||
"aspect": 1.9104477
|
||||
},
|
||||
"focus": {
|
||||
|
|
@ -674,7 +674,7 @@ func (suite *InternalToFrontendTestSuite) TestWarnFilteredStatusToFrontend() {
|
|||
}
|
||||
},
|
||||
"description": "Black and white image of some 50's style text saying: Welcome On Board",
|
||||
"blurhash": "LNJRdVM{00Rj%Mayt7j[4nWBofRj"
|
||||
"blurhash": "LIIE|gRj00WB-;j[t7j[4nWBj[Rj"
|
||||
}
|
||||
],
|
||||
"mentions": [],
|
||||
|
|
@ -881,7 +881,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendUnknownAttachments
|
|||
"type": "image",
|
||||
"url": "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/original/01HE7Y3C432WRSNS10EZM86SA5.jpg",
|
||||
"text_url": "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/original/01HE7Y3C432WRSNS10EZM86SA5.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/small/01HE7Y3C432WRSNS10EZM86SA5.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/small/01HE7Y3C432WRSNS10EZM86SA5.webp",
|
||||
"remote_url": "http://example.org/fileserver/01HE7Y659ZWZ02JM4AWYJZ176Q/attachment/original/01HE7Y6G0EMCKST3Q0914WW0MS.jpg",
|
||||
"preview_remote_url": null,
|
||||
"meta": {
|
||||
|
|
@ -903,7 +903,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendUnknownAttachments
|
|||
}
|
||||
},
|
||||
"description": "Photograph of a sloth, Public Domain.",
|
||||
"blurhash": "LNEC{|w}0K9GsEtPM|j[NFbHoeof"
|
||||
"blurhash": "LKE3VIw}0KD%a2o{M|t7NFWps:t7"
|
||||
}
|
||||
],
|
||||
"mentions": [
|
||||
|
|
@ -1041,7 +1041,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToWebStatus() {
|
|||
"type": "image",
|
||||
"url": "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/original/01HE7Y3C432WRSNS10EZM86SA5.jpg",
|
||||
"text_url": "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/original/01HE7Y3C432WRSNS10EZM86SA5.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/small/01HE7Y3C432WRSNS10EZM86SA5.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/small/01HE7Y3C432WRSNS10EZM86SA5.webp",
|
||||
"remote_url": "http://example.org/fileserver/01HE7Y659ZWZ02JM4AWYJZ176Q/attachment/original/01HE7Y6G0EMCKST3Q0914WW0MS.jpg",
|
||||
"preview_remote_url": null,
|
||||
"meta": {
|
||||
|
|
@ -1063,7 +1063,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToWebStatus() {
|
|||
}
|
||||
},
|
||||
"description": "Photograph of a sloth, Public Domain.",
|
||||
"blurhash": "LNEC{|w}0K9GsEtPM|j[NFbHoeof",
|
||||
"blurhash": "LKE3VIw}0KD%a2o{M|t7NFWps:t7",
|
||||
"Sensitive": true,
|
||||
"MIMEType": "image/jpg"
|
||||
},
|
||||
|
|
@ -1174,7 +1174,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendUnknownLanguage()
|
|||
"type": "image",
|
||||
"url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
||||
"text_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.webp",
|
||||
"remote_url": null,
|
||||
"preview_remote_url": null,
|
||||
"meta": {
|
||||
|
|
@ -1185,9 +1185,9 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendUnknownLanguage()
|
|||
"aspect": 1.9047619
|
||||
},
|
||||
"small": {
|
||||
"width": 256,
|
||||
"height": 134,
|
||||
"size": "256x134",
|
||||
"width": 512,
|
||||
"height": 268,
|
||||
"size": "512x268",
|
||||
"aspect": 1.9104477
|
||||
},
|
||||
"focus": {
|
||||
|
|
@ -1196,7 +1196,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendUnknownLanguage()
|
|||
}
|
||||
},
|
||||
"description": "Black and white image of some 50's style text saying: Welcome On Board",
|
||||
"blurhash": "LNJRdVM{00Rj%Mayt7j[4nWBofRj"
|
||||
"blurhash": "LIIE|gRj00WB-;j[t7j[4nWBj[Rj"
|
||||
}
|
||||
],
|
||||
"mentions": [],
|
||||
|
|
@ -1289,10 +1289,10 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendPartialInteraction
|
|||
"note": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e",
|
||||
"url": "http://localhost:8080/@the_mighty_zork",
|
||||
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
|
||||
"avatar_description": "a green goblin looking nasty",
|
||||
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
|
||||
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
|
||||
"followers_count": 2,
|
||||
"following_count": 2,
|
||||
|
|
@ -1348,7 +1348,7 @@ func (suite *InternalToFrontendTestSuite) TestVideoAttachmentToFrontend() {
|
|||
"type": "video",
|
||||
"url": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01CDR64G398ADCHXK08WWTHEZ5.mp4",
|
||||
"text_url": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01CDR64G398ADCHXK08WWTHEZ5.mp4",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01CDR64G398ADCHXK08WWTHEZ5.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01CDR64G398ADCHXK08WWTHEZ5.webp",
|
||||
"remote_url": null,
|
||||
"preview_remote_url": null,
|
||||
"meta": {
|
||||
|
|
@ -1356,16 +1356,16 @@ func (suite *InternalToFrontendTestSuite) TestVideoAttachmentToFrontend() {
|
|||
"width": 720,
|
||||
"height": 404,
|
||||
"frame_rate": "30/1",
|
||||
"duration": 15.033334,
|
||||
"bitrate": 1206522,
|
||||
"duration": 15.034,
|
||||
"bitrate": 1209808,
|
||||
"size": "720x404",
|
||||
"aspect": 1.7821782
|
||||
},
|
||||
"small": {
|
||||
"width": 720,
|
||||
"height": 404,
|
||||
"size": "720x404",
|
||||
"aspect": 1.7821782
|
||||
"width": 512,
|
||||
"height": 287,
|
||||
"size": "512x287",
|
||||
"aspect": 1.7839721
|
||||
},
|
||||
"focus": {
|
||||
"x": 0,
|
||||
|
|
@ -1373,7 +1373,7 @@ func (suite *InternalToFrontendTestSuite) TestVideoAttachmentToFrontend() {
|
|||
}
|
||||
},
|
||||
"description": "A cow adorably licking another cow!",
|
||||
"blurhash": null
|
||||
"blurhash": "L9B|BBY8yZtS~AxZV@t6,njEjZV@"
|
||||
}`, string(b))
|
||||
}
|
||||
|
||||
|
|
@ -2185,9 +2185,9 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend2() {
|
|||
"type": "image",
|
||||
"url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"text_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg",
|
||||
"preview_url": "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.webp",
|
||||
"remote_url": "http://fossbros-anonymous.io/attachments/original/13bbc3f8-2b5e-46ea-9531-40b4974d9912.jpg",
|
||||
"preview_remote_url": "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpg",
|
||||
"preview_remote_url": null,
|
||||
"meta": {
|
||||
"original": {
|
||||
"width": 472,
|
||||
|
|
@ -2207,7 +2207,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend2() {
|
|||
}
|
||||
},
|
||||
"description": "tweet from thoughts of dog: i drank. all the water. in my bowl. earlier. but just now. i returned. to the same bowl. and it was. full again.. the bowl. is haunted",
|
||||
"blurhash": "LARysgM_IU_3~pD%M_Rj_39FIAt6"
|
||||
"blurhash": "L3Q9_@4n9E?axW4mD$Mx~q00Di%L"
|
||||
}
|
||||
],
|
||||
"mentions": [],
|
||||
|
|
|
|||