From 3f53cbd8f680c5659c53bf709fdd044c5dcb59c7 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight <saschanaz@outlook.com> Date: Fri, 10 Mar 2023 01:37:22 +0100 Subject: [PATCH] fix(backend/DriveService): convert WebP/AVIF to WebP (#10239) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(backend/DriveService): convert transparent WebP/AVIF to PNG * webpにする その希望が複数ありましたので * Update packages/backend/src/core/DriveService.ts Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com> * update test * webpはwebpublicにできる --------- Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com> Co-authored-by: tamaina <tamaina@hotmail.co.jp> --- packages/backend/src/core/DriveService.ts | 12 ++-- .../src/core/activitypub/ApRendererService.ts | 68 +++++++++--------- packages/backend/test/e2e/endpoints.ts | 41 ++++++++++- .../backend/test/resources/with-alpha.avif | Bin 0 -> 10032 bytes .../backend/test/resources/with-alpha.webp | Bin 0 -> 4984 bytes .../backend/test/resources/without-alpha.avif | Bin 0 -> 3982 bytes .../backend/test/resources/without-alpha.webp | Bin 0 -> 4474 bytes packages/backend/test/utils.ts | 7 +- 8 files changed, 86 insertions(+), 42 deletions(-) create mode 100644 packages/backend/test/resources/with-alpha.avif create mode 100644 packages/backend/test/resources/with-alpha.webp create mode 100644 packages/backend/test/resources/without-alpha.avif create mode 100644 packages/backend/test/resources/without-alpha.webp diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts index f4a06faebb..c3835faa33 100644 --- a/packages/backend/src/core/DriveService.ts +++ b/packages/backend/src/core/DriveService.ts @@ -299,7 +299,7 @@ export class DriveService { } satisfyWebpublic = !!( - type !== 'image/svg+xml' && type !== 'image/webp' && type !== 'image/avif' && + type !== 'image/svg+xml' && type !== 'image/avif' && !(metadata.exif ?? metadata.iptc ?? metadata.xmp ?? metadata.tifftagPhotoshop) && metadata.width && metadata.width <= 2048 && metadata.height && metadata.height <= 2048 @@ -319,11 +319,11 @@ export class DriveService { this.registerLogger.info('creating web image'); try { - if (['image/jpeg', 'image/webp', 'image/avif'].includes(type)) { + if (type === 'image/jpeg') { webpublic = await this.imageProcessingService.convertSharpToJpeg(img, 2048, 2048); - } else if (['image/png'].includes(type)) { - webpublic = await this.imageProcessingService.convertSharpToPng(img, 2048, 2048); - } else if (['image/svg+xml'].includes(type)) { + } else if (['image/webp', 'image/avif'].includes(type)) { + webpublic = await this.imageProcessingService.convertSharpToWebp(img, 2048, 2048); + } else if (['image/png', 'image/svg+xml'].includes(type)) { webpublic = await this.imageProcessingService.convertSharpToPng(img, 2048, 2048); } else { this.registerLogger.debug('web image not created (not an required image)'); @@ -749,7 +749,7 @@ export class DriveService { }: UploadFromUrlArgs): Promise<DriveFile> { // Create temp file const [path, cleanup] = await createTemp(); - + try { // write content at URL to temp file const { filename: name } = await this.downloadService.downloadUrl(url, path); diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 6a1f233bd8..4601eca2f0 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -116,7 +116,7 @@ export class ApRendererService { if (block.blockee?.uri == null) { throw new Error('renderBlock: missing blockee uri'); } - + return { type: 'Block', id: `${this.config.url}/blocks/${block.id}`, @@ -134,10 +134,10 @@ export class ApRendererService { published: note.createdAt.toISOString(), object, } as ICreate; - + if (object.to) activity.to = object.to; if (object.cc) activity.cc = object.cc; - + return activity; } @@ -155,7 +155,7 @@ export class ApRendererService { public renderDocument(file: DriveFile): IApDocument { return { type: 'Document', - mediaType: file.type, + mediaType: file.webpublicType ?? file.type, url: this.driveFileEntityService.getPublicUrl(file), name: file.comment, }; @@ -297,16 +297,16 @@ export class ApRendererService { const items = await this.driveFilesRepository.findBy({ id: In(ids) }); return ids.map(id => items.find(item => item.id === id)).filter(item => item != null) as DriveFile[]; }; - + let inReplyTo; let inReplyToNote: Note | null; - + if (note.replyId) { inReplyToNote = await this.notesRepository.findOneBy({ id: note.replyId }); - + if (inReplyToNote != null) { const inReplyToUser = await this.usersRepository.findOneBy({ id: inReplyToNote.userId }); - + if (inReplyToUser != null) { if (inReplyToNote.uri) { inReplyTo = inReplyToNote.uri; @@ -322,24 +322,24 @@ export class ApRendererService { } else { inReplyTo = null; } - + let quote; - + if (note.renoteId) { const renote = await this.notesRepository.findOneBy({ id: note.renoteId }); - + if (renote) { quote = renote.uri ? renote.uri : `${this.config.url}/notes/${renote.id}`; } } - + const attributedTo = `${this.config.url}/users/${note.userId}`; - + const mentions = (JSON.parse(note.mentionedRemoteUsers) as IMentionedRemoteUsers).map(x => x.uri); - + let to: string[] = []; let cc: string[] = []; - + if (note.visibility === 'public') { to = ['https://www.w3.org/ns/activitystreams#Public']; cc = [`${attributedTo}/followers`].concat(mentions); @@ -352,44 +352,44 @@ export class ApRendererService { } else { to = mentions; } - + const mentionedUsers = note.mentions.length > 0 ? await this.usersRepository.findBy({ id: In(note.mentions), }) : []; - + const hashtagTags = (note.tags ?? []).map(tag => this.renderHashtag(tag)); const mentionTags = mentionedUsers.map(u => this.renderMention(u)); - + const files = await getPromisedFiles(note.fileIds); - + const text = note.text ?? ''; let poll: Poll | null = null; - + if (note.hasPoll) { poll = await this.pollsRepository.findOneBy({ noteId: note.id }); } - + let apText = text; - + if (quote) { apText += `\n\nRE: ${quote}`; } - + const summary = note.cw === '' ? String.fromCharCode(0x200B) : note.cw; - + const content = this.apMfmService.getNoteHtml(Object.assign({}, note, { text: apText, })); - + const emojis = await this.getEmojis(note.emojis); const apemojis = emojis.map(emoji => this.renderEmoji(emoji)); - + const tag = [ ...hashtagTags, ...mentionTags, ...apemojis, ]; - + const asPoll = poll ? { type: 'Question', content: this.apMfmService.getNoteHtml(Object.assign({}, note, { @@ -601,7 +601,7 @@ export class ApRendererService { if (typeof x === 'object' && x.id == null) { x.id = `${this.config.url}/${uuid()}`; } - + return Object.assign({ '@context': [ 'https://www.w3.org/ns/activitystreams', @@ -634,18 +634,18 @@ export class ApRendererService { ], }, x as T & { id: string; }); } - + @bindThis public async attachLdSignature(activity: any, user: { id: User['id']; host: null; }): Promise<IActivity> { const keypair = await this.userKeypairStoreService.getUserKeypair(user.id); - + const ldSignature = this.ldSignatureService.use(); ldSignature.debug = false; activity = await ldSignature.signRsaSignature2017(activity, keypair.privateKey, `${this.config.url}/users/${user.id}#main-key`); - + return activity; } - + /** * Render OrderedCollectionPage * @param id URL of self @@ -686,11 +686,11 @@ export class ApRendererService { type: 'OrderedCollection', totalItems, }; - + if (first) page.first = first; if (last) page.last = last; if (orderedItems) page.orderedItems = orderedItems; - + return page; } diff --git a/packages/backend/test/e2e/endpoints.ts b/packages/backend/test/e2e/endpoints.ts index c130093732..653520cf5f 100644 --- a/packages/backend/test/e2e/endpoints.ts +++ b/packages/backend/test/e2e/endpoints.ts @@ -4,7 +4,7 @@ import * as assert from 'assert'; // node-fetch only supports it's own Blob yet // https://github.com/node-fetch/node-fetch/pull/1664 import { Blob } from 'node-fetch'; -import { startServer, signup, post, api, uploadFile } from '../utils.js'; +import { startServer, signup, post, api, uploadFile, simpleGet } from '../utils.js'; import type { INestApplicationContext } from '@nestjs/common'; describe('Endpoints', () => { @@ -439,6 +439,45 @@ describe('Endpoints', () => { assert.strictEqual(res.body.name, 'image.svg'); assert.strictEqual(res.body.type, 'image/svg+xml'); }); + + for (const type of ['webp', 'avif']) { + const mediaType = `image/${type}`; + + const getWebpublicType = async (user: any, fileId: string): Promise<string> => { + // drive/files/create does not expose webpublicType directly, so get it by posting it + const res = await post(user, { + text: mediaType, + fileIds: [fileId], + }); + const apRes = await simpleGet(`notes/${res.id}`, 'application/activity+json'); + assert.strictEqual(apRes.status, 200); + assert.ok(Array.isArray(apRes.body.attachment)); + return apRes.body.attachment[0].mediaType; + }; + + test(`透明な${type}ファイルを作成できる`, async () => { + const path = `with-alpha.${type}`; + const res = await uploadFile(alice, { path }); + + assert.strictEqual(res.status, 200); + assert.strictEqual(res.body.name, path); + assert.strictEqual(res.body.type, mediaType); + + const webpublicType = await getWebpublicType(alice, res.body.id); + assert.strictEqual(webpublicType, 'image/webp'); + }); + + test(`透明じゃない${type}ファイルを作成できる`, async () => { + const path = `without-alpha.${type}`; + const res = await uploadFile(alice, { path }); + assert.strictEqual(res.status, 200); + assert.strictEqual(res.body.name, path); + assert.strictEqual(res.body.type, mediaType); + + const webpublicType = await getWebpublicType(alice, res.body.id); + assert.strictEqual(webpublicType, 'image/webp'); + }); + } }); describe('drive/files/update', () => { diff --git a/packages/backend/test/resources/with-alpha.avif b/packages/backend/test/resources/with-alpha.avif new file mode 100644 index 0000000000000000000000000000000000000000..05f494212eff008216ce34d939b545aeaf288e88 GIT binary patch literal 10032 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 literal 0 HcmV?d00001 diff --git a/packages/backend/test/resources/with-alpha.webp b/packages/backend/test/resources/with-alpha.webp new file mode 100644 index 0000000000000000000000000000000000000000..d7b0d70b7fdbbd9ef4be7e2d680aeee7b7821d5a GIT binary patch literal 4984 zcmYkAbyO5w^T&4=mTm!oC6-1yrIrvx36X9kq`M_nSXerQMY>nIM3EK{1QbL>IwU2e zq?d->7oYd}o%c6q=FI1wJ2Us*|GwwyYdm=1bqfG6QB%=1)|D|O0RR9DH-Y=d?>*90 z=O6+Afcr7m&CbnO+{>3GZFh=)%2l|}Hr@D6@y{mrHhHPk>X&u79j8nPNyj%*eOYbW z?OCx|0Cfza2#1S#U22_>@=e-pu|DW{?&E|wyvUGS?y=cH--&{SiOwHg{yS_In@I*H zp0oAW$)&1HcExF~y_I~1xFFlUhJs#W_@@v<HiWH55NSkB@sGaOTg?cmeV&vLi|*qS zt>sNKs;f^ibpGUKX_*<7STnHymAFX6JHI1aUEI2mHY<8sj5e@=?6vu+o@bx961xWP z7xZ*4on2-~4D#8j1Me#v!g#VxE_AmR?QVf*YIY@@izJ!FrAU_(AMB}BnQEUydPnih z$PyTXTCG#|UYX;&3i5dRYEQK&rO`fp`wmUWc{OzGMafxd8in&N$IRJdpDLz!JJkeY zvFmV2PAyl>QzBx4e0xI$3gQ^LTXlfSX!>!~^4(X@rBZdG7`RySo^}G&PknieCT-QP zEc|C^6Yei3>u(udLD<{>ym26SmE13qDae*`<&giv61o}0?;?QN*AC7uX^$b3-;`i+ zZi~Ott~%{Ma1akNrR403tqETBqw3i%i!|o^5kl`Q_^^QY*fe4l!lT>u9sl;XXH-7! zwL%dQ3or30IA?)A6?@N)2Fjcz#RVw<U|Pl9XmLK~s26aj;4T|6fSdA{5w$b>7s-h` z^yERP72aDViEEK;^<GD<Nj0v{8$%#Ov~d4rsHSBGUO&7#S}6z<88NtDkv_p;$C_$5 z@6IaFUfl9a?(uv|h_*j9EGb<T%Xv2LeUMu{KpFItP*d5thuc%;P^p+7lDc$E(>1LR z8|_phj?NulwWoob6ENgOMEoF6dxp+IKFWK3XX%zz@b7uPJ`NWj31Z50yn+KBX-aN0 zEo}mxy%nx-i$}d5iUc9m8q3Sx1}WgjXrrDxFYmf6NhQDG(=HV%ZU4ph{dv{n{VaaU z#J4KEP@*--{D<ywOH+jvTpfw8sy=t8Yw|GAD)+SG*{8!YdcY_W%TsnS(o*oOEGC1@ zLyCF>N#i=$MGb}I3D<T@XPf=O7>E14%d99=)pHom%oE6rT&_+yXfB?61uJi2;EJRM z-=7wKy^03b=~R|Rz8%|i{D~Zmcv_P70Lt5*{iwNe1E}9wB*|tM1s|02*M$Mol8SvN zwJckd3lAwUM8jQbYvCg5WS3hh>jJ?<8!Kf8G79S7Cv<ZcB`^%bG8x@#02Jf_-Q+X* zWLErvcIsvx;(m%nN4@n%LIsku9U9t6(6}b)&gO*a-QpNv1x_XG(8PS7=&XHd(H<66 zK<IXDxw*Pvi7%;1mS3Ha3xMMOIAQJsCLP*V8fMDZK;Okxd-oqwek_`c0w@oBkkIKg zpowqoZ1oHsHt=E9HAFW3>7*CR;Z)f02#dt6=XxISu)t5Y#v39FslSbSUOqHrY_CTc ztFBEP)Ig*J*5v{jx!;C*>aLq82u4@T;n4<`M;;vHl%sXm)l)xx^&*bi)9`TenNC?E zN8lMi88jA1MFnLQIYzd>l51L1y;5+I;`&{z9{7QsF(z%kkxZSH@Xm|eIj^k8><6;Z z#X$Y!A1;!@DLvc-#e$>B$5QmwjMmbszgPx-CBCi*W6r;m*c(W1I;PINEH<N#e=zL^ ztvP_zLSixfM;+n)-?;{rY3-IJsnoKs_IWQvMi4k^3|gagq_Cy;EnmL-7s^5jX#m&a z&`MA!Ak0E3_{S1_jDUhtyzA6A6!VxD&_sw)JX1kFMPMFt<3}xjm5PpRV*qEV>_8bP z-mWw#+KaNHmW4}O^sSYlV-|9nTB2O2b9TA_D^Whw1vB|WEm1*hi!v&rN+JRR^ab1| zMm($zh@(4DLCzu_R)8q~My=+h6h-Suz~LiAb<DP30A$1Y5n#~hwpD`3v4iKLAG%)e ze8ITvTd!KR$q>WBn_vKuq_`oDG%I&TBQ(FIF-2LjzT?W=%at$O+5vJtv1V)pdhQ@_ zp1yAU1jL*Day2u`0-eM0#8|?$`^TRpItrH~@i@i-K{lnp-tC;Knnx-Fha^&3)(UT< zs$OJIci5WlfQg?kPw3J`9?B4uo06mM-8Ft}<v$fv6K0wBgwYN#CBp(b-VVZmIz1DU zB4`P{T}oebCR+iXOSlNd_)#cYy^yrCKbXPSMe3l8DBeZ?2pkU1?-2)t)w_K_a`}E} zxqs%u)c+b2utv+1+-?WlZcPMz$Btljb3aCq!_o$z+Bgwd0rv>O(PkqOe=Mr*jD_oG zOjH}kMizU{PfjhB;l!S!G;y(=by0FZ7L7L~SJ(W(V(0g&!r3<Rn>JRCQIiC^*%%V3 z04<c;jH$~#=X>if#L|%ZmEmEIy%!OFxh+m11H>N!IA~4q#~l$5U1-!>GF3KR*{NhA z5~~@VzF(n|#2HHFE+F{<ok;aDbN-HdZF`LTNlnmAej7tp2ZFla++0sOly$ZxrQ^^X z&>c4ur>k_bNJ`(h1b2{}Nr<+!EkCMdDlyR8CO`aH>1k2HD&c%cnH;`CE$9{QI1Re? zqd|ELr=u3>YUV?g9b%scfCq@65FJ{ev<~htkIiov`9h$gG3}=971-P;sGzR<3txyz z#ya>X9fi!X*RBX5m)0Zsz2SXt*B{FJXhoqZg{h?v9TgdL8-yo{w6(&A>Wh-fQ^pOS zv(`F27wheh^A@D)BM2Xxw9aBCa!=fFzH7bDOAUY)TH*A?CT`QMt}6p|Z%8blBe*y$ zjxFj&J3uvW#DgddkPqYs00BTn7P6>&NLLC}n6*s7-Mzk1sI%E^N9M#&G3BeBaY}8u zv@qO${mIc)Icy>RIppN>a!OzJ59V?N@g8A~4ab&WWa4mFO8mH#P_YvLf*ebHoq2&c zqCCM3E8%b_`&Pg4E+`K?PpoD-&t7Qbgs}5}@QzI|cuRN}(uYcCot;WJtRZ3s4hRMy zAUMLU-0O$ew@*CJJFh>6<19P(aaGs23j(a#)f6^nM+divqP+fyW-Z2bDQH}5V)6DZ zFnDK#rr-%kEad~v1!ZPeDF9aJy1IrCO}JG_qtmCvy!$`%uQk`lUlY049`2`d@g!Mz zjO2P#&cTmUe1zQwNfFWLGDlpyKR#s5(4x%Le%1DQnVow`S+yG~IT$}C){3v!FPGZC zl9rf5=17(hTsY*_;OMwq^v=ZjL3E}Pb&_Cq;l!G2`21h{egtJRxa};PasB1<-}T(D zjmqiwpTd?$NoD+)v_2g;gY)EWi(67AsPsyje;M+4P7Y>*#B!MJI4?4}xhC64R%$j) zH>+T6Pe>KeVM&}GF~-xeg9IRCgAiqQ8-AM0I{)|x*2mZ<T1nDs>?i2K<b`}VWgqiq zk~gDm-h<lzKKeHRfW>-C-Y7+@5C?K+2T!Vlvd}In_ma;$XAV&)H)WjCX-umhq?Q7b zUa_|JUf11VD=Ttq+<7J3d?HT(<1@HG46f(LhR`1KBP7pf(Z;*sm~u*LB<<khQmmlv zpNuNIIt%(sdCzuU;(FEfDfX08k;!@fRku8)0P1_MjiX&66Q@nHFOP?IXZNSQbx>q| zcs92&FrpGw7deJxFlQk{-wAht)_#@t{n8qyuYJp8jqGxbOi}lLKHPS+={x<BGX6kX z*i04fNs2gr5=R*6tLz&n#=GG%C!Pp;@_p4d(9YpD+bw$HmtRl9k2-KDu2Dh0IkiUR z$<l-0_b*3w6bZ(E-M6l^^bM`w>b$rbE{EsQ57ZQU3&8yuS%gcfzXgXKxOJV0Xt`zD zWOL<A^)^2e<@Tv3(sT&u*%WR+Gh~?*ybux&ra1%wSP7QpGlQk5Re+&BXO0m=b##o| z>gUTbZ$NjxhEA8A!=|`A#%40Aj=Mf3mr>aj;x4}xPxKhtCSrb(D9VLHgcfnb1qZTy z!%R8KXGT_>z(%$?8@g@(z=hR@docR=%KowO1_?thhwd+r1RKVOTKWw?HH$CAzA>4} z(0|L+lw^GENDAiMzDFhQ+RFmx?<Wk`8}}6)Jc-4Qx?e+^mb46GO?eFbhsky#LS6fj zgn8+%@D9$Ha%O0>p=!Q7HPiAszq7yJQkhoZ%3A(#gg|BdAY?r99pZs*v<R}v{Nore z4tK<*`AO^Vy}iEddk)v;UL-Utg%G8l%#Y2Q|Jnh+?+wlnuX5c>NgJ?chL@I%ZVD<n zCa#$E2qw?ljLB$SaDt<9B!xhTo}fLO*XlOKrMJ~OW&L6t&<)1$TdOgjTFy-+o_3&Z zpTqhE4{jOn3gWx9_||a8em&+mN5!-fRw+C!VwFOIH)pAW3pFTeJ)XMIWlAT$o!fR) z>y}sG9ObhcwSJ%drYJUf^j%>Uoh4gdLuxVJm=0{Yn$x7}Ob0h!>0}Up4*}WpU!z|) zF_V&Q@vHUHuLuJ6>3Y~{2K&G3&#d|eZSIpv(`=o4ndW^f>ov7=>C7~N=h!z;C(@HI zO@x8?cGCvt`m=R0(UQ0z`=8O@-Ms0l;lqsr&({NuIQPt>qmR0zHZKw8yD9_5nb9D8 zq{4nd`qMsN;cdDTl3M=8TgAb$ndZGB@xR~qA$=?*7o{*-G>7kkq8(WJE{}^c6;xMS znxi~kSfW(9YFkvPTXH43JOp-%D!fLkNI<)vwKDzBx+~L5%OM=j_Br`%xA7((Tj7Mf z3_kDZ0Bejr+|-sEcheIe3OS?OySg)ogmPt_O`Xi?L|2rG%wCoT;eBs@`|ZrKm<(T| ziZubZ4;~Solktb?k0s6W0gp|W-<uRlFw>YCX{BI+f`q+f+JcYrYPQZ&7T!1ChtaI8 z3};Yc+YIV4Qkq+#1}kh6Bzy+`twNN6eX9kes?pOnMAseOpxhHEy)pop&3X>>KF+KP zZrzGY^89e#!gmXkEdPaf$EZl!&Th!o><7hb`I<>PosSB_HZ8alxT*#IeYzHx7Vry9 zAt5k_(2ELA?-gngG^F=<a9=R1cg<)&*2M7rQqsfsdekAP&fVS}V4SSi-Q;aXJ^$_1 zXa_q|rnMcW2A#->f+P<}8>9@P)80ip_Io=!!HIp(?7UAW)~OaK+zmPPiK&RZgN?oo z^DpD_3}#k5o=r8=rqdx%aeVIwUEP2Rt!pIa)$V*QZW|F&zqJl;$D8d|_c8|n@Cf|c zIT_EhuYZXgedOnX*jk8+*jV6br+ZVqM$pYTDDLCVNWw8T3tRQws-#_MO$DDUj$={8 zK*U!<oDcgeI$y-rWa6Ad_D;<SAN@%h5r>|eq#^Qrprd!B)7JuHxe|^Y<+l{!nyK|~ z9|Zsvu1ggzL=Af@lbk4B{!jw8FF7k$M(}zp%#aNE=Kg5J2jk@fl}U&jF*iHzX$d5Q zPJel8By8I4!inbKocibMB~q)`zAfM=Mc8qn+>)nyWv1ke_`7kIzV)`4sqs${?K@5L z{0fcxtE11VB;RtsU{(q^(=vL37?Uh@r4V>oYjw)_ab`@F*YYV0FPE}aZ;3XGCml;Q z7#4`fcO;y<r>?__$>e-F_;rQNYDF9W3Vs24Lr25bs_DQOcZ@W5FGo}LOB>|Of0*qz z`w1xu4LE&CQ^Lf+OYkzI;~|}NWXjXdK&z0{{KE-05lHrAQTkyaBk0PLl-)%zUf<wi z`}YN`)O3o|rnI9pR=bX%uH%q=q2dG4T6CW3$j7Q4@Ow}cPYC%JgjbWVUoKnNmo!Un z@;$ML1TV^FS%#^Hdc1ukN-QL%SWrjE^~J1}m_PbZb&I`Bk7S)UpogwYng|&YSJJe~ z%9VbW^du<Wut;~$mo66(=d!Y8r1ZG4(oMa+p3g;jt^{`2UY=>A+iA@M%hdb!<l(9| z)w0Vp^Nx#HM3Qrq)U_)-w6Ui=UY@nQa^NY7j9YFKwWLp(LquS7=51OGagts#T+Lsk zN%Z>EP6_UJi~r@Sx(}nvv#{~xf8)%<%CJ_H<ohneVJJ1(Fe_e=o?9>l-pS?FeX_96 zHa}(MFk^K${aEVj@W#2>9O4boPiEOhBvMn$lPUiU4d0cQ%_DNJ&B%*T*(9CgdL)7D z?CFSJh_ujN8}T(K*!e1#03b+<7Nw%dz#T3pGI#A?1|)D<t}`Iz#6mmA*e1-XF}pc5 zmK*cJt~J=5!G?=@mv3bZ;W4<9EhXHbFWjd=CMYxQkr6-<F*egjTZgZ9xmXIkf(F{U zTHF`beNz0^wF}(Zb)zW+9smGprWy|>Z&*WvA8_*p1t0*>0P${w<;`!@O)vq$|77DE zhWyKxH_Z2M4d{l&fFJ<XO?J2m=NSBd>Yv~6U$ef6zjOXCd)YX9_z8R1`$46IMTNxy zU;qF`2*AIo5EYjY1)~3VG6?<ONq^h%{vU(?<(8YCzXrM~0R1yTUsmRZ{+%W!D*AW# EKN@#aRsaA1 literal 0 HcmV?d00001 diff --git a/packages/backend/test/resources/without-alpha.avif b/packages/backend/test/resources/without-alpha.avif new file mode 100644 index 0000000000000000000000000000000000000000..9ea23608b85155a9bbd933961dba3b6604ef8147 GIT binary patch literal 3982 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 literal 0 HcmV?d00001 diff --git a/packages/backend/test/resources/without-alpha.webp b/packages/backend/test/resources/without-alpha.webp new file mode 100644 index 0000000000000000000000000000000000000000..a51091efe24081ecea3d6f38d35bd8625d48b608 GIT binary patch literal 4474 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 WO9AMwgQ0@_CHvP+QbOXN+y4NnZExrR literal 0 HcmV?d00001 diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts index 37e5ae10d6..d1a5d6d949 100644 --- a/packages/backend/test/utils.ts +++ b/packages/backend/test/utils.ts @@ -204,7 +204,12 @@ export const simpleGet = async (path: string, accept = '*/*'): Promise<{ status: redirect: 'manual', }); - const body = res.headers.get('content-type') === 'application/json; charset=utf-8' + const jsonTypes = [ + 'application/json; charset=utf-8', + 'application/activity+json; charset=utf-8', + ]; + + const body = jsonTypes.includes(res.headers.get('content-type') ?? '') ? await res.json() : null;