{ "issue": { "url": "https://api.github.com/repos/laurent22/joplin/issues/14356", "repository_url": "https://api.github.com/repos/laurent22/joplin", "labels_url": "https://api.github.com/repos/laurent22/joplin/issues/14356/labels{/name}", "comments_url": "https://api.github.com/repos/laurent22/joplin/issues/14356/comments", "events_url": "https://api.github.com/repos/laurent22/joplin/issues/14356/events", "html_url": "https://github.com/laurent22/joplin/pull/14356", "id": 3942301540, "node_id": "PR_kwDOBLftOs7D0sb2", "number": 14356, "title": "Fix: Only embed YouTube videos when URL is on its own line ", "user": { "login": "Shresthap21", "id": 122041239, "node_id": "U_kgDOB0Yzlw", "avatar_url": "https://avatars.githubusercontent.com/u/122041239?v=4", "gravatar_id": "", "url": "https://api.github.com/users/Shresthap21", "html_url": "https://github.com/Shresthap21", "followers_url": "https://api.github.com/users/Shresthap21/followers", "following_url": "https://api.github.com/users/Shresthap21/following{/other_user}", "gists_url": "https://api.github.com/users/Shresthap21/gists{/gist_id}", "starred_url": "https://api.github.com/users/Shresthap21/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/Shresthap21/subscriptions", "organizations_url": "https://api.github.com/users/Shresthap21/orgs", "repos_url": "https://api.github.com/users/Shresthap21/repos", "events_url": "https://api.github.com/users/Shresthap21/events{/privacy}", "received_events_url": "https://api.github.com/users/Shresthap21/received_events", "type": "User", "user_view_type": "public", "site_admin": false }, "labels": [], "state": "closed", "locked": true, "assignees": [], "milestone": null, "comments": 4, "created_at": "2026-02-14T20:45:12Z", "updated_at": "2026-02-17T22:53:22Z", "closed_at": "2026-02-15T09:38:44Z", "assignee": null, "author_association": "NONE", "active_lock_reason": "spam", "draft": false, "pull_request": { "url": "https://api.github.com/repos/laurent22/joplin/pulls/14356", "html_url": "https://github.com/laurent22/joplin/pull/14356", "diff_url": "https://github.com/laurent22/joplin/pull/14356.diff", "patch_url": "https://github.com/laurent22/joplin/pull/14356.patch", "merged_at": null }, "body": "Fixes #14352\r\n\r\n## Problem\r\nWhen `markdown.plugin.externalEmbed` is enabled, YouTube videos were being embedded even when the URL appeared inline with other text, not just when standalone on its own line.\r\n\r\n## Solution\r\nModified the `externalEmbed` plugin to check for surrounding text content before/after YouTube links:\r\n- Checks for any text tokens before the link in the same paragraph\r\n- Checks for any text tokens after the link in the same paragraph\r\n- Only embeds the video if no surrounding text is found (URL is standalone)\r\n- Inline URLs are now rendered as regular links\r\n\r\n## Test Cases\r\nAdded comprehensive test cases:\r\n- `external_embed_inline.md/html` - Tests inline and standalone scenarios\r\n- `external_embed_edges.md/html` - Edge cases (URL at start/end of paragraph, multiple URLs)\r\n\r\n## Examples\r\n **Before:** Inline URL would embed → `Text https://youtube.com/watch?v=xyz more text` ❌ \r\n **After:** Inline URL shows as link → `Text https://youtube.com/watch?v=xyz more text` ✓ \r\n **Standalone still embeds:** Empty line with just URL → Embeds video ✓\n\n\n## Summary by CodeRabbit\n\n* **Tests**\n * Added Markdown and HTML test cases covering various external embed edge cases (URLs at start/end of paragraphs, standalone URLs, multiple inline URLs, YouTube embed behaviour).\n\n* **Improvements**\n * YouTube/video embedding now triggers only for truly standalone links; links surrounded by other text render as regular anchors.\n", "closed_by": { "login": "laurent22", "id": 1285584, "node_id": "MDQ6VXNlcjEyODU1ODQ=", "avatar_url": "https://avatars.githubusercontent.com/u/1285584?v=4", "gravatar_id": "", "url": "https://api.github.com/users/laurent22", "html_url": "https://github.com/laurent22", "followers_url": "https://api.github.com/users/laurent22/followers", "following_url": "https://api.github.com/users/laurent22/following{/other_user}", "gists_url": "https://api.github.com/users/laurent22/gists{/gist_id}", "starred_url": "https://api.github.com/users/laurent22/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/laurent22/subscriptions", "organizations_url": "https://api.github.com/users/laurent22/orgs", "repos_url": "https://api.github.com/users/laurent22/repos", "events_url": "https://api.github.com/users/laurent22/events{/privacy}", "received_events_url": "https://api.github.com/users/laurent22/received_events", "type": "User", "user_view_type": "public", "site_admin": false }, "reactions": { "url": "https://api.github.com/repos/laurent22/joplin/issues/14356/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 }, "timeline_url": "https://api.github.com/repos/laurent22/joplin/issues/14356/timeline", "performed_via_github_app": null, "state_reason": null }, "comments": [ { "url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3902492465", "html_url": "https://github.com/laurent22/joplin/pull/14356#issuecomment-3902492465", "issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14356", "id": 3902492465, "node_id": "IC_kwDOBLftOs7om08x", "user": { "login": "github-actions[bot]", "id": 41898282, "node_id": "MDM6Qm90NDE4OTgyODI=", "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", "gravatar_id": "", "url": "https://api.github.com/users/github-actions%5Bbot%5D", "html_url": "https://github.com/apps/github-actions", "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", "type": "Bot", "user_view_type": "public", "site_admin": false }, "created_at": "2026-02-14T20:45:23Z", "updated_at": "2026-02-15T09:38:54Z", "body": "****CLA Assistant Lite bot**** All contributors have signed the CLA ✍️ ✅", "author_association": "CONTRIBUTOR", "reactions": { "url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3902492465/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 }, "performed_via_github_app": { "id": 15368, "client_id": "Iv1.05c79e9ad1f6bdfa", "slug": "github-actions", "node_id": "MDM6QXBwMTUzNjg=", "owner": { "login": "github", "id": 9919, "node_id": "MDEyOk9yZ2FuaXphdGlvbjk5MTk=", "avatar_url": "https://avatars.githubusercontent.com/u/9919?v=4", "gravatar_id": "", "url": "https://api.github.com/users/github", "html_url": "https://github.com/github", "followers_url": "https://api.github.com/users/github/followers", "following_url": "https://api.github.com/users/github/following{/other_user}", "gists_url": "https://api.github.com/users/github/gists{/gist_id}", "starred_url": "https://api.github.com/users/github/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/github/subscriptions", "organizations_url": "https://api.github.com/users/github/orgs", "repos_url": "https://api.github.com/users/github/repos", "events_url": "https://api.github.com/users/github/events{/privacy}", "received_events_url": "https://api.github.com/users/github/received_events", "type": "Organization", "user_view_type": "public", "site_admin": false }, "name": "GitHub Actions", "description": "Automate your workflow from idea to production", "external_url": "https://help.github.com/en/actions", "html_url": "https://github.com/apps/github-actions", "created_at": "2018-07-30T09:30:17Z", "updated_at": "2026-05-05T14:51:38Z", "permissions": { "actions": "write", "administration": "read", "artifact_metadata": "write", "attestations": "write", "checks": "write", "code_quality": "write", "contents": "write", "copilot_requests": "write", "deployments": "write", "discussions": "write", "issues": "write", "merge_queues": "write", "metadata": "read", "models": "read", "packages": "write", "pages": "write", "pull_requests": "write", "repository_hooks": "write", "repository_projects": "write", "security_events": "write", "statuses": "write", "vulnerability_alerts": "read" }, "events": [ "branch_protection_rule", "check_run", "check_suite", "create", "delete", "deployment", "deployment_status", "discussion", "discussion_comment", "fork", "gollum", "issues", "issue_comment", "label", "merge_group", "milestone", "page_build", "public", "pull_request", "pull_request_review", "pull_request_review_comment", "push", "registry_package", "release", "repository", "repository_dispatch", "status", "watch", "workflow_dispatch", "workflow_run" ] } }, { "url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3902492902", "html_url": "https://github.com/laurent22/joplin/pull/14356#issuecomment-3902492902", "issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14356", "id": 3902492902, "node_id": "IC_kwDOBLftOs7om1Dm", "user": { "login": "coderabbitai[bot]", "id": 136622811, "node_id": "BOT_kgDOCCSy2w", "avatar_url": "https://avatars.githubusercontent.com/in/347564?v=4", "gravatar_id": "", "url": "https://api.github.com/users/coderabbitai%5Bbot%5D", "html_url": "https://github.com/apps/coderabbitai", "followers_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/followers", "following_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/following{/other_user}", "gists_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/gists{/gist_id}", "starred_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/subscriptions", "organizations_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/orgs", "repos_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/repos", "events_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/events{/privacy}", "received_events_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/received_events", "type": "Bot", "user_view_type": "public", "site_admin": false }, "created_at": "2026-02-14T20:45:40Z", "updated_at": "2026-02-14T20:59:01Z", "body": "\n\n\n## Walkthrough\n\nUpdates add new markdown/HTML test fixtures for external-URL embedding edge cases and tighten the renderer's external-embed rule so YouTube links are embedded only when the link appears on its own line (standalone), not when inline with other text.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**External Embed Test Cases**
`packages/app-cli/tests/md_to_html/external_embed_edges.md`, `packages/app-cli/tests/md_to_html/external_embed_edges.html`, `packages/app-cli/tests/md_to_html/external_embed_inline.md`, `packages/app-cli/tests/md_to_html/external_embed_inline.html`|Adds new test fixtures covering edge cases for external embedding: URLs at paragraph start/end, standalone URL blocks, and inline multiple URLs. Expected HTML shows standalone YouTube URLs rendered as iframes while inline URLs remain plain links.|\n|**Embedding Logic**
`packages/renderer/MdToHtml/rules/externalEmbed.ts`|Changes standalone-link detection: embedding now triggers only when a link has no surrounding content (ignoring whitespace/line breaks). Retains `activeEmbedVideo` state and existing embed HTML generation, but guards activation with the stricter standalone condition.|\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n\n\n\n\n\n
\n🚥 Pre-merge checks | ✅ 6\n\n
\n✅ Passed checks (6 passed)\n\n| Check name | Status | Explanation |\n| :------------------------: | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |\n| Title check | ✅ Passed | The title accurately summarizes the main change: implementing a fix to embed YouTube videos only when the URL appears on its own line, which is the primary objective of the PR. |\n| Linked Issues check | ✅ Passed | The PR modifications to externalEmbed.ts implement the required detection of standalone URLs, and test files comprehensively cover inline, standalone, and edge-case scenarios as specified in issue `#14352`. |\n| Out of Scope Changes check | ✅ Passed | All changes are directly scoped to the linked issue `#14352`: modifying the embed detection logic and adding comprehensive test fixtures for inline vs. standalone YouTube URL scenarios. |\n| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |\n| Merge Conflict Detection | ✅ Passed | ✅ No merge conflicts detected when merging into `dev` |\n\n
\n\n✏️ Tip: You can configure your own custom pre-merge checks in the settings.\n\n
\n\n\n\n\n\n
\n✨ Finishing touches\n\n- [ ] 📝 Generate docstrings\n
\n🧪 Generate unit tests (beta)\n\n- [ ] Create PR with unit tests\n- [ ] Post copyable unit tests in a comment\n\n
\n\n
\n\n\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n
\n🧹 Recent nitpick comments
\n\n
\npackages/renderer/MdToHtml/rules/externalEmbed.ts (1)
\n\n`24-24`: **Consider resetting state at the start of rendering to improve robustness.**\n\nThe `activeEmbedVideo` variable is closure-scoped and persists across renders when the same `markdownIt` instance is reused. If rendering fails after `link_open` sets the state but before `link_close` clears it, stale state could affect subsequent renders.\n\nA defensive approach would be to ensure the state is reset at appropriate boundaries, though this may require architectural changes beyond this PR's scope.\n\n
\n\n
\n\n\n\n---\n\n\n\nComment `@coderabbitai help` to get the list of available commands and usage tips.\n\n\n\n\n\n\n\n\n", "author_association": "CONTRIBUTOR", "reactions": { "url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3902492902/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 }, "performed_via_github_app": { "id": 347564, "client_id": "Iv1.6aaafe4fe882736b", "slug": "coderabbitai", "node_id": "A_kwHOB96YWc4ABU2s", "owner": { "login": "coderabbitai", "id": 132028505, "node_id": "O_kgDOB96YWQ", "avatar_url": "https://avatars.githubusercontent.com/u/132028505?v=4", "gravatar_id": "", "url": "https://api.github.com/users/coderabbitai", "html_url": "https://github.com/coderabbitai", "followers_url": "https://api.github.com/users/coderabbitai/followers", "following_url": "https://api.github.com/users/coderabbitai/following{/other_user}", "gists_url": "https://api.github.com/users/coderabbitai/gists{/gist_id}", "starred_url": "https://api.github.com/users/coderabbitai/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/coderabbitai/subscriptions", "organizations_url": "https://api.github.com/users/coderabbitai/orgs", "repos_url": "https://api.github.com/users/coderabbitai/repos", "events_url": "https://api.github.com/users/coderabbitai/events{/privacy}", "received_events_url": "https://api.github.com/users/coderabbitai/received_events", "type": "Organization", "user_view_type": "public", "site_admin": false }, "name": "coderabbitai", "description": "# Transforming Code Reviews with AI\r\n\r\n## Features\r\n\r\n**Automated Reviews**: Continuous reviews of the pull requests including incremental commits. \r\n\r\n**Summarization**: Generates high-level summary and a technical walkthrough of the PR changes. \r\n\r\n**Line-by-line review**: Provides line-by-line suggestions committable with one click.\r\n\r\n**Codebase verification**: Verifies the impact on the overall codebase and identifies missing changes.\r\n\r\n**Insights into your code**: Ask any questions on your codebase within the pull request \r\n\r\n**Chat about your code** : Chat with the bot around your code. The more you chat, the smarter it gets.\r\n\r\n**Issue Validation**: Validates the PR against the linked issues and identifies other related issues \r\n\r\n\r\n\r\n", "external_url": "https://coderabbit.ai?utm_source=cr_app&utm_medium=github", "html_url": "https://github.com/apps/coderabbitai", "created_at": "2023-06-14T15:47:27Z", "updated_at": "2026-03-14T07:58:44Z", "permissions": { "actions": "read", "checks": "write", "contents": "write", "discussions": "read", "issues": "write", "members": "read", "metadata": "read", "pull_requests": "write", "statuses": "write" }, "events": [ "issues", "issue_comment", "label", "organization", "pull_request", "pull_request_review", "pull_request_review_comment", "pull_request_review_thread", "release", "repository" ] } }, { "url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3902499388", "html_url": "https://github.com/laurent22/joplin/pull/14356#issuecomment-3902499388", "issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14356", "id": 3902499388, "node_id": "IC_kwDOBLftOs7om2o8", "user": { "login": "Shresthap21", "id": 122041239, "node_id": "U_kgDOB0Yzlw", "avatar_url": "https://avatars.githubusercontent.com/u/122041239?v=4", "gravatar_id": "", "url": "https://api.github.com/users/Shresthap21", "html_url": "https://github.com/Shresthap21", "followers_url": "https://api.github.com/users/Shresthap21/followers", "following_url": "https://api.github.com/users/Shresthap21/following{/other_user}", "gists_url": "https://api.github.com/users/Shresthap21/gists{/gist_id}", "starred_url": "https://api.github.com/users/Shresthap21/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/Shresthap21/subscriptions", "organizations_url": "https://api.github.com/users/Shresthap21/orgs", "repos_url": "https://api.github.com/users/Shresthap21/repos", "events_url": "https://api.github.com/users/Shresthap21/events{/privacy}", "received_events_url": "https://api.github.com/users/Shresthap21/received_events", "type": "User", "user_view_type": "public", "site_admin": false }, "created_at": "2026-02-14T20:50:00Z", "updated_at": "2026-02-14T20:50:00Z", "body": "I have read the CLA Document and I hereby sign the CLA", "author_association": "NONE", "reactions": { "url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3902499388/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 }, "performed_via_github_app": null }, { "url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3903997230", "html_url": "https://github.com/laurent22/joplin/pull/14356#issuecomment-3903997230", "issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14356", "id": 3903997230, "node_id": "IC_kwDOBLftOs7oskUu", "user": { "login": "laurent22", "id": 1285584, "node_id": "MDQ6VXNlcjEyODU1ODQ=", "avatar_url": "https://avatars.githubusercontent.com/u/1285584?v=4", "gravatar_id": "", "url": "https://api.github.com/users/laurent22", "html_url": "https://github.com/laurent22", "followers_url": "https://api.github.com/users/laurent22/followers", "following_url": "https://api.github.com/users/laurent22/following{/other_user}", "gists_url": "https://api.github.com/users/laurent22/gists{/gist_id}", "starred_url": "https://api.github.com/users/laurent22/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/laurent22/subscriptions", "organizations_url": "https://api.github.com/users/laurent22/orgs", "repos_url": "https://api.github.com/users/laurent22/repos", "events_url": "https://api.github.com/users/laurent22/events{/privacy}", "received_events_url": "https://api.github.com/users/laurent22/received_events", "type": "User", "user_view_type": "public", "site_admin": false }, "created_at": "2026-02-15T09:38:44Z", "updated_at": "2026-02-15T09:38:44Z", "body": "Thanks for the submission.\r\n\r\nWhile this PR targets an existing issue, the proposed solution is not suitable for the project in its current form. Bringing it up to an acceptable standard would require significant redesign and guidance.\r\n\r\nFor future contributions, please ensure changes are well-aligned with the existing architecture and sufficiently tested.\r\n\r\nPlease do not open another PR for this issue.", "author_association": "OWNER", "reactions": { "url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3903997230/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 }, "performed_via_github_app": null } ] }