Skip to content

feat: post-download script hook#561

Merged
biodrone merged 10 commits into
stagingfrom
feat/post-download-script-hook
Apr 14, 2026
Merged

feat: post-download script hook#561
biodrone merged 10 commits into
stagingfrom
feat/post-download-script-hook

Conversation

@biodrone

@biodrone biodrone commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add support for running a user-defined script after a file has been successfully downloaded and moved to its final location. This enables use cases like auto-transcribing, remuxing to different formats, and copying files to additional locations.

Closes #478

Design decisions

  • Post-move only (for now): We considered supporting both pre-move and post-move hooks but decided to ship post-move only. The stated use cases (transcoding, remuxing, moving to additional locations, auto-transcribing) all operate on the final file in its final location. Pre-move introduces complexity around error handling (should a failure block the move?), filename mutation, and path passing — all for a use case nobody has requested. The plumbing will make adding pre_script trivial later if needed.
  • Config-driven: The script path will be set via a post_script field in the YAML config at the site level, making it configurable per-site.
  • Context via environment variables: The script will receive context about the download (file path, user, site, type) via environment variables rather than positional arguments, making it easier to extend without breaking existing scripts.
  • Non-blocking: The script runs in a goroutine so it doesn't block the tick loop or other downloads.

Test plan

  • Unit test for the script execution helper
  • Integration test with a simple script that touches a marker file
  • Verify live stream and VOD completion paths both trigger the hook
  • Verify missing/failing scripts log errors without crashing

@coderabbitai

coderabbitai Bot commented Apr 14, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds an optional per-site asynchronous post-download script hook: new config field, execution function with validation/timeout, integration into live/VOD download flows (non-blocking with waitgroup at shutdown), tests, and README/docs.

Changes

Cohort / File(s) Summary
Documentation
README.md
Added "Post-Download Script Hook" docs describing post_script YAML field, async invocation, env vars (STREAMDL_FILE, STREAMDL_USER, STREAMDL_SITE, STREAMDL_TYPE), and failure logging behavior.
Configuration
config.go
Added PostScript string (yaml:post_script) to Config struct for per-site hook configuration.
Config Tests
config_reader_test.go
Added TestParseConfig_PostScript to verify parsing of explicit and default post_script values across sites.
Download Integration
download_stream.go, streamdl.go
Extended downloadStream and downloadVOD signatures to accept site and postScript; start async runPostScript after successful file move; added global postScriptWg and wait for it during shutdown.
Post-Script Implementation
post_script.go
New runPostScript(scriptPath, filePath, user, site, dlType string) error: checks existence and executability, applies timeout from STREAMDL_POST_SCRIPT_TIMEOUT, executes script with file path arg and STREAMDL_* env vars, sets process group and enforces kill on timeout, returns contextual errors.
Post-Script Tests
post_script_test.go
Added unit tests covering successful execution and env vars, empty-script no-op, missing script, non-zero exit propagation, argument passing, and executability validation.
Integration Tests / Harness
tests/integration/docker-compose.integration.yml, tests/integration/run.sh
Mounted hooks and marker dirs into integration container; created test hook script and updated generated config.yml to set post_script; added verification checks for hook markers after live and VOD runs.
Manual Test Script
tests/manual/test_post_hook.sh
Added manual verification script that logs env vars and first arg to a host file for manual validation.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Downloader
    participant FS
    participant PostExecutor
    participant HookScript

    Client->>Downloader: start download
    Downloader->>FS: write temp file
    FS-->>Downloader: temp save ok
    Downloader->>FS: move file to final location
    FS-->>Downloader: move complete
    alt post_script configured
        Downloader->>PostExecutor: runPostScript(async)(scriptPath, filePath, user, site, type)
    end
    Downloader-->>Client: report download complete
    PostExecutor->>FS: stat script & check exec perms
    FS-->>PostExecutor: stat result
    PostExecutor->>HookScript: exec (arg=filePath) + env STREAMDL_*
    HookScript-->>PostExecutor: exit (success/failure)
    PostExecutor->>PostExecutor: log result (errors logged, not propagated)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • feat: Twitch VOD support #551 — touches download_stream.go and downloadVOD call sites; likely to conflict or interact with the signature and VOD-specific changes introduced here.

Poem

🐰
I hopped in code to plant a hook,
A tiny script that earns a look,
Async I nibble, never block,
Env vars passed — a tasty stock,
Cheers! — the rabbit left a crook.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: post-download script hook' clearly and concisely summarizes the main change: addition of a post-download script hook feature.
Linked Issues check ✅ Passed The PR fully addresses all requirements from issue #478: triggers user-defined scripts on file completion (post-move), supplies context via environment variables, enables post-processing use cases, and handles failures gracefully.
Out of Scope Changes check ✅ Passed All code changes are directly scoped to the post-download script hook feature. The changes include configuration, execution logic, tests, and integration test updates—all aligned with the feature requirements.
Description check ✅ Passed The pull request description is well-structured, clear, and comprehensive. It includes a summary, design decisions, and an itemized test plan.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/post-download-script-hook

Comment @coderabbitai help to get the list of available commands and usage tips.

@biodrone biodrone marked this pull request as ready for review April 14, 2026 10:27

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
README.md (1)

153-175: Document the timeout and executability requirements.

The runtime also requires the hook file to be executable and honors STREAMDL_POST_SCRIPT_TIMEOUT, but neither detail is called out in this section. Adding both will make hook failures much easier for users to diagnose.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 153 - 175, Update the "Post-Download Script Hook"
README section to state that the specified post_script file must be executable
by the runtime (ensure users set executable bits, e.g., chmod +x) and that
StreamDL enforces a timeout controlled by the STREAMDL_POST_SCRIPT_TIMEOUT
environment variable (document the env var name and its effect on script
execution and logging when the timeout is reached). Mention that if the script
is not executable or times out, an error will be logged and StreamDL will
continue processing other downloads.
post_script_test.go (1)

10-103: Add a timeout-path regression test.

These tests cover success, missing files, and non-zero exits, but the STREAMDL_POST_SCRIPT_TIMEOUT branch in runPostScript is still untested. A short timeout case with a sleeping script would protect the new cancellation logic from regressing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@post_script_test.go` around lines 10 - 103, Add a new unit test exercising
the STREAMDL_POST_SCRIPT_TIMEOUT branch by creating a short-lived temp script
that sleeps (e.g., "sleep 2") and setting the STREAMDL_POST_SCRIPT_TIMEOUT env
var to a smaller value (e.g., "1s") before calling runPostScript; assert that
runPostScript returns a timeout/cancellation error, and ensure you unset or
restore the env var after the test and mark the script executable (refer to
runPostScript, STREAMDL_POST_SCRIPT_TIMEOUT, and use t.TempDir(), os.WriteFile,
os.Setenv/Unsetenv in the test).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@post_script_test.go`:
- Around line 10-103: Add a new unit test exercising the
STREAMDL_POST_SCRIPT_TIMEOUT branch by creating a short-lived temp script that
sleeps (e.g., "sleep 2") and setting the STREAMDL_POST_SCRIPT_TIMEOUT env var to
a smaller value (e.g., "1s") before calling runPostScript; assert that
runPostScript returns a timeout/cancellation error, and ensure you unset or
restore the env var after the test and mark the script executable (refer to
runPostScript, STREAMDL_POST_SCRIPT_TIMEOUT, and use t.TempDir(), os.WriteFile,
os.Setenv/Unsetenv in the test).

In `@README.md`:
- Around line 153-175: Update the "Post-Download Script Hook" README section to
state that the specified post_script file must be executable by the runtime
(ensure users set executable bits, e.g., chmod +x) and that StreamDL enforces a
timeout controlled by the STREAMDL_POST_SCRIPT_TIMEOUT environment variable
(document the env var name and its effect on script execution and logging when
the timeout is reached). Mention that if the script is not executable or times
out, an error will be logged and StreamDL will continue processing other
downloads.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ed652bd6-7e23-4278-843d-b68b8af57f72

📥 Commits

Reviewing files that changed from the base of the PR and between a8567a1 and 5be9793.

📒 Files selected for processing (7)
  • README.md
  • config.go
  • config_reader_test.go
  • download_stream.go
  • post_script.go
  • post_script_test.go
  • streamdl.go

Comment thread post_script.go
Add a marker-based hook script to the integration test that writes
context to a file when fired. Both live stream and VOD phases now
verify the post_script hook ran with correct env vars.

Also add a manual test hook script for verifying on a live instance.
@biodrone biodrone merged commit 650e7f1 into staging Apr 14, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant