kopia lustrzana https://codeberg.org/nmkj/audon
add listener online indicator
rodzic
906170c110
commit
5b7c6735ed
|
@ -64,7 +64,7 @@ startListening: "Start Listening"
|
||||||
browserMuted: "To protect your ears, sound is muted by the browser. Press @:startListening to continue."
|
browserMuted: "To protect your ears, sound is muted by the browser. Press @:startListening to continue."
|
||||||
onlineIndicator:
|
onlineIndicator:
|
||||||
message: "Do you want to add the online indicator to your account's avatar like this?"
|
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."
|
warning: "Your instance may take a while to reflect the indicator."
|
||||||
sure: "Yes"
|
sure: "Yes"
|
||||||
nope: "No"
|
nope: "No"
|
||||||
|
|
|
@ -63,8 +63,8 @@ errors:
|
||||||
startListening: "視聴を始める"
|
startListening: "視聴を始める"
|
||||||
browserMuted: "大きな音であなたが驚かないよう、無音になっています。続行するには @:startListening ボタンを押してください。"
|
browserMuted: "大きな音であなたが驚かないよう、無音になっています。続行するには @:startListening ボタンを押してください。"
|
||||||
onlineIndicator:
|
onlineIndicator:
|
||||||
message: "あなたが部屋をホスト中であることを表示しますか?「表示する」を選ぶとアカウントのアバターがこのようになります。"
|
message: "あなたが部屋に参加中であることを表示しますか?「表示する」を選ぶとアカウントのアバターがこのようになります。"
|
||||||
hint: "部屋を閉じた後、アバターは自動で元に戻ります。"
|
hint: "部屋から退出後、アバターは自動で元に戻ります。"
|
||||||
warning: "サーバーが変更を反映するまで時間がかかることがあります。"
|
warning: "サーバーが変更を反映するまで時間がかかることがあります。"
|
||||||
sure: "表示する"
|
sure: "表示する"
|
||||||
nope: "表示しない"
|
nope: "表示しない"
|
||||||
|
|
|
@ -48,7 +48,8 @@ export const useMastodonStore = defineStore("mastodon", {
|
||||||
},
|
},
|
||||||
async revertAvatar() {
|
async revertAvatar() {
|
||||||
const token = await axios.get("/api/token");
|
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) {
|
if (this.avatar) {
|
||||||
await this.updateAvatar(this.avatar, token.data.audon.avatar);
|
await this.updateAvatar(this.avatar, token.data.audon.avatar);
|
||||||
}
|
}
|
||||||
|
|
12
avatar.go
12
avatar.go
|
@ -22,7 +22,7 @@ import (
|
||||||
"gopkg.in/gographics/imagick.v2/imagick"
|
"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 {
|
if u == nil {
|
||||||
return nil, errors.New("nil user")
|
return nil, errors.New("nil user")
|
||||||
}
|
}
|
||||||
|
@ -73,17 +73,21 @@ func (u *AudonUser) GetIndicator(ctx context.Context, fnew []byte) ([]byte, erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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))
|
avatarPNG := image.NewRGBA(image.Rect(0, 0, 150, 150))
|
||||||
draw.BiLinear.Scale(avatarPNG, avatarPNG.Rect, avatar, avatar.Bounds(), draw.Src, nil)
|
draw.BiLinear.Scale(avatarPNG, avatarPNG.Rect, avatar, avatar.Bounds(), draw.Src, nil)
|
||||||
|
|
||||||
baseFrame := image.NewRGBA(avatarPNG.Bounds())
|
baseFrame := image.NewRGBA(avatarPNG.Bounds())
|
||||||
draw.Draw(baseFrame, baseFrame.Bounds(), image.Black, image.Point{}, draw.Src)
|
draw.Draw(baseFrame, baseFrame.Bounds(), image.Black, image.Point{}, draw.Src)
|
||||||
draw.Copy(baseFrame, image.Point{}, avatarPNG, avatarPNG.Bounds(), draw.Over, nil)
|
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)
|
anim := webpanimation.NewWebpAnimation(150, 150, 0)
|
||||||
defer anim.ReleaseMemory()
|
defer anim.ReleaseMemory()
|
||||||
|
|
37
config.go
37
config.go
|
@ -21,11 +21,12 @@ type (
|
||||||
}
|
}
|
||||||
|
|
||||||
AppConfigBase struct {
|
AppConfigBase struct {
|
||||||
LocalDomain string `validate:"required,hostname|hostname_port"`
|
LocalDomain string `validate:"required,hostname|hostname_port"`
|
||||||
Environment string `validate:"printascii"`
|
Environment string `validate:"printascii"`
|
||||||
StorageDir string
|
StorageDir string
|
||||||
LogoImageBack image.Image
|
LogoImageBlueBack image.Image
|
||||||
LogoImageFront image.Image
|
LogoImageWhiteBack image.Image
|
||||||
|
LogoImageFront image.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
LivekitConfig struct {
|
LivekitConfig struct {
|
||||||
|
@ -92,12 +93,21 @@ func loadConfig(envname string) (*AppConfig, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
publicDir, _ := filepath.Abs("public")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer logoBack.Close()
|
defer logoBlueBack.Close()
|
||||||
logoBackPng, err := png.Decode(logoBack)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -112,11 +122,12 @@ func loadConfig(envname string) (*AppConfig, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
basicConf := AppConfigBase{
|
basicConf := AppConfigBase{
|
||||||
LocalDomain: os.Getenv("LOCAL_DOMAIN"),
|
LocalDomain: os.Getenv("LOCAL_DOMAIN"),
|
||||||
Environment: envname,
|
Environment: envname,
|
||||||
StorageDir: storageDir,
|
StorageDir: storageDir,
|
||||||
LogoImageBack: logoBackPng,
|
LogoImageBlueBack: logoBlueBackPng,
|
||||||
LogoImageFront: logoFrontPng,
|
LogoImageWhiteBack: logoWhiteBackPng,
|
||||||
|
LogoImageFront: logoFrontPng,
|
||||||
}
|
}
|
||||||
if err := mainValidator.Struct(&basicConf); err != nil {
|
if err := mainValidator.Struct(&basicConf); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
Przed Szerokość: | Wysokość: | Rozmiar: 5.6 KiB Po Szerokość: | Wysokość: | Rozmiar: 5.6 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 5.6 KiB |
101
room.go
101
room.go
|
@ -326,66 +326,63 @@ func joinRoomHandler(c echo.Context) (err error) {
|
||||||
|
|
||||||
roomMetadata.MastodonAccounts[user.AudonID] = mastoAccount
|
roomMetadata.MastodonAccounts[user.AudonID] = mastoAccount
|
||||||
|
|
||||||
// Get ready to change avatar if user is host or cohost
|
// Get user's stored avatar if exists
|
||||||
if room.IsHost(user) || room.IsCoHost(user) {
|
if user.AvatarFile != "" {
|
||||||
// Get user's stored avatar if exists
|
orig, err := os.ReadFile(user.getAvatarImagePath(user.AvatarFile))
|
||||||
if user.AvatarFile != "" {
|
if err == nil && orig != nil {
|
||||||
orig, err := os.ReadFile(user.getAvatarImagePath(user.AvatarFile))
|
resp.Original = fmt.Sprintf("data:%s;base64,%s", mimetype.Detect(orig), base64.StdEncoding.EncodeToString(orig))
|
||||||
if err == nil && orig != nil {
|
} else if orig == nil {
|
||||||
resp.Original = fmt.Sprintf("data:%s;base64,%s", mimetype.Detect(orig), base64.StdEncoding.EncodeToString(orig))
|
user.AvatarFile = ""
|
||||||
} 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))
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
avatarLink := mastoAccount.Avatar
|
// icon, err := os.ReadFile(user.GetGIFAvatarPath())
|
||||||
if err := mainValidator.Var(&avatarLink, "required"); err != nil {
|
// if err == nil && icon != nil {
|
||||||
return wrapValidationError(err)
|
// resp.Indicator = fmt.Sprintf("data:image/gif;base64,%s", base64.StdEncoding.EncodeToString(icon))
|
||||||
}
|
// }
|
||||||
avatarURL, err := url.Parse(avatarLink)
|
}
|
||||||
|
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 {
|
if err != nil {
|
||||||
c.Logger().Error(err)
|
c.Logger().Error(err)
|
||||||
return ErrInvalidRequestFormat
|
return ErrInvalidRequestFormat
|
||||||
}
|
}
|
||||||
|
req.Header.Set("User-Agent", USER_AGENT)
|
||||||
|
|
||||||
// Retrieve user's current avatar if the old one doesn't exist in Audon.
|
avatarResp, err := http.DefaultClient.Do(req)
|
||||||
// Skips if user is still in another room.
|
if err != nil {
|
||||||
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 {
|
|
||||||
c.Logger().Error(err)
|
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
|
// Create room in LiveKit if it doesn't exist
|
||||||
|
|
|
@ -170,7 +170,7 @@ func main() {
|
||||||
|
|
||||||
api := e.Group("/api", authMiddleware)
|
api := e.Group("/api", authMiddleware)
|
||||||
api.GET("/token", getUserTokenHandler)
|
api.GET("/token", getUserTokenHandler)
|
||||||
// api.GET("/room", getStatusHandler)
|
api.GET("/room", getStatusHandler)
|
||||||
api.POST("/room", createRoomHandler)
|
api.POST("/room", createRoomHandler)
|
||||||
api.DELETE("/room", leaveRoomHandler)
|
api.DELETE("/room", leaveRoomHandler)
|
||||||
api.POST("/room/:id", joinRoomHandler)
|
api.POST("/room/:id", joinRoomHandler)
|
||||||
|
|
Ładowanie…
Reference in New Issue