Skip to content

fix: don't autoplay videos in waves feed#965

Merged
feruzm merged 3 commits into
developfrom
fix/waves-no-video-autoplay
Jun 16, 2026
Merged

fix: don't autoplay videos in waves feed#965
feruzm merged 3 commits into
developfrom
fix/waves-no-video-autoplay

Conversation

@feruzm

@feruzm feruzm commented Jun 16, 2026

Copy link
Copy Markdown
Member

Problem

A user reported that videos (3Speak, and other embeds) on the Waves page autoplay, which is confusing, especially when scrolling past several at once.

Root cause

Waves and thread feeds render video embeds inline via renderOptions.embedVideosDirectly (set in waves-list-item and wave-view-details) instead of behind the usual click-to-play overlay. The directly-embedded players were requesting autoplay:

  • YouTube: the inline iframe used src=.../embed/<id>?autoplay=1 and an allow attribute that included autoplay.
  • 3Speak: the player autoplays by default, and nothing told it not to (neither the link-embed path in a.method nor the raw-iframe path in iframe.method).

Fix

Only when embedVideosDirectly is set (i.e. the waves/thread feed), load players paused:

  • YouTube (a.method): inline iframe src is now .../embed/<id> (no autoplay=1) and the autoplay permission is removed from allow.
  • 3Speak (a.method): inline iframe src now requests autoplay=false explicitly.
  • 3Speak raw iframes (iframe.method): renderOptions is now threaded through traverse, so raw <iframe> embeds in a wave body also default to autoplay=false.

The click-to-play path used everywhere else (post/entry pages) is unchanged: data-embed-src still carries autoplay, so playback starts right after the user clicks the overlay.

Tests

  • New regression tests in a.method.spec.ts (YouTube + 3Speak waves embeds verify no autoplay in the iframe src, while data-embed-src keeps autoplay for click-to-play).
  • New regression test in iframe.method.spec.ts (raw 3Speak iframe defaults to autoplay=false under embedVideosDirectly).
  • Full render-helper suite passes (1179 tests); package builds and lints clean.

Summary by CodeRabbit

  • Bug Fixes

    • Prevented embedded YouTube and 3Speak videos from autoplaying when direct embedding is enabled, including overriding any existing autoplay=true setting.
    • Updated direct-embed iframe behavior to ensure the embed URLs and autoplay permissions are non-autoplaying.
  • Tests

    • Added/expanded unit tests covering non-autoplay direct-embed behavior for YouTube and 3Speak, including cases where the input URL already contains autoplay=true.
  • Chores

    • Updated the render-helper changelog and bumped the package version to 2.5.13.

Waves and thread feeds render video embeds inline (embedVideosDirectly)
instead of behind a click-to-play overlay. The inline 3Speak and YouTube
players were starting playback automatically, so scrolling a feed could
leave several videos playing at once, which is disorienting.

When embedVideosDirectly is set, load the players paused:
- YouTube: drop ?autoplay=1 from the iframe src and remove the autoplay
  permission from the allow attribute.
- 3Speak: request autoplay=false explicitly (the player autoplays by
  default), both for link embeds (a.method) and raw iframe embeds
  (iframe.method, now passed renderOptions via traverse).

The click-to-play path used everywhere else is unchanged: data-embed-src
still carries autoplay so playback starts after the user clicks.
@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes video autoplay in the Waves/thread feed by ensuring that YouTube and 3Speak embeds rendered inline (embedVideosDirectly) load paused, while the existing click-to-play behavior on post/entry pages is unchanged.

  • YouTube (a.method.ts): a directSrc (no ?autoplay=1, no autoplay in allow) is used for the inline iframe; data-embed-src still carries ?autoplay=1 for click-to-play.
  • 3Speak (a.method.ts): &autoplay=false is appended to the inline iframe src; data-embed-src keeps the default URL so clicking still starts playback.
  • 3Speak raw iframes (iframe.method.ts + traverse.method.ts): renderOptions is now threaded through traverseiframe, and the 3Speak normalization path force-replaces any existing autoplay=true with autoplay=false when embedVideosDirectly is set — the regex replace handles pre-baked autoplay=true values correctly, and a dedicated regression test covers that case.

Confidence Score: 5/5

Safe to merge — the changes are narrowly scoped to the embedVideosDirectly code path, the click-to-play path is untouched, and the previously-reported edge case (pre-baked autoplay=true in a raw iframe src) is now properly handled with a regex replace and covered by a dedicated regression test.

The fix correctly suppresses autoplay across all three embed paths (YouTube via a.method, 3Speak via a.method, 3Speak raw iframes via iframe.method). The one subtle edge case — a raw iframe whose src already contains autoplay=true — is addressed by the regex substitution and verified by the new override test. The non-waves click-to-play path is unchanged. No logic errors or missing guards were found.

No files require special attention.

Important Files Changed

Filename Overview
packages/render-helper/src/methods/a.method.ts Adds directSrc for YouTube (no autoplay) and 3Speak (autoplay=false) when embedVideosDirectly is set; click-to-play path via data-embed-src is untouched.
packages/render-helper/src/methods/iframe.method.ts Accepts renderOptions, and for 3Speak raw iframes forces autoplay=false (replacing any pre-baked autoplay=true) when embedVideosDirectly is set.
packages/render-helper/src/methods/traverse.method.ts Threads renderOptions through to iframe() so raw iframe nodes in wave bodies also receive the no-autoplay treatment.
packages/render-helper/src/methods/a.method.spec.ts Adds regression tests for YouTube and 3Speak inline embeds verifying no autoplay in the iframe src, while data-embed-src retains autoplay for click-to-play.
packages/render-helper/src/methods/iframe.method.spec.ts Adds tests for both the no-autoplay default and the overriding of a pre-baked autoplay=true in raw 3Speak iframes under embedVideosDirectly.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[traverse node] --> B{node type?}
    B -->|anchor tag| C[a.method]
    B -->|iframe tag| D[iframe.method\nnow receives renderOptions]

    C --> E{embedVideosDirectly?}
    E -->|Yes - waves feed| F{platform?}
    E -->|No - post/entry| G[set data-embed-src\nwith autoplay\nclick-to-play overlay]

    F -->|YouTube| H[directSrc: embed/ID\nno autoplay=1\nno autoplay in allow]
    F -->|3Speak| I[directSrc: videoHref\n+ autoplay=false]

    D --> J{3Speak src?}
    J -->|Yes| K{embedVideosDirectly?}
    K -->|Yes| L{hasAutoplay?}
    L -->|autoplay present| M[regex replace\nautoplay=false]
    L -->|autoplay absent| N[append autoplay=false]
    K -->|No| O[append autoplay=true\nif absent]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[traverse node] --> B{node type?}
    B -->|anchor tag| C[a.method]
    B -->|iframe tag| D[iframe.method\nnow receives renderOptions]

    C --> E{embedVideosDirectly?}
    E -->|Yes - waves feed| F{platform?}
    E -->|No - post/entry| G[set data-embed-src\nwith autoplay\nclick-to-play overlay]

    F -->|YouTube| H[directSrc: embed/ID\nno autoplay=1\nno autoplay in allow]
    F -->|3Speak| I[directSrc: videoHref\n+ autoplay=false]

    D --> J{3Speak src?}
    J -->|Yes| K{embedVideosDirectly?}
    K -->|Yes| L{hasAutoplay?}
    L -->|autoplay present| M[regex replace\nautoplay=false]
    L -->|autoplay absent| N[append autoplay=false]
    K -->|No| O[append autoplay=true\nif absent]
Loading

Reviews (3): Last reviewed commit: "chore: apply changeset versioning for PR..." | Re-trigger Greptile

Comment thread packages/render-helper/src/methods/iframe.method.ts Outdated
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0bd46a4d-ab30-4ebf-8053-2d76674f21f5

📥 Commits

Reviewing files that changed from the base of the PR and between 4a1b86c and 006e2f2.

⛔ Files ignored due to path filters (6)
  • packages/render-helper/dist/browser/index.js is excluded by !**/dist/**
  • packages/render-helper/dist/browser/index.js.map is excluded by !**/dist/**, !**/*.map
  • packages/render-helper/dist/node/index.cjs is excluded by !**/dist/**
  • packages/render-helper/dist/node/index.cjs.map is excluded by !**/dist/**, !**/*.map
  • packages/render-helper/dist/node/index.mjs is excluded by !**/dist/**
  • packages/render-helper/dist/node/index.mjs.map is excluded by !**/dist/**, !**/*.map
📒 Files selected for processing (4)
  • packages/render-helper/CHANGELOG.md
  • packages/render-helper/package.json
  • packages/render-helper/src/methods/iframe.method.spec.ts
  • packages/render-helper/src/methods/iframe.method.ts

📝 Walkthrough

Walkthrough

YouTube and 3Speak embed handlers are updated so that the embedVideosDirectly path produces iframes without autoplay. The iframe() function gains an optional renderOptions parameter to control 3Speak autoplay defaulting, and traverse() is updated to pass renderOptions through to iframe(). Tests are added for both providers, and the package version is bumped to 2.5.13.

Changes

Disable autoplay in embedVideosDirectly mode

Layer / File(s) Summary
iframe() signature and 3Speak autoplay logic
packages/render-helper/src/methods/iframe.method.ts
Adds RenderOptions import and optional renderOptions parameter to iframe(); sets 3Speak autoplay=false when embedVideosDirectly is true and autoplay=true otherwise, preserving any pre-existing autoplay value.
traverse() threads renderOptions to iframe()
packages/render-helper/src/methods/traverse.method.ts
Updates the iframe() call to pass renderOptions as the fourth argument.
YouTube and 3Speak direct-embed URL changes
packages/render-helper/src/methods/a.method.ts
YouTube embedVideosDirectly branch uses /embed/{vid} without autoplay=1 and removes autoplay from the allow attribute; 3Speak embedVideosDirectly branch constructs directSrc with &autoplay=false.
Tests for no-autoplay direct-embed behavior
packages/render-helper/src/methods/a.method.spec.ts, packages/render-helper/src/methods/iframe.method.spec.ts
New test cases assert that embedVideosDirectly produces iframes without autoplay in src/allow for both YouTube and 3Speak, while data-embed-src retains the autoplay URL for click-to-play; additional iframe() tests assert autoplay=false and no autoplay=true in the normalized 3Speak src, including when the input URL already contains autoplay=true.
Release notes and version bump
packages/render-helper/package.json, packages/render-helper/CHANGELOG.md
Package version incremented to 2.5.13 and changelog entry documents the fix to avoid autoplaying videos in the Waves feed.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • ecency/vision-next#661: Modifies the same 3Speak embed URL handling in a.method.ts and iframe.method.ts, directly adjacent to this PR's autoplay/embedVideosDirectly extension of that logic.
  • ecency/vision-next#719: Updates iframe() signature and traverse() call propagation patterns in the same files to pass options through the render pipeline.
  • ecency/vision-next#617: Updates 3Speak src/autoplay URL normalization in the same render path files (a.method.ts / iframe.method.ts).

Poem

🐇 A rabbit hops and checks the code,
No autoplay on the embed road!
Direct-embed means quiet streams,
3Speak and YouTube, no autoplaying dreams.
Tests all pass — the warren's clean! 🎬

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: preventing autoplay of videos in the Waves feed, which directly addresses the core issue described in the PR objectives.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 fix/waves-no-video-autoplay

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/render-helper/src/methods/iframe.method.spec.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

YAMLException: Cannot read config file: /packages/render-helper/eslint.config.mjs
Error: end of the stream or a document separator is expected (22:12)

19 |
20 | export default tseslint.config(
21 | {
22 | ignores: ["dist", "node_modules", "tsu ...
-----------------^
23 | },
24 | {
at generateError (/node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/lib/loader.js:199:10)
at throwError (/node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/lib/loader.js:203:9)
at readDocument (/node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/lib/loader.js:1651:5)
at loadDocuments (/node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/lib/loader.js:1694:5)
at Object.load (/node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/lib/loader.js:1720:19)
at loadLegacyConfigFile (/node_modules/.pnpm/@eslint+eslintrc@2.1.4/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2565:21)
at loadConfigFile (/node_modules/.pnpm/@eslint+eslintrc@2.1.4/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2680:20)
at ConfigArrayFactory._loadConfigData (/node_modules/.pnpm/@eslint+eslintrc@2.1.4/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2984:42)
at ConfigArrayFactory.loadFile (/node_modules/.pnpm/@eslint+eslintrc@2.1.4/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2850:40)
at createCLIConfigArray (/node_modules/.pnpm/@eslint+eslintrc@2.1.4/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3660:35)

packages/render-helper/src/methods/iframe.method.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

YAMLException: Cannot read config file: /packages/render-helper/eslint.config.mjs
Error: end of the stream or a document separator is expected (22:12)

19 |
20 | export default tseslint.config(
21 | {
22 | ignores: ["dist", "node_modules", "tsu ...
-----------------^
23 | },
24 | {
at generateError (/node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/lib/loader.js:199:10)
at throwError (/node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/lib/loader.js:203:9)
at readDocument (/node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/lib/loader.js:1651:5)
at loadDocuments (/node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/lib/loader.js:1694:5)
at Object.load (/node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/lib/loader.js:1720:19)
at loadLegacyConfigFile (/node_modules/.pnpm/@eslint+eslintrc@2.1.4/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2565:21)
at loadConfigFile (/node_modules/.pnpm/@eslint+eslintrc@2.1.4/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2680:20)
at ConfigArrayFactory._loadConfigData (/node_modules/.pnpm/@eslint+eslintrc@2.1.4/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2984:42)
at ConfigArrayFactory.loadFile (/node_modules/.pnpm/@eslint+eslintrc@2.1.4/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2850:40)
at createCLIConfigArray (/node_modules/.pnpm/@eslint+eslintrc@2.1.4/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3660:35)


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Address review: the previous embedVideosDirectly guard in iframe.method
only applied when the src had no autoplay param. A raw 3Speak <iframe>
that already carried autoplay=true (e.g. .../embed?v=foo&autoplay=true)
short-circuited the guard and still autoplayed in the waves feed.

Now, under embedVideosDirectly, force autoplay=false even when one is
already present (overwrite via regex); elsewhere keep adding autoplay=true
only when absent so an author-supplied value is preserved. Adds a
regression test for the baked-in autoplay=true case.
@feruzm feruzm added the patch Bug fixes and patches (1.0.0 → 1.0.1) label Jun 16, 2026
@feruzm feruzm merged commit 9f48d76 into develop Jun 16, 2026
2 of 3 checks passed
@feruzm feruzm deleted the fix/waves-no-video-autoplay branch June 16, 2026 11:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

patch Bug fixes and patches (1.0.0 → 1.0.1)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant