Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 24 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Keep the build context to what `go build` needs. Every Dockerfile does
# `COPY . .`, so anything not listed here ends up in the build stage.
.git
.github
.claude
.idea
.vscode
.local
.DS_Store
.env
.env.*
env.example
*.md
*.Dockerfile
.dockerignore
Makefile
VERSION
coverage.out
coverage.html
*.db
__debug_bin*
build
**/testdata
**/*_test.go
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@ jobs:
- name: Run vet, tests and workflowcheck
run: make test

tidy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- uses: actions/setup-go@v6
with:
go-version-file: go.mod

- name: go.mod and go.sum are tidy
run: go mod tidy -diff

govulncheck:
runs-on: ubuntu-latest
steps:
- uses: golang/govulncheck-action@v1
with:
go-version-file: go.mod
go-package: ./...

lint:
runs-on: ubuntu-latest
steps:
Expand Down
6 changes: 3 additions & 3 deletions activities/directus.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type CreateMediaItemTagInput struct {

type CreateMediaItemInput struct {
Label string
Type string
Type directus.MediaItemType
AssetID string
Title string
ParentEpisodeID string
Expand All @@ -37,12 +37,12 @@ type CreateMediaItemInput struct {

type CreateShortInput struct {
MediaItemID string
Status string
Status directus.ShortStatus
}

type CreateStyledImageInput struct {
ImageID string
Style string
Style directus.ImageStyle
}

type GetOrCreateTagInput struct {
Expand Down
27 changes: 17 additions & 10 deletions activities/vidispine/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,20 @@ type WaitForJobCompletionParams struct {

type MBJobStatusResult struct {
JobID string
Status string
Status vsapi.JobStatus
}

// Application error types raised by these activities. Workflows match on
// them to decide whether an error is worth retrying or reporting.
const (
// JobFailedErrorType marks a Vidispine job that ended in a state other
// than FINISHED; retrying the wait cannot help.
JobFailedErrorType = "JOB_FAILED"
// ShapeTagNotFoundErrorType marks an import whose shape-tag Vidispine has
// not configured.
ShapeTagNotFoundErrorType = "VS_SHAPE_TAG_NOT_FOUND"
)

func (a Activities) WaitForJobCompletion(ctx context.Context, params WaitForJobCompletionParams) (*MBJobStatusResult, error) {
logger := activity.GetLogger(ctx)
logger.Info("Starting WaitForJobCompletionActivity")
Expand All @@ -43,11 +54,7 @@ func (a Activities) WaitForJobCompletion(ctx context.Context, params WaitForJobC
if err != nil {
return nil, err
}
if job.Status == "FINISHED" {
return &MBJobStatusResult{params.JobID, job.Status}, nil
}

if job.Status != "STARTED" && job.Status != "READY" && job.Status != "WAITING" {
if job.Status == vsapi.JobStatusFinished || !job.Status.InProgress() {
return &MBJobStatusResult{params.JobID, job.Status}, nil
}

Expand All @@ -67,13 +74,13 @@ func (a Activities) JobCompleteOrErr(ctx context.Context, params WaitForJobCompl
for {
job, err := a.Client.GetJob(params.JobID)
if err != nil {
return false, temporal.NewNonRetryableApplicationError("couldn't complete job", "JOB_FAILED", err)
return false, temporal.NewNonRetryableApplicationError("couldn't complete job", JobFailedErrorType, err)
}
if job.Status == "FINISHED" {
if job.Status == vsapi.JobStatusFinished {
return true, nil
}
if job.Status != "STARTED" && job.Status != "READY" && job.Status != "WAITING" {
return false, temporal.NewNonRetryableApplicationError("couldn't complete job", "JOB_FAILED", fmt.Errorf("job failed with status: %s", job.Status), job)
if !job.Status.InProgress() {
return false, temporal.NewNonRetryableApplicationError("couldn't complete job", JobFailedErrorType, fmt.Errorf("job failed with status: %s", job.Status), job)
}

activity.RecordHeartbeat(ctx, job)
Expand Down
6 changes: 3 additions & 3 deletions activities/vidispine/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
type ImportFileAsShapeParams struct {
AssetID string
FilePath paths.Path
ShapeTag string
ShapeTag vsapi.ShapeTag
Growing bool
Replace bool
}
Expand Down Expand Up @@ -53,9 +53,9 @@ func (a Activities) ImportFileAsShapeActivity(ctx context.Context, params Import
}
}

res, err := a.Client.AddShapeToItem(params.ShapeTag, params.AssetID, fileID)
res, err := a.Client.AddShapeToItem(params.ShapeTag.Value, params.AssetID, fileID)
if err != nil && errors.Is(err, vsapi.ErrShapeTagNotFound) {
err = temporal.NewNonRetryableApplicationError(err.Error(), "VS_SHAPE_TAG_NOT_FOUND", err)
err = temporal.NewNonRetryableApplicationError(err.Error(), ShapeTagNotFoundErrorType, err)
}
return &ImportFileResult{
JobID: res,
Expand Down
4 changes: 2 additions & 2 deletions activities/vidispine/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ type VXOnlyParam struct {

type GetFileFromVXParams struct {
VXID string
Tags []string
Tags []vsapi.ShapeTag
}

type GetFileFromVXResult struct {
FilePath paths.Path
ShapeTag string
ShapeTag vsapi.ShapeTag
}

func (a Activities) GetFileFromVXActivity(ctx context.Context, params GetFileFromVXParams) (*GetFileFromVXResult, error) {
Expand Down
8 changes: 4 additions & 4 deletions cmd/fakerclone/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package main
import (
"github.com/bcc-code/bcc-media-flows/internal/bootstrap"
"github.com/bcc-code/bcc-media-flows/services/rclone"
"github.com/davecgh/go-spew/spew"
"github.com/gin-gonic/gin"
"log"
"net/http"
"time"
)
Expand All @@ -13,7 +13,7 @@ func jobStatusHandler(c *gin.Context) {
req := &rclone.JobStatusRequest{}
err := c.BindJSON(req)
if err != nil {
spew.Dump(err)
log.Println(err)
c.JSON(400, gin.H{"error": err.Error()})
return
}
Expand Down Expand Up @@ -57,7 +57,7 @@ func operationsListHandler(c *gin.Context) {
req := &rclone.ListRequest{}
err := c.BindJSON(req)
if err != nil {
spew.Dump(err)
log.Println(err)
c.JSON(400, gin.H{"error": err.Error()})
return
}
Expand All @@ -70,7 +70,7 @@ func operationsStatHandler(c *gin.Context) {
req := &rclone.ListRequest{}
err := c.BindJSON(req)
if err != nil {
spew.Dump(err)
log.Println(err)
c.JSON(400, gin.H{"error": err.Error()})
return
}
Expand Down
8 changes: 6 additions & 2 deletions cmd/httpin/watchers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"
"time"

"github.com/bcc-code/bcc-media-flows/common"
"github.com/bcc-code/bcc-media-flows/environment"
"github.com/bcc-code/bcc-media-flows/paths"
wfutils "github.com/bcc-code/bcc-media-flows/utils/workflows"
Expand Down Expand Up @@ -139,13 +140,16 @@ func doTranscode(ctx context.Context, path string) error {
}

matches := exp.FindStringSubmatch(path)
t := matches[1]
folder := common.WatchFolders.Parse(matches[1])
if folder == nil {
return fmt.Errorf("%w %q for %s", common.ErrUnknownWatchFolder, matches[1], path)
}

workflowOptions := wfutils.NewWorkflowOptions(environment.GetWorkerQueue(), "", "watcher")

_, err = c.ExecuteWorkflow(ctx, workflowOptions, miscworkflows.WatchFolderTranscode, miscworkflows.WatchFolderTranscodeInput{
Path: path,
FolderName: t,
FolderName: *folder,
})
return err
}
Expand Down
7 changes: 2 additions & 5 deletions cmd/trigger_ui/isilon_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ import (
wfutils "github.com/bcc-code/bcc-media-flows/utils/workflows"
"github.com/bcc-code/bcc-media-flows/workflows/export"
bccmUtils "github.com/bcc-code/bcc-media-platform/backend/utils"
"github.com/davecgh/go-spew/spew"
"github.com/gin-gonic/gin"
"github.com/teris-io/shortid"
"github.com/google/uuid"
)

func (s *TriggerServer) isilonExportGET(ctx *gin.Context) {
Expand Down Expand Up @@ -80,8 +79,6 @@ func (s *TriggerServer) isilonExportPOST(ctx *gin.Context) {

selectedResolution := vsResolutions[resolutionIndex]

spew.Dump(ctx.PostForm("exportFormat"))

params := export.IsilonExportParams{
VXID: vxID,
WatermarkPath: ctx.PostForm("watermarkPath"),
Expand All @@ -92,7 +89,7 @@ func (s *TriggerServer) isilonExportPOST(ctx *gin.Context) {
}

var wfID string
workflowOptions.ID = params.VXID + "-" + shortid.MustGenerate()
workflowOptions.ID = params.VXID + "-" + uuid.NewString()
res, err := s.wfClient.ExecuteWorkflow(ctx, workflowOptions, export.IsilonExport, params)
if err != nil {
renderErrorPage(ctx, http.StatusInternalServerError, err)
Expand Down
13 changes: 12 additions & 1 deletion cmd/trigger_ui/vb.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"fmt"
"github.com/bcc-code/bcc-media-flows/environment"
"log"
"net/http"
Expand Down Expand Up @@ -65,9 +66,19 @@ func (s *TriggerServer) vbExportPOST(ctx *gin.Context) {

workflowOptions := wfutils.NewWorkflowOptions(environment.GetQueue(), vxID, getTriggeredBy(ctx))

var destinations []vb_export.Destination
for _, name := range ctx.PostFormArray("destinations[]") {
dest := vb_export.Destinations.Parse(name)
if dest == nil {
renderErrorPage(ctx, http.StatusBadRequest, fmt.Errorf("%w: %q", vb_export.ErrUnknownDestination, name))
return
}
destinations = append(destinations, *dest)
}

params := vb_export.VBExportParams{
VXID: vxID,
Destinations: ctx.PostFormArray("destinations[]"),
Destinations: destinations,
SubtitleShapeTag: ctx.PostForm("subtitleShape"),
SubtitleStyle: ctx.PostForm("subtitleStyle"),
}
Expand Down
58 changes: 49 additions & 9 deletions common/codecs.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,52 @@
package common

const (
FolderProRes422HQHD = "ProRes422HQ_HD"
FolderProRes422HQNative = "ProRes422HQ_Native"
FolderProRes422HQNative25FPS = "ProRes422HQ_Native_25FPS"
FolderProRes4444K25FPS = "ProRes444_4K-25FPS"
FolderAVCIntra100HD = "AVCintra100_HD"
FolderXDCAMHD422 = "XDCAMHD422"
FolderTranscribe = "Transcribe"
FolderHAP50FPS = "HAP_50FPS"
import (
"errors"

"github.com/bcc-code/bcc-media-flows/internal/enumjson"
"github.com/orsinium-labs/enum"
)

// WatchFolder names a subfolder of the transcode root that the file watcher
// monitors. A file dropped in `<root>/<WatchFolder>/in/` is transcoded (or
// transcribed) according to the folder it landed in.
type WatchFolder enum.Member[string]

var (
FolderProRes422HQHD = WatchFolder{Value: "ProRes422HQ_HD"}
FolderProRes422HQNative = WatchFolder{Value: "ProRes422HQ_Native"}
FolderProRes422HQNative25FPS = WatchFolder{Value: "ProRes422HQ_Native_25FPS"}
FolderProRes4444K25FPS = WatchFolder{Value: "ProRes444_4K-25FPS"}
FolderAVCIntra100HD = WatchFolder{Value: "AVCintra100_HD"}
FolderXDCAMHD422 = WatchFolder{Value: "XDCAMHD422"}
FolderTranscribe = WatchFolder{Value: "Transcribe"}
FolderHAP50FPS = WatchFolder{Value: "HAP_50FPS"}
WatchFolders = enum.New(
FolderProRes422HQHD,
FolderProRes422HQNative,
FolderProRes422HQNative25FPS,
FolderProRes4444K25FPS,
FolderAVCIntra100HD,
FolderXDCAMHD422,
FolderTranscribe,
FolderHAP50FPS,
)
ErrUnknownWatchFolder = errors.New("unknown watch folder")
)

func (f WatchFolder) String() string {
return f.Value
}

// MarshalJSON writes the bare folder name, which is what workflow histories
// recorded while FolderName was a plain string contain.
//
//goland:noinspection GoMixedReceiverTypes
func (f WatchFolder) MarshalJSON() ([]byte, error) {
return enumjson.Marshal(f)
}

//goland:noinspection GoMixedReceiverTypes
func (f *WatchFolder) UnmarshalJSON(data []byte) error {
return enumjson.UnmarshalStrict(data, WatchFolders, f, ErrUnknownWatchFolder)
}
4 changes: 1 addition & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ require (
github.com/bcc-code/bcc-media-platform v0.0.0-20250903091027-11ead5481489
github.com/cloudevents/sdk-go/v2 v2.15.2
github.com/creativeprojects/go-selfupdate v1.1.3
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/deckarep/golang-set/v2 v2.3.1
github.com/gin-contrib/cors v1.7.2
github.com/gin-gonic/gin v1.10.0
github.com/glebarez/go-sqlite v1.22.0
Expand All @@ -22,7 +20,6 @@ require (
github.com/sendgrid/sendgrid-go v3.14.0+incompatible
github.com/stretchr/testify v1.11.1
github.com/teamwork/reload v1.4.2
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569
go.temporal.io/api v1.62.14
go.temporal.io/sdk v1.45.0
go.uber.org/mock v0.6.0
Expand All @@ -39,6 +36,7 @@ require (
github.com/MicahParks/keyfunc v1.9.0 // indirect
github.com/ansel1/merry/v2 v2.2.1 // indirect
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/envoyproxy/go-control-plane/envoy v1.37.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect
github.com/fatih/color v1.18.0 // indirect
Expand Down
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
github.com/deckarep/golang-set/v2 v2.3.1 h1:vjmkvJt/IV27WXPyYQpAh4bRyWJc5Y435D17XQ9QU5A=
github.com/deckarep/golang-set/v2 v2.3.1/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
Expand Down Expand Up @@ -662,8 +660,6 @@ github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/teamwork/reload v1.4.2 h1:e3U0xXFmhzOSgWNBuyOMOvKS2Q34YNo5bp9Z1uOujYE=
github.com/teamwork/reload v1.4.2/go.mod h1:tGCBzttv2CSfSjBTRlIdnQ4kopxrCXPGCTXeOO61SWg=
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 h1:xzABM9let0HLLqFypcxvLmlvEciCHL7+Lv+4vwZqecI=
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569/go.mod h1:2Ly+NIftZN4de9zRmENdYbvPQeaVIYKWpLFStLFEBgI=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
Expand Down
Loading
Loading