From 5b7c6735ed37b9f8c6d76f1da9ad36741c532359 Mon Sep 17 00:00:00 2001 From: Namekuji Date: Wed, 25 Jan 2023 15:58:15 -0500 Subject: [PATCH] add listener online indicator --- audon-fe/src/locales/en.yaml | 2 +- audon-fe/src/locales/ja.yaml | 4 +- audon-fe/src/stores/mastodon.js | 3 +- avatar.go | 12 ++- config.go | 37 ++++--- public/{logo_back.png => logo_back_blue.png} | Bin public/logo_back_white.png | Bin 0 -> 5692 bytes room.go | 101 +++++++++---------- server.go | 2 +- 9 files changed, 87 insertions(+), 74 deletions(-) rename public/{logo_back.png => logo_back_blue.png} (100%) create mode 100644 public/logo_back_white.png diff --git a/audon-fe/src/locales/en.yaml b/audon-fe/src/locales/en.yaml index 206cb88..825494b 100644 --- a/audon-fe/src/locales/en.yaml +++ b/audon-fe/src/locales/en.yaml @@ -64,7 +64,7 @@ startListening: "Start Listening" browserMuted: "To protect your ears, sound is muted by the browser. Press @:startListening to continue." onlineIndicator: message: "Do you want to add the online indicator to your account's avatar like this?" - hint: "Audon will remove the indicator after this room is closed." + hint: "Audon will remove the indicator after you leave." warning: "Your instance may take a while to reflect the indicator." sure: "Yes" nope: "No" diff --git a/audon-fe/src/locales/ja.yaml b/audon-fe/src/locales/ja.yaml index d7d1ee8..8f8cf65 100644 --- a/audon-fe/src/locales/ja.yaml +++ b/audon-fe/src/locales/ja.yaml @@ -63,8 +63,8 @@ errors: startListening: "視聴を始める" browserMuted: "大きな音であなたが驚かないよう、無音になっています。続行するには @:startListening ボタンを押してください。" onlineIndicator: - message: "あなたが部屋をホスト中であることを表示しますか?「表示する」を選ぶとアカウントのアバターがこのようになります。" - hint: "部屋を閉じた後、アバターは自動で元に戻ります。" + message: "あなたが部屋に参加中であることを表示しますか?「表示する」を選ぶとアカウントのアバターがこのようになります。" + hint: "部屋から退出後、アバターは自動で元に戻ります。" warning: "サーバーが変更を反映するまで時間がかかることがあります。" sure: "表示する" nope: "表示しない" diff --git a/audon-fe/src/stores/mastodon.js b/audon-fe/src/stores/mastodon.js index e4274af..f2df163 100644 --- a/audon-fe/src/stores/mastodon.js +++ b/audon-fe/src/stores/mastodon.js @@ -48,7 +48,8 @@ export const useMastodonStore = defineStore("mastodon", { }, async revertAvatar() { const token = await axios.get("/api/token"); - if (token.data.audon.avatar) { + const rooms = await axios.get("/api/room"); + if (token.data.audon.avatar && rooms.data.length < 1) { if (this.avatar) { await this.updateAvatar(this.avatar, token.data.audon.avatar); } diff --git a/avatar.go b/avatar.go index 6d35b9a..f3233ca 100644 --- a/avatar.go +++ b/avatar.go @@ -22,7 +22,7 @@ import ( "gopkg.in/gographics/imagick.v2/imagick" ) -func (u *AudonUser) GetIndicator(ctx context.Context, fnew []byte) ([]byte, error) { +func (u *AudonUser) GetIndicator(ctx context.Context, fnew []byte, room *Room) ([]byte, error) { if u == nil { return nil, errors.New("nil user") } @@ -73,17 +73,21 @@ func (u *AudonUser) GetIndicator(ctx context.Context, fnew []byte) ([]byte, erro if err != nil { return nil, err } - return u.createGIF(newImg) + return u.createGIF(newImg, room.IsHost(u) || room.IsCoHost(u)) } -func (u *AudonUser) createGIF(avatar image.Image) ([]byte, error) { +func (u *AudonUser) createGIF(avatar image.Image, blue bool) ([]byte, error) { avatarPNG := image.NewRGBA(image.Rect(0, 0, 150, 150)) draw.BiLinear.Scale(avatarPNG, avatarPNG.Rect, avatar, avatar.Bounds(), draw.Src, nil) baseFrame := image.NewRGBA(avatarPNG.Bounds()) draw.Draw(baseFrame, baseFrame.Bounds(), image.Black, image.Point{}, draw.Src) draw.Copy(baseFrame, image.Point{}, avatarPNG, avatarPNG.Bounds(), draw.Over, nil) - draw.Draw(baseFrame, baseFrame.Bounds(), mainConfig.LogoImageBack, image.Point{-55, -105}, draw.Over) + logoImageBack := mainConfig.LogoImageWhiteBack + if blue { + logoImageBack = mainConfig.LogoImageBlueBack + } + draw.Draw(baseFrame, baseFrame.Bounds(), logoImageBack, image.Point{-55, -105}, draw.Over) anim := webpanimation.NewWebpAnimation(150, 150, 0) defer anim.ReleaseMemory() diff --git a/config.go b/config.go index efb1c25..9959997 100644 --- a/config.go +++ b/config.go @@ -21,11 +21,12 @@ type ( } AppConfigBase struct { - LocalDomain string `validate:"required,hostname|hostname_port"` - Environment string `validate:"printascii"` - StorageDir string - LogoImageBack image.Image - LogoImageFront image.Image + LocalDomain string `validate:"required,hostname|hostname_port"` + Environment string `validate:"printascii"` + StorageDir string + LogoImageBlueBack image.Image + LogoImageWhiteBack image.Image + LogoImageFront image.Image } LivekitConfig struct { @@ -92,12 +93,21 @@ func loadConfig(envname string) (*AppConfig, error) { return nil, err } publicDir, _ := filepath.Abs("public") - logoBack, err := os.Open(filepath.Join(publicDir, "logo_back.png")) + logoBlueBack, err := os.Open(filepath.Join(publicDir, "logo_back_blue.png")) if err != nil { return nil, err } - defer logoBack.Close() - logoBackPng, err := png.Decode(logoBack) + defer logoBlueBack.Close() + logoBlueBackPng, err := png.Decode(logoBlueBack) + if err != nil { + return nil, err + } + logoWhiteBack, err := os.Open(filepath.Join(publicDir, "logo_back_white.png")) + if err != nil { + return nil, err + } + defer logoWhiteBack.Close() + logoWhiteBackPng, err := png.Decode(logoWhiteBack) if err != nil { return nil, err } @@ -112,11 +122,12 @@ func loadConfig(envname string) (*AppConfig, error) { } basicConf := AppConfigBase{ - LocalDomain: os.Getenv("LOCAL_DOMAIN"), - Environment: envname, - StorageDir: storageDir, - LogoImageBack: logoBackPng, - LogoImageFront: logoFrontPng, + LocalDomain: os.Getenv("LOCAL_DOMAIN"), + Environment: envname, + StorageDir: storageDir, + LogoImageBlueBack: logoBlueBackPng, + LogoImageWhiteBack: logoWhiteBackPng, + LogoImageFront: logoFrontPng, } if err := mainValidator.Struct(&basicConf); err != nil { return nil, err diff --git a/public/logo_back.png b/public/logo_back_blue.png similarity index 100% rename from public/logo_back.png rename to public/logo_back_blue.png diff --git a/public/logo_back_white.png b/public/logo_back_white.png new file mode 100644 index 0000000000000000000000000000000000000000..981c8abd737a3fb0de2ed58f6b8702263bc600b5 GIT binary patch literal 5692 zcmeHLYg7~07EYw)DZZr&OC5t+X`N&yk4Z93YLREOfiy(4Xf2b>1V%_E zDvAYRVZq1sK@p2+tKtI-RMD!awAD)G)@#Lzwf2HaYt?%a5U}<3*0tLHGFdapoU`}0 z&-b0Z_sp85s;CHGZ+~wVi{-0`3{`{QiO$2*9h_G@*lS?1`u&iunQ2uMcF1IA^mH-> zS<_4uL^)_Zi{<$0`+ViDwh4o>Tgy4qR1eRbG!I%*b^|(bn%!`GPf1Hn!^G+D42e%1 zRrG)*9kt-T^z4{O&6K>N2(FZgjN5Gr3;am%`Si0}KA639jIN`(P-%gQ><-v8Y7edTb$t&(ZyS5+Ol zG`V)+izhQLQg@cro?vXDI|Hr`z8VsVt>qNB@y96CXP~u{+-rT^hadKt`rc9X;9Psk z{+LA(y8UI$yYFvnhSOV0=FmZJPx#M}D;Zxh_l90Lv9P)Q*6Bh~h2P}6uav0ic}pK; ze0mN2qNs9N*~ks2zT7x^+MDqC@7HOgMtP;DS!C{BZ|{RVQf;-d*JfQzy%L^1Vy}CU ztxR}rrfrk^3-7I}yY+5iz=`YqQ@G83iuHx=uZ&3bG8ufTy;}}77JZZq@3_!UV9yL1 zTIablqxjrb-U@V8zcYUJ@_)V1-XCjTcSY|d7_=ef`Ojk)j`>NXtmv1CZIZ2u4357W zqZR+$IwAM@xcJ0vrv;Ihca1r#2o~%qmRD$t&lK zOwMd=a@5m>yU_h9V-}soXRN6|;=Z;2hZ^5|M@1jzlr7y}NLhSdj;$h3=3DN_c=gvW z7d6YO=Q)1#AL8#Pm2svveG+D(;~MIxtyRyhFCKn;I5T5J)BbjD_09Y{2kwoYcOj|v z4*ga6w^!jfdXJ@G<-JXot|84!@xx#W%TgWKPl zxu9W;YSVImp88xPGxwTpL1g2BsARqy5;YaNIh2hFqxG|LUy3&8U5GW^|K`-5cbtn|C%}dZVpf(BxOyKI~Mfk$=@=o4M(y z;Q2GQw)kemEyzAJ@irTr6%QSS)rH9TK8agoHdw zeUR|Q^H<9wYgNOtqhspTFAYdlr5sbOpR{C|WbW`~sGczIRDfQn40)9v#0%bTxp#$PHJ7FXx^=Eql0Rkz-{G=E{^Hss`We-Gi;*tv$R zbtiW$lkfD5A2c>=a9$zxnL_P-=(a8TYmGhS{cl_DCfqJdTh3;$cI1!TqC5~RJ4go< z-(9+?eB1|ht#!HyZ{>EbZd-PgDPGR?kqPGN&$idSp{+cBWU5Ein(c$52Orfaw`PoO zt2~~zyef8kcjIzHO8&#k{~m4RK=^vA&`Q}{BCyNv;)}S3UXhk!Xuj4w#z$HjVOK}|r6KGW| zmTa=aMCg(zE2O0oXrr9-L-k<}M3ZvP43QF1nnI{VIx^i%#iU1Rbm>VtDao1qs<+I6 z0{{bMB_M|(*=WHXa*hiZ2mhVJJPzbCu_nnmGnFbRgfUZ)kSpXOaF~Nm<#S&3hGb?^ zkE=t&yCJ}poRes^ns6S^Zntyo0xn}t;Gt5fl!x$nd_D{;U`v|ON;qJnCC~}cg%L_w zbY|LQr5PjS#3Zzg%_`?`z&!M5eFl?K*#mF1bgKaL;5i5r59J~}gMruA!(t6f1t8rE zdZLF#13EfSO<5S5Sx1GXQbucFUkFmy<8QK=lU;O39gj+;48YU^qN0z5j8G_5JswU8 z5@>_TMhW5yC=5#D|5XSPM%8CnXtrq4B5D}~w3&pUM&H~<{N z7r+P#qe2ae-~u6zNMS^TBV7S{tQoV0VUpz>CpXBsgdQ*@C~K0i5>JE^;VAMeIIu`s zpZ5Q(oka}EKzNWrk+j9inA2QCU6ma}rF30&T_)46l7=8xapHuoi?Gf`vnzD~TGu4~ zr0n^lTi%0WVf0ozVWxr;fWC50u(NkUsz=oa@r7IznmB_tl8oIFckzG9 z&iez*EJP~xD_*)p!k9pT{@mRVevdCkAf$jG#4sV@Q!qscMX*#LlENsa(~G5IN{mUU z#~1x)^X-!te*<5UlpryQ7J>ByDu9JL5eXCE3==4UYC)^vVgKQfbT^K_G6V!Y z3-VO@K9lR2Tu-IIQyD+Yu4i&Rl>$#?{4BfvG`YNc-$77D@L+2PZy2K9yYc~eJK?UK z77@yN==_!*+?oeQyiAdAT39S@pz~lm{y8}n40>1<$}o>s_DIj6@cpB|#Dk%1MQE^Q zX6^SEDt)J*{lm@#47^=%Y`}_zm)w{5a>9=dn8S%Vvo7B+@ZiOLuS}gie(~HLqD5Y_ zfBDF5^XBJ9WLLY1)Ax)&7{0za?|u2kiakjJ{~OI8SCpo?`zMwz`pv1crRLmud%t6! p)~rZZw)m#ZQm;JSbUWa(@0OrZ`H4BVoNt9$im<5AiYf7#{{^V07v}%~ literal 0 HcmV?d00001 diff --git a/room.go b/room.go index 05a9fea..5f5015c 100644 --- a/room.go +++ b/room.go @@ -326,66 +326,63 @@ func joinRoomHandler(c echo.Context) (err error) { roomMetadata.MastodonAccounts[user.AudonID] = mastoAccount - // Get ready to change avatar if user is host or cohost - if room.IsHost(user) || room.IsCoHost(user) { - // Get user's stored avatar if exists - if user.AvatarFile != "" { - orig, err := os.ReadFile(user.getAvatarImagePath(user.AvatarFile)) - if err == nil && orig != nil { - resp.Original = fmt.Sprintf("data:%s;base64,%s", mimetype.Detect(orig), base64.StdEncoding.EncodeToString(orig)) - } else if orig == nil { - user.AvatarFile = "" - } - // icon, err := os.ReadFile(user.GetGIFAvatarPath()) - // if err == nil && icon != nil { - // resp.Indicator = fmt.Sprintf("data:image/gif;base64,%s", base64.StdEncoding.EncodeToString(icon)) - // } + // Get user's stored avatar if exists + if user.AvatarFile != "" { + orig, err := os.ReadFile(user.getAvatarImagePath(user.AvatarFile)) + if err == nil && orig != nil { + resp.Original = fmt.Sprintf("data:%s;base64,%s", mimetype.Detect(orig), base64.StdEncoding.EncodeToString(orig)) + } else if orig == nil { + user.AvatarFile = "" } - avatarLink := mastoAccount.Avatar - if err := mainValidator.Var(&avatarLink, "required"); err != nil { - return wrapValidationError(err) - } - avatarURL, err := url.Parse(avatarLink) + // icon, err := os.ReadFile(user.GetGIFAvatarPath()) + // if err == nil && icon != nil { + // resp.Indicator = fmt.Sprintf("data:image/gif;base64,%s", base64.StdEncoding.EncodeToString(icon)) + // } + } + avatarLink := mastoAccount.Avatar + if err := mainValidator.Var(&avatarLink, "required"); err != nil { + return wrapValidationError(err) + } + avatarURL, err := url.Parse(avatarLink) + if err != nil { + c.Logger().Error(err) + return ErrInvalidRequestFormat + } + + // Retrieve user's current avatar if the old one doesn't exist in Audon. + // Skips if user is still in another room. + if already, err := user.InLivekit(c.Request().Context()); !already && err == nil && user.AvatarFile == "" { + // Download user's avatar + req, err := http.NewRequest(http.MethodGet, avatarURL.String(), nil) if err != nil { c.Logger().Error(err) return ErrInvalidRequestFormat } + req.Header.Set("User-Agent", USER_AGENT) - // Retrieve user's current avatar if the old one doesn't exist in Audon. - // Skips if user is still in another room. - if already, err := user.InLivekit(c.Request().Context()); !already && err == nil && user.AvatarFile == "" { - // Download user's avatar - req, err := http.NewRequest(http.MethodGet, avatarURL.String(), nil) - if err != nil { - c.Logger().Error(err) - return ErrInvalidRequestFormat - } - req.Header.Set("User-Agent", USER_AGENT) - - avatarResp, err := http.DefaultClient.Do(req) - if err != nil { - c.Logger().Error(err) - return ErrInvalidRequestFormat - } - defer avatarResp.Body.Close() - - fnew, err := io.ReadAll(avatarResp.Body) - if err != nil { - c.Logger().Error(err) - return echo.NewHTTPError(http.StatusInternalServerError) - } - - // Generate indicator GIF - indicator, err := user.GetIndicator(c.Request().Context(), fnew) - if err != nil { - c.Logger().Error(err) - return echo.NewHTTPError(http.StatusInternalServerError) - } - resp.Original = fmt.Sprintf("data:%s;base64,%s", mimetype.Detect(fnew), base64.StdEncoding.EncodeToString(fnew)) - resp.Indicator = fmt.Sprintf("data:image/gif;base64,%s", base64.StdEncoding.EncodeToString(indicator)) - } else if err != nil { + avatarResp, err := http.DefaultClient.Do(req) + if err != nil { c.Logger().Error(err) + return ErrInvalidRequestFormat } + defer avatarResp.Body.Close() + + fnew, err := io.ReadAll(avatarResp.Body) + if err != nil { + c.Logger().Error(err) + return echo.NewHTTPError(http.StatusInternalServerError) + } + + // Generate indicator GIF + indicator, err := user.GetIndicator(c.Request().Context(), fnew, room) + if err != nil { + c.Logger().Error(err) + return echo.NewHTTPError(http.StatusInternalServerError) + } + resp.Original = fmt.Sprintf("data:%s;base64,%s", mimetype.Detect(fnew), base64.StdEncoding.EncodeToString(fnew)) + resp.Indicator = fmt.Sprintf("data:image/gif;base64,%s", base64.StdEncoding.EncodeToString(indicator)) + } else if err != nil { + c.Logger().Error(err) } // Create room in LiveKit if it doesn't exist diff --git a/server.go b/server.go index a434fa5..1b236aa 100644 --- a/server.go +++ b/server.go @@ -170,7 +170,7 @@ func main() { api := e.Group("/api", authMiddleware) api.GET("/token", getUserTokenHandler) - // api.GET("/room", getStatusHandler) + api.GET("/room", getStatusHandler) api.POST("/room", createRoomHandler) api.DELETE("/room", leaveRoomHandler) api.POST("/room/:id", joinRoomHandler)