Repository source: docs/plans/media_embed_support_checklist.md
Media embed support checklist
Use this checklist to verify existing embeds, close URL coverage gaps, and add providers. Checked implementation items describe repository support, not live deployment status. Unchecked expansion items are candidates to scope; no delivery dates are committed. Coverage and local verification updated October 15, 2026. Production flag settings still need an operator check.
Current support
| Provider | Recognized URL shapes | Available presentation |
|---|---|---|
| YouTube | youtube.com/watch?v=VIDEO_ID, youtu.be/VIDEO_ID, youtube.com/shorts/VIDEO_ID | Link card or expandable inline player; portrait sizing for Shorts |
instagram.com/p/SHORTCODE/, instagram.com/reel/SHORTCODE/ | Link card or cached thumbnail and title preview | |
| Spotify | open.spotify.com/track/ID, /album/ID, /playlist/ID | Link card or expandable player; provider may offer previews |
| TikTok | tiktok.com/@USER/video/ID | Link card or expandable portrait player |
| SoundCloud | soundcloud.com/USER/TRACK, /USER/sets/PLAYLIST | Link card or expandable track/collection player |
| Bandcamp | ARTIST.bandcamp.com/track/SLUG, /album/SLUG | Link card or expandable player after cached ID discovery |
Both HTTP and HTTPS are recognized. YouTube, Instagram, and TikTok accept optional
www.; SoundCloud also accepts www.. Spotify uses exactly open.spotify.com and short YouTube links use exactly
youtu.be. YouTube IDs must be 11 characters, Spotify IDs 22 alphanumeric
characters, and TikTok IDs 19 digits. Paths must match the listed content forms
completely; URL credentials and explicit ports are rejected. Instagram previews
link to the original post; they do not play Instagram video inline.
Redirecting share links, localized Spotify paths such as /intl-en/track/ID,
YouTube live/mobile/embed paths, and playlist-only YouTube links remain unsupported.
YouTube player URLs do not carry start times or playlist context. Source links preserve
meaningful parameters and fragments while removing known tracking parameters.
- [x] Detect the URL shapes above in post bodies and render provider cards.
- [x] Strip known tracking parameters from card links.
- [x] Load YouTube, Spotify, TikTok, SoundCloud, and Bandcamp players only when the reader expands them; keep source links visible outside collapsed players.
- [x] Use a sandboxed `youtube-nocookie.com` player with responsive 16:9 sizing.
- [x] Fetch and cache Instagram title and thumbnail metadata, with a plain-card fallback.
- [x] Fetch titles for untitled threads containing exactly one YouTube/Shorts or Instagram URL, preserving existing subjects. Spotify/TikTok/SoundCloud/Bandcamp retain ordinary body-derived titles.
- [x] Gate cards behind `FORUM_MEDIA_EMBEDS_ENABLED` and players/previews behind
`FORUM_MEDIA_EMBEDS_INLINE_PLAYER_ENABLED`; both default off, and the second requires the first.
- [x] Pass the expanded focused embed/title/presentation suites: 98 tests passed, 0 failed on October 15, 2026; current browser and full-suite results are recorded in the [music implementation summary](music_media_embeds/music_media_embeds_step4_implementation_summary.md). Earlier coverage remains in the [top-five summary](top_five_media_embeds/top_five_media_embeds_step4_implementation_summary.md).
Implementation: detector (source unavailable), renderer (source unavailable), and preview controller (source unavailable).
Music provider boundaries
SoundCloud accepts complete public track and set paths; user/slug segments use
ASCII letters, digits, underscores, and hyphens, with alphanumeric ends. Reserved
service routes and profile tabs are excluded. Bandcamp accepts a single artist
subdomain with /track/ or /album/; slugs use lowercase ASCII letters/digits
separated by single hyphens. Custom domains, service subdomains, encoded path
segments, profiles, redirecting shares, extra segments, and recognized private/tokenized
URLs are excluded. The exact conservative rules and examples are recorded in the
acceptance matrix.
Source links preserve meaningful public parameters/fragments; music player and
discovery targets use only canonical HTTPS content paths. Source timestamps do
not affect music playback. SoundCloud uses public permalinks without server
metadata lookup. Bandcamp discovers matching numeric IDs from og:video metadata
only on expansion; it never renders fetched HTML. Successful lookups cache for 24
hours and failures for one hour under state/cache/bandcamp_players/. Concurrent
lookups are deduplicated. Fetching validates/pins a public IPv4 destination,
verifies TLS, disables redirects, caps responses at 1 MiB, and applies a three-second
fetch deadline; system DNS uses the host resolver. Challenge pages, timeouts, and
unavailable content retain source access with an unavailable-player message when
discovery fails. Opening a player does not guarantee full playback or availability.
Bandcamp chooses its standard light or dark player background from the selected theme's panel brightness and uses the theme's source-link color. Low-contrast link colors fall back to readable black or white. Theme changes apply on the next expansion, leaving an open player uninterrupted; reopening with the same palette does not reload it. Release-ID caching remains independent of theme. Bandcamp's internal player surfaces use its own light/dark palette rather than arbitrary site background colors.
Both existing embed flags govern these providers; no new deployment flag or credentials are required. No lookup occurs during post rendering or with players disabled. Implementation and local acceptance evidence are recorded in the music implementation summary.
Verification and rollout
October 15 music acceptance confirmed SoundCloud track/set playback progress and Bandcamp album/track audio progress through real thread pages, including cold Bandcamp discovery. Controlled checks cover pending/failed lookups, late responses after closing a player, rejected foreign player destinations, and repeat expansion.
Local checks used headless Chrome 145 on Linux and all 16 theme modes at 360px and 1280px. Live players, Instagram previews, and Shorts title backfill passed through real forum pages. These checks close the earlier local layout and Instagram-fetching gaps; production acceptance remains separate.
Expand URL coverage for existing providers
These are proposed follow-ups based on current detection gaps, not previously committed roadmap items. Decide scope before implementing each group.
Add providers from the existing backlog
The provider backlog prioritizes the first group for the club's music content. SoundCloud, Bandcamp, Spotify, and direct TikTok videos are implemented within the boundaries above; the remaining providers and redirecting share links are unscheduled.
| Complete | Priority | Provider | Content to scope |
|---|---|---|---|
| [x] | Higher | SoundCloud | Direct public tracks and sets implemented |
| [x] | Higher | TikTok | Direct video links implemented; shared redirect links deferred |
| [x] | Higher | Spotify | Direct tracks, albums, and playlists implemented |
| [x] | Higher | Bandcamp | Direct artist-subdomain tracks and albums implemented |
| [ ] | Lower | X/Twitter | Individual posts |
| [ ] | Lower | Posts and videos | |
| [ ] | Lower | Vimeo | Videos |
| [ ] | Lower | Twitch | Channels, clips, and recorded videos |
For each selected provider, copy and complete this sequence in its implementation plan:
General URL cleanup
This is a separate backlog item in todo.txt (source unavailable), broader than embed detection.
Repeatable automated verification
Run from the repository root after changing embed behavior:
php tests/run.php MusicMediaEmbedTest BandcampPlayerResolverTest BandcampPlayerControllerTest MediaEmbedDetectorTest MediaEmbedRendererTest MediaEmbedPreviewCacheStoreTest MediaEmbedPreviewControllerTest MediaEmbedInlinePlayerScriptTest TemplateRendererMediaEmbedsScriptTest MediaEmbedBeaconTemplatesTest YoutubeOembedTitleFetcherTest InstagramPagePreviewFetcherTest ThreadTitleTest
For browser checks, install the declared dependency with npm install --ignore-scripts --package-lock=false, then run:
node tests/browser/media_embed_browser.mjs
node tests/browser/media_embed_browser.mjs --live
The default run uses controlled unavailable player documents; --live additionally
checks real playback (including SoundCloud and Bandcamp), cold Bandcamp discovery, Instagram previews, and Shorts title backfill. Tests use an
isolated temporary repository and remove it afterward. Set CHROMIUM_PATH if
Chrome is not installed at /opt/google/chrome/chrome. Use a distinct
FORUM_TEST_HISTORY_DB_PATH when running PHP suites concurrently.
Include new provider tests as support grows. Automated passes do not replace production acceptance.
Expected URL frequency
Working estimate for the MIT Rap Club's rap and hip-hop discussions, ordered from most to least likely. This is an audience-based planning hypothesis, not measured post traffic or a ranking of internet-wide popularity. Adjacent positions are uncertain. Likelihood also differs from implementation priority: SoundCloud may be especially valuable for members' own releases even if Spotify links occur more often. The existing club backlog provides the audience context.
The examples below are URL shapes, not an exhaustive acceptance specification;
ID, USER, and SLUG are placeholders. HTTPS is omitted for readability.
“Unsupported” means no automatic media embed in the current detector.
| Rank | URL type | Representative shapes | Current embed support |
|---|---|---|---|
| 1 | YouTube videos and shared video links | youtube.com/watch?v=ID, youtu.be/ID | Supported; start time and playlist context are not passed into the player |
| 2 | Instagram reels and posts | instagram.com/reel/ID/, instagram.com/p/ID/ | Linked preview or plain card, not inline playback |
| 3 | Spotify songs, albums, and playlists | open.spotify.com/track/ID, /album/ID, /playlist/ID | Supported: link card or click-to-load player |
| 4 | TikTok clips | tiktok.com/@USER/video/ID | Supported for direct video links; share redirects deferred |
| 5 | YouTube Shorts | youtube.com/shorts/ID | Supported: portrait click-to-load player |
| 6 | SoundCloud tracks and sets | soundcloud.com/USER/SLUG, soundcloud.com/USER/sets/SLUG | Supported: link card or click-to-load player |
| 7 | Articles, lyrics, and reference pages | News articles, interviews, Genius song pages, Wikipedia articles | Unsupported; general link previews are a separate candidate |
| 8 | Event, ticket, and venue pages | Eventbrite events, venue calendars, club event pages | Unsupported as media embeds; separate from structured event fields |
| 9 | Artist profiles and release landing pages | YouTube channels, Instagram profiles, artist websites, Linktree pages | Unsupported; a profile is not an individual video or post |
| 10 | Bandcamp releases | ARTIST.bandcamp.com/album/SLUG, ARTIST.bandcamp.com/track/SLUG | Supported: link card or click-to-load player after ID discovery |
| 11 | X/Twitter posts and Reddit discussions | x.com/USER/status/ID, reddit.com/r/COMMUNITY/comments/ID/... | Unsupported; Reddit is an additional candidate, outside the existing provider backlog |
| 12 | Other music and podcast services | Apple Music releases, podcast episode pages, Mixcloud mixes | Unsupported; additional candidates to scope only if demand appears |
| 13 | Shared files and direct media | Google Drive or Dropbox links; direct .jpg, .png, .mp3, .mp4 URLs | Unsupported as URL embeds; owned image uploads are a separate feature |
| 14 | Facebook posts, videos, and events | Facebook post, reel, video, and event links | Unsupported |
| 15 | Livestreams and less common video links | youtube.com/live/ID, Twitch channels/clips, vimeo.com/ID | Unsupported; a YouTube stream shared as a recognized watch URL is detected |
Provider references confirm content types and sharing mechanisms, not the frequency estimates: Spotify supports track, album, and playlist embeds (Spotify documentation); SoundCloud accepts track and playlist URLs (SoundCloud documentation); Bandcamp documents its official player creation flow (Bandcamp documentation); TikTok documents the individual-video URL shape (TikTok documentation).
URL variants to account for
These overlap the ranked types; count them as variants of their destination, not additional provider categories.