Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.6.0 #59

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4b57378
Refactored backend
FlowingSPDG May 20, 2024
3ae0c3c
backup
FlowingSPDG May 20, 2024
eda7ad1
remove old PI, added react-based pi
FlowingSPDG May 20, 2024
d22dd84
Implement Preview Action
FlowingSPDG May 20, 2024
9ec6e0b
Tallyの実装
FlowingSPDG May 20, 2024
c0f2952
コメント追加
FlowingSPDG May 20, 2024
c6db3e4
クリーンナップ処理の修正
FlowingSPDG May 20, 2024
105863e
ACTS タリーの実装
FlowingSPDG May 21, 2024
414fa66
ACTSタリーの追加実装
FlowingSPDG May 21, 2024
27467da
Fix ACT tally
FlowingSPDG May 21, 2024
f84dbfa
disabled multiaction for Activator
FlowingSPDG May 21, 2024
65d4b4c
Fix PI inputs, Disabled "OK" alert
FlowingSPDG May 22, 2024
818b6e3
Added log directory, Fix destination store
FlowingSPDG May 22, 2024
27b5cc8
panic修正
FlowingSPDG May 22, 2024
832f3bc
panicの修正
FlowingSPDG May 22, 2024
1e9a56e
設定変更時のvMix接続処理を修正
FlowingSPDG May 22, 2024
53029d7
メモリリークの起因になりそうなか所の修正
FlowingSPDG May 22, 2024
00c605f
不要な型定義を削除
FlowingSPDG May 22, 2024
7145e79
fix front package
FlowingSPDG Jun 24, 2024
93146ca
vMixの再接続処理を修正
FlowingSPDG Jun 24, 2024
0a0d695
backup
FlowingSPDG Jun 24, 2024
287d858
fix errors
FlowingSPDG Sep 14, 2024
9c79352
Fix log writer?
FlowingSPDG Sep 14, 2024
26d5dd4
refactor: Cleanup backend codes. Remove some actions temporary
FlowingSPDG Oct 11, 2024
8d3307d
Replace action with Preview.
FlowingSPDG Oct 11, 2024
be5563c
Fix vMix connection with Logger
FlowingSPDG Oct 23, 2024
364c814
backup
Oct 23, 2024
cd8295c
発狂
Oct 23, 2024
d036b03
ブチギレビッグバンcommit
Oct 29, 2024
741631b
vMix connection pool now handles TCP connection successfully includin…
Oct 29, 2024
2be63bd
implement simple tally
Oct 29, 2024
6e45fbc
fix panic
Oct 29, 2024
d82db10
Fix tally ignores PI setting
Oct 29, 2024
309f1ac
XML/Input保持関連機能の追加
Oct 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified DistributionTool.exe
100644 → 100755
Empty file.
23 changes: 18 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,36 @@ endif
.DEFAULT_GOAL := build

test:
cd $(SRCDIR)/code && go run $(GOFLAGS) main.go handlers.go pi.go vmix.go -port 12345 -pluginUUID 213 -registerEvent test -info "{\"application\":{\"language\":\"en\",\"platform\":\"mac\",\"version\":\"4.1.0\"},\"plugin\":{\"version\":\"1.1\"},\"devicePixelRatio\":2,\"devices\":[{\"id\":\"55F16B35884A859CCE4FFA1FC8D3DE5B\",\"name\":\"Device Name\",\"size\":{\"columns\":5,\"rows\":3},\"type\":0},{\"id\":\"B8F04425B95855CF417199BCB97CD2BB\",\"name\":\"Another Device\",\"size\":{\"columns\":3,\"rows\":2},\"type\":1}]}"
cd $(SRCDIR)/code && go run $(GOFLAGS) cmd/main.go -port 12345 -pluginUUID 213 -registerEvent test -info "{\"application\":{\"language\":\"en\",\"platform\":\"mac\",\"version\":\"4.1.0\"},\"plugin\":{\"version\":\"1.1\"},\"devicePixelRatio\":2,\"devices\":[{\"id\":\"55F16B35884A859CCE4FFA1FC8D3DE5B\",\"name\":\"Device Name\",\"size\":{\"columns\":5,\"rows\":3},\"type\":0},{\"id\":\"B8F04425B95855CF417199BCB97CD2BB\",\"name\":\"Another Device\",\"size\":{\"columns\":3,\"rows\":2},\"type\":1}]}"

vet:
cd $(SRCDIR)/code && go vet

prepare:
setup-pi:
cd $(PIDIR) && npm install

setup-server:
cd $(SRCDIR)/code && go mod tidy

setup: setup-pi setup-server

prepare:
@$(MKDIR) $(BUILDDIR)
@$(RM) $(BUILDDIR)/*
@$(RM) ./$(RELEASEDIR)/*

build: prepare
build-pi:
cd $(SRCDIR)/pi && npm run build

build-server:
cd $(SRCDIR)/code/cmd && GOOS=windows GOARCH=amd64 go build -o $(BUILDDIR)/vmix_go.exe .
cd $(SRCDIR)/code/cmd && GOOS=darwin GOARCH=amd64 go build -o $(BUILDDIR)/vmix_go .
$(CP) $(PIDIR) $(BUILDDIR)/inspector

build: prepare build-pi build-server
$(CP) $(PIDIR)/dist $(BUILDDIR)/inspector
$(CP) $(SRCDIR)/manifest.json $(BUILDDIR)
$(CP) $(SRCDIR)/images $(BUILDDIR)

distribute: build
@$(RM) ./$(RELEASEDIR)/*
@$(MKDIR) $(RELEASEDIR)
$(DISTRIBUTION_TOOL) -b -i $(APPNAME) -o $(RELEASEDIR)
14 changes: 14 additions & 0 deletions Source/code/action/action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Package action provides the action interface and its implementations.
//
// Each Action interface does not belong to a specific "button".
// Instead, it is a usecase(logics) that can own any button.
// Action interface owns each StreamDeck context internally.

package action

import "context"

type Action interface {
Tally(ctx context.Context, host string, input int) error
Activator(ctx context.Context) error // TODO...
}
196 changes: 196 additions & 0 deletions Source/code/action/preview.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package action

import (
"context"
"errors"
"slices"

"github.com/FlowingSPDG/streamdeck-vmix-plugin/Source/code/adapter/adapters"
"github.com/FlowingSPDG/streamdeck-vmix-plugin/Source/code/logger/loggers"
"github.com/FlowingSPDG/streamdeck-vmix-plugin/Source/code/setting"
"github.com/FlowingSPDG/streamdeck-vmix-plugin/Source/code/solver"
vmixtcp "github.com/FlowingSPDG/vmix-go/tcp"

"github.com/FlowingSPDG/streamdeck"
sdcontext "github.com/FlowingSPDG/streamdeck/context"
"golang.org/x/sync/errgroup"
"golang.org/x/xerrors"
)

const PreviewActionUUID = "dev.flowingspdg.vmix.preview"

type PreviewAction interface {
Appear(ctx context.Context, setting *setting.PreviewSetting) error
Disappear(ctx context.Context, setting *setting.PreviewSetting) error
UpdateSetting(ctx context.Context, setting *setting.PreviewSetting) error
Execute(ctx context.Context) error
Tally(ctx context.Context, host string, tally *vmixtcp.TallyResponse) error
}

type previewAction struct {
logger loggers.Logger

// adapters
streamDeckAdapter adapters.StreamDeckContextAdapter
vmixAdapter adapters.VMixAdapter

// solver
solver solver.Solver

// internal
store setting.SettingStore[setting.PreviewSetting]
}

func NewPreviewAction(
logger loggers.Logger,
streamDeckAdapter adapters.StreamDeckContextAdapter,
vmixAdapter adapters.VMixAdapter,
solver solver.Solver,
store setting.SettingStore[setting.PreviewSetting],
) PreviewAction {
return &previewAction{
logger: logger,
streamDeckAdapter: streamDeckAdapter,
vmixAdapter: vmixAdapter,
solver: solver,
store: store,
}
}

func (p *previewAction) Appear(ctx context.Context, setting *setting.PreviewSetting) error {
if err := p.logger.LogMessage(ctx, "preview action appeared"); err != nil {
return xerrors.Errorf("failed to log message: %w", err)
}

p.storeNewVmix(ctx, setting)

return nil
}

func (p *previewAction) Disappear(ctx context.Context, setting *setting.PreviewSetting) error {
if err := p.logger.LogMessage(ctx, "preview action disappeared"); err != nil {
return xerrors.Errorf("failed to log message: %w", err)
}

ctxStr := sdcontext.Context(ctx)
if ctxStr == "" {
return errors.New("failed to get context")
}

p.store.Delete(ctxStr)
p.vmixAdapter.RemoveVMix(ctx)

return nil
}

func (p *previewAction) UpdateSetting(ctx context.Context, setting *setting.PreviewSetting) error {
if err := p.logger.LogMessage(ctx, "preview action received updated setting: %v", setting); err != nil {
return xerrors.Errorf("failed to log message: %w", err)
}

// 既存の設定と新しい設定を比較して、設定が変更されていれば更新する
ctxStr := sdcontext.Context(ctx)
if ctxStr == "" {
return errors.New("failed to get context")
}
oldSetting, _ := p.store.Load(ctxStr)
if oldSetting.Host == setting.Host && oldSetting.Input == setting.Input {
return nil
}

// ここで古いvMixのインスタンスを削除する
p.vmixAdapter.RemoveVMix(ctx)
p.storeNewVmix(ctx, setting)

return nil
}

func (p *previewAction) Execute(ctx context.Context) error {
if err := p.logger.LogMessage(ctx, "preview action executing"); err != nil {
return xerrors.Errorf("failed to log message: %w", err)
}

ctxStr := sdcontext.Context(ctx)
if ctxStr == "" {
return errors.New("failed to get context")
}

s, ok := p.store.Load(ctxStr)
if !ok {
return errors.New("failed to get settings for context " + ctxStr)
}

if err := p.vmixAdapter.PreviewInput(s.Host, s.Input); err != nil {
return err
}

return nil
}

func (p *previewAction) Tally(ctx context.Context, host string, tally *vmixtcp.TallyResponse) error {
if err := p.logger.LogMessage(ctx, "preview action received tally signal"); err != nil {
return xerrors.Errorf("failed to log message: %w", err)
}

contextStrs, ok := p.solver.SolveByHost(host)
if !ok {
return xerrors.Errorf("unknown host detected: %s", host)
}

contextStrs = slices.DeleteFunc(contextStrs, func(s string) bool {
setting, ok := p.store.Load(s)
if !ok {
return false
}
return !setting.Tally || setting.Host != host || setting.Input == 0 || setting.Input > len(tally.Tally)
})

eg := errgroup.Group{}
for _, contextStr := range contextStrs {
eg.Go(func() error {
if err := p.logger.LogMessage(ctx, "Applying tally for context %s", contextStr); err != nil {
return xerrors.Errorf("failed to log message: %w", err)
}

cctx := sdcontext.WithContext(ctx, contextStr)

// PIの設定を読み出す
s, ok := p.store.Load(contextStr)
if !ok {
return xerrors.Errorf("failed to get settings for context %s", contextStr)
}

// 設定情報をもとに、Tallyをセットする
target := s.Input - 1
if tally.Tally[target] == vmixtcp.Preview {
if err := p.streamDeckAdapter.SetPreviewColor(cctx, streamdeck.HardwareAndSoftware); err != nil {
return xerrors.Errorf("failed to set tally: %w", err)
}
return nil
}

if err := p.logger.LogMessage(ctx, "Applying Preview tally for context %s", contextStr); err != nil {
return xerrors.Errorf("failed to log message: %w", err)
}
if err := p.streamDeckAdapter.SetInactiveColor(cctx, streamdeck.HardwareAndSoftware); err != nil {
return xerrors.Errorf("failed to set tally: %w", err)
}
return nil
})
}
if err := eg.Wait(); err != nil {
return xerrors.Errorf("failed to apply tally: %w", err)
}
return nil
}

func (p *previewAction) storeNewVmix(ctx context.Context, setting *setting.PreviewSetting) error {
ctxStr := sdcontext.Context(ctx)
if ctxStr == "" {
return errors.New("failed to get context")
}

p.store.Store(ctxStr, setting)
p.vmixAdapter.AddVMix(ctx, setting.Host)
return nil
}
32 changes: 32 additions & 0 deletions Source/code/adapter/adapters/adapters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package adapters

import (
"context"

"github.com/FlowingSPDG/streamdeck"
vmixtcp "github.com/FlowingSPDG/vmix-go/tcp"
)

type StreamDeckContextAdapter interface {
// TALLY
SetInactiveColor(ctx context.Context, target streamdeck.Target) error
SetPreviewColor(ctx context.Context, target streamdeck.Target) error
SetProgramColor(ctx context.Context, target streamdeck.Target) error

SendInputs(ctx context.Context, inputs map[string]Input) error
}

type Input struct {
Number int `json:"number"`
Name string `json:"name"`
Key string `json:"key"`
}

type VMixAdapter interface {
AddVMix(ctx context.Context, destination string)
RemoveVMix(ctx context.Context)
PreviewInput(destination string, input int) error
OnTally(f func(ctx context.Context, host string, tally *vmixtcp.TallyResponse) error)
// OnVersion(f func(ctx context.Context, host string, version *vmixtcp.VersionResponse) error)
OnXML(f func(ctx context.Context, host string, xml *vmixtcp.XMLResponse) error)
}
Loading