Skip to content

Add plt build command to download and cut playlist media#887

Merged
statik merged 10 commits into
mainfrom
plt-phase-2
Jun 12, 2026
Merged

Add plt build command to download and cut playlist media#887
statik merged 10 commits into
mainfrom
plt-phase-2

Conversation

@statik

@statik statik commented Jun 11, 2026

Copy link
Copy Markdown
Member

Summary

Second phase of the plt command group. Adds vbs plt build <playlist>,
which turns a purple playlist into a self-contained, play-ready working
directory.

Stacked on #886 (Phase 1). Review/merge that first; this targets
plt-phase-1 and will retarget main once #886 merges.

The pipeline:

  • Resolve each catalog location to a media-API query (pub/track, book/chapter,
    docid shapes) and pick a rendition (default 720p, --resolution; falls
    back to the highest available with a warning).
  • Download to a shared cache (UserCacheDir/vbs/media/) with MD5 + size
    verification and a JSON sidecar; one re-download on mismatch, then a hard
    error. Distinct locations are fetched once.
  • Cut segment clips by merging markers into contiguous ranges (0.5 s gap),
    snapping the start back to the nearest keyframe, and stream-copying (no
    re-encode). Non-contiguous markers become lettered sub-clips. Untrimmed,
    marker-free videos are copied whole; image cues are extracted from the zip.
  • Describe with playlist.json (the Phase 3 contract: per-cue markers,
    cut metadata, lead-in, raw end action) and a Typst cuesheet.typ, compiled
    to cuesheet.pdf when typst is on PATH.

The media endpoint is config-only (plt.mediaapi, overridable with
--media-api) and the build fails fast with an actionable message when unset.
ffmpeg/ffprobe are required and checked up front. New code is standard
library only (no new vendored dependencies).

Test Plan

  • go test ./cmd/ green: URL builder (3 shapes + unsupported), httptest
    client + rendition fallback, cache reuse + checksum/size mismatch,
    marker merge (mutation-verified), keyframe probe + ffmpeg cut, image
    extraction, cue-sheet render + playlist.json round-trip
  • Hermetic end-to-end build test (fake media server + generated video):
    download→verify→cache, whole-video copy, lettered segment sub-clips, image
    extract, playlist.json + cuesheet.typ, cache-hit re-run
  • bazel build //cmd:go_default_library and bazel test //cmd:go_default_test green
  • gofmt, go vet, go build ./..., go mod verify, vendor guard clean
  • funlen / gocyclo / lll within limits
  • Real build of the example export: 15 cues, media deduped to 10
    files, every segment clip snaps to a keyframe within one GOP (lead-ins
    0.07–1.75 s), checksum confirmed MD5, re-run completes in ~1.7 s (cache)

@statik statik added the feature label Jun 11, 2026

@statik statik left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit

golangci

🚫 [golangci] reported by reviewdog 🐶
string sjj has 6 occurrences, make it a constant (goconst)

resp, err := fetchMedia(srv.Client(), srv.URL, "ASL", &Location{KeySymbol: "sjj", Track: 135})


🚫 [golangci] reported by reviewdog 🐶
string 720p has 7 occurrences, make it a constant (goconst)

if item.Label != "720p" || item.FrameHeight != 720 {


🚫 [golangci] reported by reviewdog 🐶
string meeting Dec 2nd has 3 occurrences, make it a constant (goconst)

Name: "meeting Dec 2nd",


🚫 [golangci] reported by reviewdog 🐶
string meeting-dec-2nd has 3 occurrences, make it a constant (goconst)

Slug: "meeting-dec-2nd",


🚫 [golangci] reported by reviewdog 🐶
string ASL has 7 occurrences, make it a constant (goconst)

Language: langInfo{ID: 420, Code: "ASL"},


🚫 [golangci] reported by reviewdog 🐶
string grapes.jpg has 3 occurrences, make it a constant (goconst)

Index: 3, Label: "grapes.jpg", Kind: "image",


🚫 [golangci] reported by reviewdog 🐶
string nwt has 4 occurrences, make it a constant (goconst)

case loc.KeySymbol == "nwt" && loc.BookNumber > 0:


🚫 [golangci] reported by reviewdog 🐶
string sjj has 6 occurrences, make it a constant (goconst)

loc: Location{KeySymbol: "sjj", Track: 135, Type: 0},


🚫 [golangci] reported by reviewdog 🐶
string booknum has 3 occurrences, make it a constant (goconst)

forbidden: []string{"booknum", "docid"},


🚫 [golangci] reported by reviewdog 🐶
string nwt has 4 occurrences, make it a constant (goconst)

loc: Location{KeySymbol: "nwt", BookNumber: 23, ChapterNumber: 5, Type: 0},


🚫 [golangci] reported by reviewdog 🐶
exitAfterDefer: log.Fatal will exit, and defer func(){...}(...) will not run (gocritic)

log.Fatal().Err(err).Msg("Could not parse playlist")


🚫 [golangci] reported by reviewdog 🐶
unnamedResult: consider giving a name to these results (gocritic)

func buildMediaFixtureServer(t *testing.T, video []byte) (*httptest.Server, *int32) {


🚫 [golangci] reported by reviewdog 🐶
rangeValCopy: each iteration copies 136 bytes (consider pointers or indexing) (gocritic)

for _, c := range manifest.Cues {


🚫 [golangci] reported by reviewdog 🐶
unnamedResult: consider giving a name to these results (gocritic)

func mediaFileServer(t *testing.T, body []byte) (*httptest.Server, *int32) {


🚫 [golangci] reported by reviewdog 🐶
rangeValCopy: each iteration copies 136 bytes (consider pointers or indexing) (gocritic)

for _, c := range manifest.Cues {


🚫 [golangci] reported by reviewdog 🐶
rangeValCopy: each iteration copies 136 bytes (consider pointers or indexing) (gocritic)

for _, c := range manifest.Cues {


🚫 [golangci] reported by reviewdog 🐶
importShadow: shadow of imported package 'url' (gocritic)

func downloadAndVerify(client *http.Client, url, dest string, wantSize int64, wantChecksum string) error {


🚫 [golangci] reported by reviewdog 🐶
G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)

cmd := exec.Command("ffmpeg", "-loglevel", "error",


🚫 [golangci] reported by reviewdog 🐶
G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)

cmd := exec.Command("ffmpeg", "-loglevel", "error", "-f", "lavfi",


🚫 [golangci] reported by reviewdog 🐶
G110: Potential DoS vulnerability via decompression bomb (gosec)

if _, err := io.Copy(out, rc); err != nil {


🚫 [golangci] reported by reviewdog 🐶
Magic number: 0o755, in detected (mnd)

if err := os.MkdirAll(filepath.Join(outDir, sub), 0o755); err != nil {


🚫 [golangci] reported by reviewdog 🐶
Magic number: 5, in detected (mnd)

from := startSec - 5


🚫 [golangci] reported by reviewdog 🐶
Magic number: 0.1, in detected (mnd)

interval := fmt.Sprintf("%.3f%%%.3f", from, startSec+0.1)


🚫 [golangci] reported by reviewdog 🐶
Magic number: 2, in detected (mnd)

if len(fields) < 2 {


🚫 [golangci] reported by reviewdog 🐶
Magic number: 0o600, in detected (mnd)

if err := os.WriteFile(path, append(data, '\n'), 0o600); err != nil {


🚫 [golangci] reported by reviewdog 🐶
Magic number: 60, in detected (mnd)

minutes := int(seconds) / 60


🚫 [golangci] reported by reviewdog 🐶
Magic number: 60, in detected (mnd)

rem := seconds - float64(minutes*60)


🚫 [golangci] reported by reviewdog 🐶
Magic number: 0o600, in detected (mnd)

if err := os.WriteFile(typPath, []byte(renderCueSheet(manifest)), 0o600); err != nil {


🚫 [golangci] reported by reviewdog 🐶
Magic number: 0o755, in detected (mnd)

if err := os.MkdirAll(cacheDir, 0o755); err != nil {


🚫 [golangci] reported by reviewdog 🐶
Magic number: 0o600, in detected (mnd)

if err := os.WriteFile(dest+".json", data, 0o600); err != nil {


🚫 [golangci] reported by reviewdog 🐶
continue with no blank line before (nlreturn)

continue


🚫 [golangci] reported by reviewdog 🐶
Function TestDownloadAndVerify missing the call to method parallel (paralleltest)

func TestDownloadAndVerify(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestDownloadAndVerify missing the call to method parallel in the test run (paralleltest)

t.Run("good size and checksum", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestDownloadAndVerify missing the call to method parallel in the test run (paralleltest)

t.Run("checksum mismatch is an error", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestDownloadAndVerify missing the call to method parallel in the test run (paralleltest)

t.Run("size mismatch is an error", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestFetchToCache_ReusesCache missing the call to method parallel (paralleltest)

func TestFetchToCache_ReusesCache(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestFetchMedia_ParsesRenditions missing the call to method parallel (paralleltest)

func TestFetchMedia_ParsesRenditions(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel (paralleltest)

func TestSelectRendition(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel in the test run (paralleltest)

t.Run("exact 720p", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel in the test run (paralleltest)

t.Run("absent resolution falls back to highest", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel in the test run (paralleltest)

t.Run("missing language is an error", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestProbeKeyframeBefore_Integration missing the call to method parallel (paralleltest)

func TestProbeKeyframeBefore_Integration(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestCutVerseClip_Integration missing the call to method parallel (paralleltest)

func TestCutVerseClip_Integration(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestArchiveExtractEntry missing the call to method parallel (paralleltest)

func TestArchiveExtractEntry(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestMergeMarkers missing the call to method parallel (paralleltest)

func TestMergeMarkers(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Range statement for test TestMergeMarkers missing the call to method parallel in test Run (paralleltest)

for _, tc := range cases {


🚫 [golangci] reported by reviewdog 🐶
Function TestFormatTimecode missing the call to method parallel (paralleltest)

func TestFormatTimecode(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestWritePlaylistJSON_RoundTrips missing the call to method parallel (paralleltest)

func TestWritePlaylistJSON_RoundTrips(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestRenderCueSheet missing the call to method parallel (paralleltest)

func TestRenderCueSheet(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestBuildMediaURL missing the call to method parallel (paralleltest)

func TestBuildMediaURL(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Range statement for test TestBuildMediaURL missing the call to method parallel in test Run (paralleltest)

for _, tc := range cases {


🚫 [golangci] reported by reviewdog 🐶
Function TestBuildMediaURL_UnsupportedShape missing the call to method parallel (paralleltest)

func TestBuildMediaURL_UnsupportedShape(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
test helper function should start from t.Helper() (thelper)

check: func(t *testing.T, ranges []clipRange) {


🚫 [golangci] reported by reviewdog 🐶
test helper function should start from t.Helper() (thelper)

check: func(t *testing.T, ranges []clipRange) {


🚫 [golangci] reported by reviewdog 🐶
test helper function should start from t.Helper() (thelper)

check: func(t *testing.T, ranges []clipRange) {


🚫 [golangci] reported by reviewdog 🐶
variable name 'rm' is too short for the scope of its usage (varnamelen)

rm, err := ctx.resolveMedia(item.Location)


🚫 [golangci] reported by reviewdog 🐶
parameter name 'rm' is too short for the scope of its usage (varnamelen)

item Item, index int, slug string, rm resolvedMedia, sourceRel, thumb string,


🚫 [golangci] reported by reviewdog 🐶
variable name 'r' is too short for the scope of its usage (varnamelen)

for i, r := range ranges {


🚫 [golangci] reported by reviewdog 🐶
parameter name 'rm' is too short for the scope of its usage (varnamelen)

func (ctx *buildContext) ensureMediaCopy(rm resolvedMedia) (string, error) {


🚫 [golangci] reported by reviewdog 🐶
parameter name 'w' is too short for the scope of its usage (varnamelen)

mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {


🚫 [golangci] reported by reviewdog 🐶
variable name 'in' is too short for the scope of its usage (varnamelen)

in, err := os.Open(src)


🚫 [golangci] reported by reviewdog 🐶
variable name 'b' is too short for the scope of its usage (varnamelen)

var b strings.Builder


🚫 [golangci] reported by reviewdog 🐶
variable name 'q' is too short for the scope of its usage (varnamelen)

q := parsed.Query()


🚫 [golangci] reported by reviewdog 🐶
variable name 'zr' is too short for the scope of its usage (varnamelen)

zr, err := zip.OpenReader(a.path)


🚫 [golangci] reported by reviewdog 🐶
variable name 'rc' is too short for the scope of its usage (varnamelen)

rc, err := entry.Open()


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = arc.Close() }()


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

for i, item := range playlist.Items {


🚫 [golangci] reported by reviewdog 🐶
append only allowed to cuddle with appended value (wsl)

cues = append(cues, itemCues...)


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with declarations or returns (wsl)

pltBuildCmd.Flags().StringVar(&mediaAPI, "media-api", "", "media API base URL (overrides config key plt.mediaapi)")


🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

t.Cleanup(func() { pltBuildOut = "."; pltBuildResolution = "720p"; pltBuildLang = "" })


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with blocks (wsl)

t.Cleanup(func() { _ = arc.Close() })


🚫 [golangci] reported by reviewdog 🐶
append only allowed to cuddle with appended value (wsl)

cur.markers = append(cur.markers, m)


🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = in.Close() }()


🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

for _, tool := range []string{"ffmpeg", "ffprobe"} {


🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

makeTestVideo(t, src, 10)


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with blocks (wsl)

fmt.Fprintf(&b, " [%d], [#%s], [%s \\ #raw(%q)], [%s], [%s], [%d], [%s],\n",


🚫 [golangci] reported by reviewdog 🐶
declarations should never be cuddled (wsl)

var side mediaSidecar


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

for k, want := range tc.wantParams {

Comment thread cmd/plt_media.go
defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != http.StatusOK {
return out, fmt.Errorf("media API returned status %d for %+v", resp.StatusCode, *loc)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf("media API returned status %d for %+v", resp.StatusCode, *loc)" (err113)

Comment thread cmd/plt_media.go
func selectRendition(resp mediaResponse, langCode, resolution string) (mediaItem, bool, error) {
lang, ok := resp.Files[langCode]
if !ok || len(lang.MP4) == 0 {
return mediaItem{}, false, fmt.Errorf("no MP4 renditions for language %q", langCode)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf("no MP4 renditions for language %q", langCode)" (err113)

Comment thread cmd/plt_media.go
defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("download for %s returned status %d", url, resp.StatusCode)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf("download for %s returned status %d", url, resp.StatusCode)" (err113)

Comment thread cmd/plt_media.go
}

if wantSize > 0 && size != wantSize {
return fmt.Errorf("size mismatch for %s: got %d, want %d", url, size, wantSize)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf("size mismatch for %s: got %d, want %d", url, size, wantSize)" (err113)

Comment thread cmd/plt_media.go
if wantChecksum != "" {
got := hex.EncodeToString(hash.Sum(nil))
if got != wantChecksum {
return fmt.Errorf("checksum mismatch for %s: got %s, want %s", url, got, wantChecksum)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf("checksum mismatch for %s: got %s, want %s", url, got, wantChecksum)" (err113)

Comment thread cmd/plt_clips_test.go
}
},
},
{

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
cmd. is missing field check (exhaustruct)

Comment thread cmd/plt_clips_test.go
markers: []Marker{mk("v1", 2.0, 10.0, 0), mk("v2", 15.0, 10.0, 0)},
wantRanges: 2,
},
{

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
cmd. is missing field check (exhaustruct)

Comment thread cmd/plt_media_test.go
},
{
name: "docid",
loc: Location{DocumentID: 1112024040, Track: 1, Type: 3},

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
cmd.Location is missing fields MajorMultimediaType, BaseDurationTicks, BookNumber, ChapterNumber, KeySymbol, MepsLanguage (exhaustruct)

Comment thread cmd/plt_media_test.go
}

func TestBuildMediaURL_UnsupportedShape(t *testing.T) {
_, err := buildMediaURL("https://example.invalid/api", "ASL", &Location{Type: 9})

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
cmd.Location is missing fields MajorMultimediaType, BaseDurationTicks, BookNumber, ChapterNumber, DocumentID, Track, KeySymbol, MepsLanguage (exhaustruct)

})
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
resp := mediaResponse{Files: map[string]mediaLang{
"ASL": {MP4: []mediaItem{{

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
string ASL has 7 occurrences, make it a constant (goconst)

@statik statik left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit

golangci

🚫 [golangci] reported by reviewdog 🐶
Magic number: 5, in detected (mnd)

from := startSec - 5


🚫 [golangci] reported by reviewdog 🐶
Magic number: 0.1, in detected (mnd)

interval := fmt.Sprintf("%.3f%%%.3f", from, startSec+0.1)


🚫 [golangci] reported by reviewdog 🐶
Magic number: 2, in detected (mnd)

if len(fields) < 2 {


🚫 [golangci] reported by reviewdog 🐶
Magic number: 0o600, in detected (mnd)

if err := os.WriteFile(path, append(data, '\n'), 0o600); err != nil {


🚫 [golangci] reported by reviewdog 🐶
Magic number: 60, in detected (mnd)

minutes := int(seconds) / 60


🚫 [golangci] reported by reviewdog 🐶
Magic number: 60, in detected (mnd)

rem := seconds - float64(minutes*60)


🚫 [golangci] reported by reviewdog 🐶
Magic number: 0o600, in detected (mnd)

if err := os.WriteFile(typPath, []byte(renderCueSheet(manifest)), 0o600); err != nil {


🚫 [golangci] reported by reviewdog 🐶
Magic number: 0o755, in detected (mnd)

if err := os.MkdirAll(cacheDir, 0o755); err != nil {


🚫 [golangci] reported by reviewdog 🐶
Magic number: 0o600, in detected (mnd)

if err := os.WriteFile(dest+".json", data, 0o600); err != nil {


🚫 [golangci] reported by reviewdog 🐶
continue with no blank line before (nlreturn)

continue


🚫 [golangci] reported by reviewdog 🐶
Function TestDownloadAndVerify missing the call to method parallel (paralleltest)

func TestDownloadAndVerify(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestDownloadAndVerify missing the call to method parallel in the test run (paralleltest)

t.Run("good size and checksum", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestDownloadAndVerify missing the call to method parallel in the test run (paralleltest)

t.Run("checksum mismatch is an error", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestDownloadAndVerify missing the call to method parallel in the test run (paralleltest)

t.Run("size mismatch is an error", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestFetchToCache_ReusesCache missing the call to method parallel (paralleltest)

func TestFetchToCache_ReusesCache(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestFetchMedia_ParsesRenditions missing the call to method parallel (paralleltest)

func TestFetchMedia_ParsesRenditions(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel (paralleltest)

func TestSelectRendition(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel in the test run (paralleltest)

t.Run("exact 720p", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel in the test run (paralleltest)

t.Run("absent resolution falls back to highest", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel in the test run (paralleltest)

t.Run("missing language is an error", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestProbeKeyframeBefore_Integration missing the call to method parallel (paralleltest)

func TestProbeKeyframeBefore_Integration(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestCutVerseClip_Integration missing the call to method parallel (paralleltest)

func TestCutVerseClip_Integration(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestArchiveExtractEntry missing the call to method parallel (paralleltest)

func TestArchiveExtractEntry(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestMergeMarkers missing the call to method parallel (paralleltest)

func TestMergeMarkers(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Range statement for test TestMergeMarkers missing the call to method parallel in test Run (paralleltest)

for _, tc := range cases {


🚫 [golangci] reported by reviewdog 🐶
Function TestFormatTimecode missing the call to method parallel (paralleltest)

func TestFormatTimecode(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestWritePlaylistJSON_RoundTrips missing the call to method parallel (paralleltest)

func TestWritePlaylistJSON_RoundTrips(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestRenderCueSheet missing the call to method parallel (paralleltest)

func TestRenderCueSheet(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestBuildMediaURL missing the call to method parallel (paralleltest)

func TestBuildMediaURL(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Range statement for test TestBuildMediaURL missing the call to method parallel in test Run (paralleltest)

for _, tc := range cases {


🚫 [golangci] reported by reviewdog 🐶
Function TestBuildMediaURL_UnsupportedShape missing the call to method parallel (paralleltest)

func TestBuildMediaURL_UnsupportedShape(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
test helper function should start from t.Helper() (thelper)

check: func(t *testing.T, ranges []clipRange) {


🚫 [golangci] reported by reviewdog 🐶
test helper function should start from t.Helper() (thelper)

check: func(t *testing.T, ranges []clipRange) {


🚫 [golangci] reported by reviewdog 🐶
test helper function should start from t.Helper() (thelper)

check: func(t *testing.T, ranges []clipRange) {


🚫 [golangci] reported by reviewdog 🐶
variable name 'rm' is too short for the scope of its usage (varnamelen)

rm, err := ctx.resolveMedia(item.Location)


🚫 [golangci] reported by reviewdog 🐶
parameter name 'rm' is too short for the scope of its usage (varnamelen)

item Item, index int, slug string, rm resolvedMedia, sourceRel, thumb string,


🚫 [golangci] reported by reviewdog 🐶
variable name 'r' is too short for the scope of its usage (varnamelen)

for i, r := range ranges {


🚫 [golangci] reported by reviewdog 🐶
parameter name 'rm' is too short for the scope of its usage (varnamelen)

func (ctx *buildContext) ensureMediaCopy(rm resolvedMedia) (string, error) {


🚫 [golangci] reported by reviewdog 🐶
parameter name 'w' is too short for the scope of its usage (varnamelen)

mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {


🚫 [golangci] reported by reviewdog 🐶
variable name 'm' is too short for the scope of its usage (varnamelen)

for _, m := range sorted {


🚫 [golangci] reported by reviewdog 🐶
variable name 'in' is too short for the scope of its usage (varnamelen)

in, err := os.Open(src)


🚫 [golangci] reported by reviewdog 🐶
variable name 'b' is too short for the scope of its usage (varnamelen)

var b strings.Builder


🚫 [golangci] reported by reviewdog 🐶
variable name 'q' is too short for the scope of its usage (varnamelen)

q := parsed.Query()


🚫 [golangci] reported by reviewdog 🐶
variable name 'zr' is too short for the scope of its usage (varnamelen)

zr, err := zip.OpenReader(a.path)


🚫 [golangci] reported by reviewdog 🐶
variable name 'rc' is too short for the scope of its usage (varnamelen)

rc, err := entry.Open()


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = arc.Close() }()


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

for i, item := range playlist.Items {


🚫 [golangci] reported by reviewdog 🐶
append only allowed to cuddle with appended value (wsl)

cues = append(cues, itemCues...)


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with declarations or returns (wsl)

pltBuildCmd.Flags().StringVar(&mediaAPI, "media-api", "", "media API base URL (overrides config key plt.mediaapi)")


🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

t.Cleanup(func() { pltBuildOut = "."; pltBuildResolution = "720p"; pltBuildLang = "" })


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with blocks (wsl)

t.Cleanup(func() { _ = arc.Close() })


🚫 [golangci] reported by reviewdog 🐶
append only allowed to cuddle with appended value (wsl)

cur.markers = append(cur.markers, m)


🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = out.Close() }()


🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

for _, tool := range []string{"ffmpeg", "ffprobe"} {


🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

makeTestVideo(t, src, 10)


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with blocks (wsl)

fmt.Fprintf(&b, " [%d], [#%s], [%s \\ #raw(%q)], [%s], [%s], [%d], [%s],\n",


🚫 [golangci] reported by reviewdog 🐶
declarations should never be cuddled (wsl)

var side mediaSidecar


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

for k, want := range tc.wantParams {

Comment thread cmd/plt_build.go
pltBuildResolution string
)

var pltBuildCmd = &coral.Command{

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
coral.Command is missing fields Aliases, SuggestFor, ValidArgs, ValidArgsFunction, ArgAliases, BashCompletionFunction, Deprecated, Annotations, Version, PersistentPreRun, PersistentPreRunE, PreRun, PreRunE, RunE, PostRun, PostRunE, PersistentPostRun, PersistentPostRunE, FParseErrWhitelist, CompletionOptions, TraverseChildren, Hidden, SilenceErrors, SilenceUsage, DisableFlagParsing, DisableAutoGenTag, DisableFlagsInUseLine, DisableSuggestions, SuggestionsMinimumDistance (exhaustruct)

Comment thread cmd/plt_client_test.go
func TestFetchMedia_ParsesRenditions(t *testing.T) {
srv := mediaTestServer(t, sanitizedMediaJSON)

resp, err := fetchMedia(srv.Client(), srv.URL, "ASL", &Location{KeySymbol: "sjj", Track: 135})

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
string sjj has 6 occurrences, make it a constant (goconst)

Comment thread cmd/plt_media.go
// then a document id. Anything else is an error naming the row.
func classifyLocation(loc *Location) (shapeKind, error) {
switch {
case loc.KeySymbol == "nwt" && loc.BookNumber > 0:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
string nwt has 4 occurrences, make it a constant (goconst)

Comment thread cmd/plt_media_test.go
}{
{
name: "pub track",
loc: Location{KeySymbol: "sjj", Track: 135, Type: 0},

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
string sjj has 6 occurrences, make it a constant (goconst)

Comment thread cmd/plt_media_test.go
name: "pub track",
loc: Location{KeySymbol: "sjj", Track: 135, Type: 0},
wantParams: map[string]string{"output": "json", "fileformat": "mp4", "langwritten": "ASL", "pub": "sjj", "track": "135"},
forbidden: []string{"booknum", "docid"},

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
string booknum has 3 occurrences, make it a constant (goconst)

Comment thread cmd/plt_cache_test.go
}

// mediaFileServer serves fixed bytes at any path and counts requests.
func mediaFileServer(t *testing.T, body []byte) (*httptest.Server, *int32) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
unnamedResult: consider giving a name to these results (gocritic)

Comment thread cmd/plt_media.go
}

// downloadAndVerify downloads url to dest and checks size and MD5 (when known).
func downloadAndVerify(client *http.Client, url, dest string, wantSize int64, wantChecksum string) error {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
importShadow: shadow of imported package 'url' (gocritic)

Comment thread cmd/plt_clips.go
}

duration := endSec - keyframe
cmd := exec.Command("ffmpeg", "-loglevel", "error",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)

func makeTestVideo(t *testing.T, path string, durationSec int) {
t.Helper()

cmd := exec.Command("ffmpeg", "-loglevel", "error", "-f", "lavfi",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)

Comment thread cmd/plt_parse.go
}
defer func() { _ = out.Close() }()

if _, err := io.Copy(out, rc); err != nil {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
G110: Potential DoS vulnerability via decompression bomb (gosec)

@statik statik left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit

golangci

🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel in the test run (paralleltest)

t.Run("absent resolution falls back to highest", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel in the test run (paralleltest)

t.Run("missing language is an error", func(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestProbeKeyframeBefore_Integration missing the call to method parallel (paralleltest)

func TestProbeKeyframeBefore_Integration(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestCutVerseClip_Integration missing the call to method parallel (paralleltest)

func TestCutVerseClip_Integration(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestArchiveExtractEntry missing the call to method parallel (paralleltest)

func TestArchiveExtractEntry(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestMergeMarkers missing the call to method parallel (paralleltest)

func TestMergeMarkers(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Range statement for test TestMergeMarkers missing the call to method parallel in test Run (paralleltest)

for _, tc := range cases {


🚫 [golangci] reported by reviewdog 🐶
Function TestFormatTimecode missing the call to method parallel (paralleltest)

func TestFormatTimecode(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestWritePlaylistJSON_RoundTrips missing the call to method parallel (paralleltest)

func TestWritePlaylistJSON_RoundTrips(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestRenderCueSheet missing the call to method parallel (paralleltest)

func TestRenderCueSheet(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestBuildMediaURL missing the call to method parallel (paralleltest)

func TestBuildMediaURL(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Range statement for test TestBuildMediaURL missing the call to method parallel in test Run (paralleltest)

for _, tc := range cases {


🚫 [golangci] reported by reviewdog 🐶
Function TestBuildMediaURL_UnsupportedShape missing the call to method parallel (paralleltest)

func TestBuildMediaURL_UnsupportedShape(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
test helper function should start from t.Helper() (thelper)

check: func(t *testing.T, ranges []clipRange) {


🚫 [golangci] reported by reviewdog 🐶
test helper function should start from t.Helper() (thelper)

check: func(t *testing.T, ranges []clipRange) {


🚫 [golangci] reported by reviewdog 🐶
test helper function should start from t.Helper() (thelper)

check: func(t *testing.T, ranges []clipRange) {


🚫 [golangci] reported by reviewdog 🐶
variable name 'rm' is too short for the scope of its usage (varnamelen)

rm, err := ctx.resolveMedia(item.Location)


🚫 [golangci] reported by reviewdog 🐶
parameter name 'rm' is too short for the scope of its usage (varnamelen)

item Item, index int, slug string, rm resolvedMedia, sourceRel, thumb string,


🚫 [golangci] reported by reviewdog 🐶
variable name 'r' is too short for the scope of its usage (varnamelen)

for i, r := range ranges {


🚫 [golangci] reported by reviewdog 🐶
parameter name 'rm' is too short for the scope of its usage (varnamelen)

func (ctx *buildContext) ensureMediaCopy(rm resolvedMedia) (string, error) {


🚫 [golangci] reported by reviewdog 🐶
parameter name 'w' is too short for the scope of its usage (varnamelen)

mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {


🚫 [golangci] reported by reviewdog 🐶
variable name 'm' is too short for the scope of its usage (varnamelen)

for _, m := range sorted {


🚫 [golangci] reported by reviewdog 🐶
variable name 'in' is too short for the scope of its usage (varnamelen)

in, err := os.Open(src)


🚫 [golangci] reported by reviewdog 🐶
variable name 'b' is too short for the scope of its usage (varnamelen)

var b strings.Builder


🚫 [golangci] reported by reviewdog 🐶
variable name 'q' is too short for the scope of its usage (varnamelen)

q := parsed.Query()


🚫 [golangci] reported by reviewdog 🐶
variable name 'zr' is too short for the scope of its usage (varnamelen)

zr, err := zip.OpenReader(a.path)


🚫 [golangci] reported by reviewdog 🐶
variable name 'rc' is too short for the scope of its usage (varnamelen)

rc, err := entry.Open()


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

for i, item := range playlist.Items {


🚫 [golangci] reported by reviewdog 🐶
append only allowed to cuddle with appended value (wsl)

cues = append(cues, itemCues...)


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with declarations or returns (wsl)

pltBuildCmd.Flags().StringVar(&mediaAPI, "media-api", "", "media API base URL (overrides config key plt.mediaapi)")


🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

t.Cleanup(func() { pltBuildOut = "."; pltBuildResolution = "720p"; pltBuildLang = "" })


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with blocks (wsl)

t.Cleanup(func() { _ = arc.Close() })


🚫 [golangci] reported by reviewdog 🐶
append only allowed to cuddle with appended value (wsl)

cur.markers = append(cur.markers, m)


🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = in.Close() }()


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = out.Close() }()


🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

for _, tool := range []string{"ffmpeg", "ffprobe"} {


🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

makeTestVideo(t, src, 10)


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with blocks (wsl)

fmt.Fprintf(&b, " [%d], [#%s], [%s \\ #raw(%q)], [%s], [%s], [%d], [%s],\n",


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = resp.Body.Close() }()


🚫 [golangci] reported by reviewdog 🐶
declarations should never be cuddled (wsl)

var side mediaSidecar


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

for k, want := range tc.wantParams {

Comment thread cmd/plt_build.go

playlist, err := parsePlaylist(arc)
if err != nil {
log.Fatal().Err(err).Msg("Could not parse playlist")

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
exitAfterDefer: log.Fatal will exit, and defer func(){...}(...) will not run (gocritic)

Comment thread cmd/plt_build.go

outDir := filepath.Join(resolveInputPath(pltBuildOut), slugify(playlist.Name))
for _, sub := range []string{"clips", "media", "thumbs"} {
if err := os.MkdirAll(filepath.Join(outDir, sub), 0o755); err != nil {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Magic number: 0o755, in detected (mnd)

Comment thread cmd/plt_clips.go
// probeKeyframeBefore returns the presentation time of the last keyframe at or
// before startSec. Published files use a uniform GOP, but this handles any.
func probeKeyframeBefore(file string, startSec float64) (float64, error) {
from := startSec - 5

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Magic number: 5, in detected (mnd)

Comment thread cmd/plt_clips.go
if from < 0 {
from = 0
}
interval := fmt.Sprintf("%.3f%%%.3f", from, startSec+0.1)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Magic number: 0.1, in detected (mnd)

Comment thread cmd/plt_clips.go
best := 0.0
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
fields := strings.Split(line, ",")
if len(fields) < 2 {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Magic number: 2, in detected (mnd)

Comment thread cmd/plt_cache_test.go
}
})

t.Run("size mismatch is an error", func(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestDownloadAndVerify missing the call to method parallel in the test run (paralleltest)

Comment thread cmd/plt_cache_test.go
})
}

func TestFetchToCache_ReusesCache(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestFetchToCache_ReusesCache missing the call to method parallel (paralleltest)

Comment thread cmd/plt_client_test.go
return srv
}

func TestFetchMedia_ParsesRenditions(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestFetchMedia_ParsesRenditions missing the call to method parallel (paralleltest)

Comment thread cmd/plt_client_test.go
}
}

func TestSelectRendition(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel (paralleltest)

Comment thread cmd/plt_client_test.go
t.Fatalf("fetchMedia: %v", err)
}

t.Run("exact 720p", func(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel in the test run (paralleltest)

@statik statik left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit

golangci

🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

t.Cleanup(func() { pltBuildOut = "."; pltBuildResolution = "720p"; pltBuildLang = "" })


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with blocks (wsl)

t.Cleanup(func() { _ = arc.Close() })


🚫 [golangci] reported by reviewdog 🐶
append only allowed to cuddle with appended value (wsl)

cur.markers = append(cur.markers, m)


🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = in.Close() }()


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = out.Close() }()


🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

for _, tool := range []string{"ffmpeg", "ffprobe"} {


🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

makeTestVideo(t, src, 10)


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with blocks (wsl)

fmt.Fprintf(&b, " [%d], [#%s], [%s \\ #raw(%q)], [%s], [%s], [%d], [%s],\n",


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = resp.Body.Close() }()


🚫 [golangci] reported by reviewdog 🐶
declarations should never be cuddled (wsl)

var side mediaSidecar


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

for k, want := range tc.wantParams {

Comment thread cmd/plt_client_test.go
}
})

t.Run("absent resolution falls back to highest", func(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel in the test run (paralleltest)

Comment thread cmd/plt_client_test.go
}
})

t.Run("missing language is an error", func(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestSelectRendition missing the call to method parallel in the test run (paralleltest)

return d
}

func TestProbeKeyframeBefore_Integration(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestProbeKeyframeBefore_Integration missing the call to method parallel (paralleltest)

}
}

func TestCutSegment_Integration(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestCutSegment_Integration missing the call to method parallel (paralleltest)

}
}

func TestArchiveExtractEntry(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestArchiveExtractEntry missing the call to method parallel (paralleltest)

Comment thread cmd/plt_media_test.go
if err != nil {
t.Fatalf("result is not a URL: %v", err)
}
q := parsed.Query()

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
variable name 'q' is too short for the scope of its usage (varnamelen)

Comment thread cmd/plt_parse.go
// the caller (derived from item order and slug), never from the entry name, so
// there is no zip-slip exposure; the entry name only locates the source bytes.
func (a *archive) extractEntry(entryName, destPath string) error {
zr, err := zip.OpenReader(a.path)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
variable name 'zr' is too short for the scope of its usage (varnamelen)

Comment thread cmd/plt_parse.go
return fmt.Errorf("zip entry %q not found in archive", entryName)
}

rc, err := entry.Open()

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
variable name 'rc' is too short for the scope of its usage (varnamelen)

Comment thread cmd/plt_build.go

var cues []cue
seen := map[string]int{}
for i, item := range playlist.Items {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

Comment thread cmd/plt_build.go
if err != nil {
return buildManifest{}, fmt.Errorf("item %d (%q): %w", i+1, item.Label, err)
}
cues = append(cues, itemCues...)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
append only allowed to cuddle with appended value (wsl)

@statik statik left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit

golangci

🚫 [golangci] reported by reviewdog 🐶
Function TestBuildCueSheetOnly_NoMedia missing the call to method parallel (paralleltest)

func TestBuildCueSheetOnly_NoMedia(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestEndActionLabel missing the call to method parallel (paralleltest)

func TestEndActionLabel(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestFormatTimecode missing the call to method parallel (paralleltest)

func TestFormatTimecode(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestWritePlaylistJSON_RoundTrips missing the call to method parallel (paralleltest)

func TestWritePlaylistJSON_RoundTrips(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
Function TestRenderCueSheet missing the call to method parallel (paralleltest)

func TestRenderCueSheet(t *testing.T) {


🚫 [golangci] reported by reviewdog 🐶
parameter name 'it' is too short for the scope of its usage (varnamelen)

vbs/cmd/plt.go

Line 179 in 2eb803b

func itemMediaURL(it Item, base string) string {


🚫 [golangci] reported by reviewdog 🐶
variable name 'b' is too short for the scope of its usage (varnamelen)

var b strings.Builder


🚫 [golangci] reported by reviewdog 🐶
parameter name 'b' is too short for the scope of its usage (varnamelen)

func writeCueSheetPreamble(b *strings.Builder, manifest buildManifest, total float64) {


🚫 [golangci] reported by reviewdog 🐶
parameter name 'c' is too short for the scope of its usage (varnamelen)

func cueSheetRow(c cue, elapsed, maxDur float64) string {


🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

vbs/cmd/plt.go

Line 294 in 2eb803b

for _, it := range view.Items {


🚫 [golangci] reported by reviewdog 🐶
if statements should only be cuddled with assignments (wsl)

vbs/cmd/plt.go

Line 299 in 2eb803b

if len(withURL) == 0 {


🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

vbs/cmd/plt.go

Line 306 in 2eb803b

for _, it := range withURL {


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with declarations or returns (wsl)

pltBuildCmd.Flags().StringVar(&mediaAPI, "media-api", "", "media API base URL (overrides config key plt.mediaapi)")


🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

t.Cleanup(func() { pltBuildOut = "."; pltBuildResolution = "720p"; pltBuildLang = "" })


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with blocks (wsl)

t.Cleanup(func() { _ = arc.Close() })


🚫 [golangci] reported by reviewdog 🐶
append only allowed to cuddle with appended value (wsl)

cur.markers = append(cur.markers, m)


🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = in.Close() }()


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = out.Close() }()


🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

makeTestVideo(t, src, 10)


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with blocks (wsl)

log.Info().Msgf("Wrote cue sheet into %s", outDir)


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

for i, item := range playlist.Items {


🚫 [golangci] reported by reviewdog 🐶
if statements should only be cuddled with assignments used in the if statement itself (wsl)

if c.DurationSec > maxDur {


🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

t.Cleanup(func() { pltCuesheetOut = "."; pltCuesheetResolution = "720p"; pltCuesheetLang = "" })


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

for _, dir := range []string{"media", "clips"} {


🚫 [golangci] reported by reviewdog 🐶
declarations should never be cuddled (wsl)

var manifest buildManifest


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

defer func() { _ = resp.Body.Close() }()


🚫 [golangci] reported by reviewdog 🐶
declarations should never be cuddled (wsl)

var side mediaSidecar

Comment thread cmd/plt.go

"github.com/muesli/coral"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
import 'github.com/spf13/viper' is not allowed from list 'Main' (depguard)

Comment thread cmd/plt_cuesheet.go
pltCuesheetResolution string
)

var pltCuesheetCmd = &coral.Command{

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
coral.Command is missing fields Aliases, SuggestFor, ValidArgs, ValidArgsFunction, ArgAliases, BashCompletionFunction, Deprecated, Annotations, Version, PersistentPreRun, PersistentPreRunE, PreRun, PreRunE, RunE, PostRun, PostRunE, PersistentPostRun, PersistentPostRunE, FParseErrWhitelist, CompletionOptions, TraverseChildren, Hidden, SilenceErrors, SilenceUsage, DisableFlagParsing, DisableAutoGenTag, DisableFlagsInUseLine, DisableSuggestions, SuggestionsMinimumDistance (exhaustruct)

Comment thread cmd/plt_cuesheet_test.go
)

func TestBuildCueSheetOnly_NoMedia(t *testing.T) {
arc, err := sniffPlaylist(writePlaylistFixture(t, fixtureOptions{}))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
cmd.fixtureOptions is missing fields schemaVersion, omitTables, omitManifest, notZip, corruptDB, databaseName (exhaustruct)

mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
resp := mediaResponse{Files: map[string]mediaLang{
"ASL": {MP4: []mediaItem{{
Title: "synthetic", Label: "720p",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
string 720p has 9 occurrences, make it a constant (goconst)

Comment thread cmd/plt_cache_test.go
cacheDir := t.TempDir()

item := mediaItem{
Label: "720p",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
string 720p has 9 occurrences, make it a constant (goconst)

Comment thread cmd/plt_client_test.go
if !fellBack {
t.Error("1080p is absent; should fall back")
}
if item.Label != "720p" || item.FrameHeight != 720 {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
string 720p has 9 occurrences, make it a constant (goconst)

Comment thread cmd/plt_cuesheet.go

playlist, err := parsePlaylist(arc)
if err != nil {
log.Fatal().Err(err).Msg("Could not parse playlist")

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
exitAfterDefer: log.Fatal will exit, and defer func(){...}(...) will not run (gocritic)

Comment thread cmd/plt_cuesheet.go

// buildCueSheetOnly assembles cue metadata from the playlist alone — no media
// downloads, no clip cutting — and writes playlist.json plus the cue sheet.
func buildCueSheetOnly(arc *archive, playlist *Playlist) (string, bool, error) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
unnamedResult: consider giving a name to these results (gocritic)

Comment thread cmd/plt_cuesheet.go
}

outDir := filepath.Join(resolveInputPath(pltCuesheetOut), slugify(playlist.Name))
if err := os.MkdirAll(filepath.Join(outDir, "thumbs"), 0o755); err != nil {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Magic number: 0o755, in detected (mnd)

Comment thread cmd/plt_cuesheet_test.go
"testing"
)

func TestBuildCueSheetOnly_NoMedia(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestBuildCueSheetOnly_NoMedia missing the call to method parallel (paralleltest)

Comment thread cmd/plt.go
// itemMediaURL builds the media API query URL an item resolves to, derived from
// its catalog keys. Image cues and unsupported shapes have no URL. When base is
// empty the placeholder "<plt.mediaapi>" stands in for the configured endpoint.
func itemMediaURL(it Item, base string) string {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
parameter name 'it' is too short for the scope of its usage (varnamelen)

Comment thread cmd/plt.go

// renderMediaURLs prints the media API query URL each item resolves to, derived
// from the playlist's catalog keys.
func renderMediaURLs(w io.Writer, view printView) error {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
parameter name 'w' is too short for the scope of its usage (varnamelen)

Comment thread cmd/plt.go
// from the playlist's catalog keys.
func renderMediaURLs(w io.Writer, view printView) error {
var withURL []printItem
for _, it := range view.Items {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

Comment thread cmd/plt.go
if _, err := fmt.Fprint(w, "\nMedia URLs:\n"); err != nil {
return fmt.Errorf("could not write media URL header: %w", err)
}
for _, it := range withURL {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
ranges should only be cuddled with assignments used in the iteration (wsl)

Comment thread cmd/plt_clips.go
if err != nil {
return fmt.Errorf("could not create %s: %w", dst, err)
}
defer func() { _ = out.Close() }()

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

dir := t.TempDir()
src := filepath.Join(dir, "src.mp4")
out := filepath.Join(dir, "clip.mp4")
makeTestVideo(t, src, 10)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

Comment thread cmd/plt_cuesheet.go
if !pdf {
log.Info().Msg("typst not found on PATH; wrote cuesheet.typ only (install typst to render cuesheet.pdf)")
}
log.Info().Msgf("Wrote cue sheet into %s", outDir)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with blocks (wsl)

Comment thread cmd/plt_cuesheet_test.go
pltCuesheetOut = out
pltCuesheetResolution = "720p"
pltCuesheetLang = ""
t.Cleanup(func() { pltCuesheetOut = "."; pltCuesheetResolution = "720p"; pltCuesheetLang = "" })

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
only cuddled expressions if assigning variable or using from line above (wsl)

Comment thread cmd/plt_media.go
if err != nil {
return false
}
var side mediaSidecar

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
declarations should never be cuddled (wsl)

@statik statik left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit

golangci

🚫 [golangci] reported by reviewdog 🐶
variable name 'rm' is too short for the scope of its usage (varnamelen)

rm, err := ctx.resolveMedia(item.Location)


🚫 [golangci] reported by reviewdog 🐶
parameter name 'rm' is too short for the scope of its usage (varnamelen)

item Item, index int, slug string, rm resolvedMedia, sourceRel, thumb string,


🚫 [golangci] reported by reviewdog 🐶
variable name 'r' is too short for the scope of its usage (varnamelen)

for i, r := range ranges {


🚫 [golangci] reported by reviewdog 🐶
variable name 'b' is too short for the scope of its usage (varnamelen)

var b strings.Builder


🚫 [golangci] reported by reviewdog 🐶
parameter name 'b' is too short for the scope of its usage (varnamelen)

func writeCueSheetPreamble(b *strings.Builder, manifest buildManifest, total float64) {


🚫 [golangci] reported by reviewdog 🐶
parameter name 'c' is too short for the scope of its usage (varnamelen)

func cueSheetRow(c cue, elapsed, maxDur float64) string {


🚫 [golangci] reported by reviewdog 🐶
expressions should not be cuddled with declarations or returns (wsl)

pltBuildCmd.Flags().StringVar(&mediaAPI, "media-api", "", "media API base URL (overrides config key plt.mediaapi)")


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

for i, item := range playlist.Items {


🚫 [golangci] reported by reviewdog 🐶
if statements should only be cuddled with assignments used in the if statement itself (wsl)

if c.DurationSec > maxDur {


🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

for _, dir := range []string{"media", "clips"} {


🚫 [golangci] reported by reviewdog 🐶
declarations should never be cuddled (wsl)

var manifest buildManifest

Comment thread cmd/plt_build.go
return ctx.imageCue(item, index, slug, thumb)
}
if item.Location == nil {
return nil, fmt.Errorf("video item has no catalog location")

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf("video item has no catalog location")" (err113)

Comment thread cmd/plt_build.go
if err := ctx.arc.extractEntry(item.Image.FilePath, filepath.Join(ctx.outDir, clipRel)); err != nil {
return nil, err
}
return []cue{{

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
cmd.cue is missing fields SourceMedia, Markers, Cut (exhaustruct)

Comment thread cmd/plt_build.go
if duration == 0 {
duration = ticksToSeconds(item.Location.BaseDurationTicks)
}
return []cue{{

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
cmd.cue is missing fields Markers, Cut (exhaustruct)

Comment thread cmd/plt_build.go
// trimRange turns an item's trim offsets into a single clip range, when set.
func trimRange(item Item) (clipRange, bool) {
if item.StartTrimTicks == 0 && item.EndTrimTicks == 0 {
return clipRange{}, false

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
cmd.clipRange is missing fields startTicks, endTicks, markers (exhaustruct)

Comment thread cmd/plt_build.go
return clipRange{}, false
}
if item.Location == nil {
return clipRange{}, false

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
cmd.clipRange is missing fields startTicks, endTicks, markers (exhaustruct)

Comment thread cmd/plt_cuesheet.go
// cuesheet.pdf. It returns whether a PDF was produced.
func writeCueSheet(dir string, manifest buildManifest) (bool, error) {
typPath := filepath.Join(dir, "cuesheet.typ")
if err := os.WriteFile(typPath, []byte(renderCueSheet(manifest)), 0o600); err != nil {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Magic number: 0o600, in detected (mnd)

Comment thread cmd/plt_cuesheet_test.go
}
}

func TestEndActionLabel(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestEndActionLabel missing the call to method parallel (paralleltest)

Comment thread cmd/plt_cuesheet_test.go
}
}

func TestFormatTimecode(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestFormatTimecode missing the call to method parallel (paralleltest)

Comment thread cmd/plt_cuesheet_test.go
}
}

func TestWritePlaylistJSON_RoundTrips(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestWritePlaylistJSON_RoundTrips missing the call to method parallel (paralleltest)

Comment thread cmd/plt_cuesheet_test.go
}
}

func TestRenderCueSheet(t *testing.T) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
Function TestRenderCueSheet missing the call to method parallel (paralleltest)

statik added 10 commits June 12, 2026 16:03
Build a self-contained working directory from a purple playlist: resolve
each catalog location to a media-API query, download renditions (default
720p) to a shared cache with MD5 + size verification, pre-cut verse clips
with a keyframe-snapped stream copy (no re-encode), extract image cues and
thumbnails, and emit playlist.json plus a Typst cue sheet (compiled to PDF
when typst is present).

Distinct locations are fetched once and downloads are cached, so re-running
is fast and deterministic. The media endpoint is config-only (plt.mediaapi)
and fails fast with an actionable message when unset.

Verified against the example export: 15 cues, media deduped to 10 files,
every verse clip starts within one GOP of its marker, re-run hits the cache.
Apply the same help example and BUILD_WORKING_DIRECTORY path resolution to
plt build: the playlist argument and --out are now resolved against the
invoking directory under 'bazel run'.
Derive and print the media-API query URL per item from its catalog keys
(pub/track, book/chapter, docid) plus the configured plt.mediaapi base.
Stays offline: image cues have no URL, and when the endpoint is unset a
<plt.mediaapi> placeholder shows the playlist-derived query. Added to both
the text output (a Media URLs section) and the JSON view.
Generate playlist.json, cuesheet.typ, extracted thumbnails, and (when typst
is installed) cuesheet.pdf straight from the playlist — no media downloads,
no clip cutting, no ffmpeg or media API. Durations come from the catalog
ticks and markers; the lead-in column is left blank since keyframe snapping
needs the real video files. Thumbnail extraction is now shared with build.
The lead-in is a build-time keyframe-snapping detail with no action for the
technical director, and was blank in offline cue sheets anyway. The value is
still recorded in playlist.json for the Phase 3 .mitti transform.
Give the cue sheet an editorial, workbook-style layout: clean sans-serif, a
header band, near-borderless rows with single-color cue numbers, and a footer
rule. Interpret the after-cue action codes (0 continue, 1 stop, 2 freeze) in
both the cue sheet and the plt print table, now that their meanings are
confirmed.
Bring back a small proportional duration sparkline per cue, and move the
running elapsed time under the duration as quiet gray text so it no longer
needs its own column.
Linear bars were dominated by the single longest cue, leaving the short cues
indistinguishable. A square-root scale spreads them out while the longest cue
still reads as the longest.
Write a .gitignore ("*") into every build/cuesheet working directory so the
generated output (clips, media, thumbnails, cue sheet, playlist.json) can never
be accidentally committed, regardless of the playlist slug or where the command
is run.
Comment thread cmd/plt_build.go
return nil, fmt.Errorf("video item has no catalog location")
}

rm, err := ctx.resolveMedia(item.Location)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
variable name 'rm' is too short for the scope of its usage (varnamelen)

Comment thread cmd/plt_build.go

// wholeVideoCue copies an untrimmed, marker-free video to its ordered clip.
func (ctx *buildContext) wholeVideoCue(
item Item, index int, slug string, rm resolvedMedia, sourceRel, thumb string,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
parameter name 'rm' is too short for the scope of its usage (varnamelen)

Comment thread cmd/plt_build.go
srcPath := filepath.Join(ctx.outDir, sourceRel)

cues := make([]cue, 0, len(ranges))
for i, r := range ranges {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
variable name 'r' is too short for the scope of its usage (varnamelen)

Comment thread cmd/plt_cuesheet.go
// a clean sans-serif, near-borderless layout with color-coded cue numbers, a
// header band, and a footer rule — echoing the meeting-workbook style.
func renderCueSheet(manifest buildManifest) string {
var b strings.Builder

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
variable name 'b' is too short for the scope of its usage (varnamelen)

Comment thread cmd/plt_cuesheet.go

// writeCueSheetPreamble emits the page setup (with a footer rule), the title
// band, and the muted metadata line.
func writeCueSheetPreamble(b *strings.Builder, manifest buildManifest, total float64) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
parameter name 'b' is too short for the scope of its usage (varnamelen)

Comment thread cmd/plt_cuesheet.go

var cues []cue
seen := map[string]int{}
for i, item := range playlist.Items {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

Comment thread cmd/plt_cuesheet.go
total, maxDur := 0.0, 0.0
for _, c := range manifest.Cues {
total += c.DurationSec
if c.DurationSec > maxDur {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
if statements should only be cuddled with assignments used in the if statement itself (wsl)

Comment thread cmd/plt_cuesheet_test.go
if entries, _ := os.ReadDir(filepath.Join(workDir, "thumbs")); len(entries) == 0 {
t.Error("expected extracted thumbnails")
}
for _, dir := range []string{"media", "clips"} {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before range statement (wsl)

Comment thread cmd/plt_cuesheet_test.go
if err != nil {
t.Fatalf("read %s: %v", path, err)
}
var manifest buildManifest

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
declarations should never be cuddled (wsl)

Comment thread cmd/plt_media.go
if err != nil {
return fmt.Errorf("download failed for %s: %w", url, err)
}
defer func() { _ = resp.Body.Close() }()

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
only one cuddle assignment allowed before defer statement (wsl)

Base automatically changed from plt-phase-1 to main June 12, 2026 20:12
@statik statik merged commit 4c1f1ce into main Jun 12, 2026
21 checks passed
@statik statik deleted the plt-phase-2 branch June 12, 2026 20:13
statik pushed a commit to kindlyops/cuesheet that referenced this pull request Jun 12, 2026
Plan covers the port of vbs plt cuesheet generation (kindlyops/vbs#887)
to a hexagonal Rust core with Typst linked as a library, a Tufte-styled
Tauri 2 GUI using the Fantastic Mr Fox palette, license attribution via
cargo-about, and a tag-driven release pipeline with gated code signing
and the Tauri updater.

https://claude.ai/code/session_01Sn1jjXDRydhdL4AGnkWNGQ
statik added a commit to kindlyops/cuesheet that referenced this pull request Jun 12, 2026
* Add detailed build plan for Cuesheet Tauri app

Plan covers the port of vbs plt cuesheet generation (kindlyops/vbs#887)
to a hexagonal Rust core with Typst linked as a library, a Tufte-styled
Tauri 2 GUI using the Fantastic Mr Fox palette, license attribution via
cargo-about, and a tag-driven release pipeline with gated code signing
and the Tauri updater.

https://claude.ai/code/session_01Sn1jjXDRydhdL4AGnkWNGQ

* Add GitHub Pages site (three.js red panda diorama) to plan

https://claude.ai/code/session_01Sn1jjXDRydhdL4AGnkWNGQ

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant