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

ProviderRecognized URL shapesAvailable presentation
YouTubeyoutube.com/watch?v=VIDEO_ID, youtu.be/VIDEO_ID, youtube.com/shorts/VIDEO_IDLink card or expandable inline player; portrait sizing for Shorts
Instagraminstagram.com/p/SHORTCODE/, instagram.com/reel/SHORTCODE/Link card or cached thumbnail and title preview
Spotifyopen.spotify.com/track/ID, /album/ID, /playlist/IDLink card or expandable player; provider may offer previews
TikToktiktok.com/@USER/video/IDLink card or expandable portrait player
SoundCloudsoundcloud.com/USER/TRACK, /USER/sets/PLAYLISTLink card or expandable track/collection player
BandcampARTIST.bandcamp.com/track/SLUG, /album/SLUGLink 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.

CompletePriorityProviderContent to scope
[x]HigherSoundCloudDirect public tracks and sets implemented
[x]HigherTikTokDirect video links implemented; shared redirect links deferred
[x]HigherSpotifyDirect tracks, albums, and playlists implemented
[x]HigherBandcampDirect artist-subdomain tracks and albums implemented
[ ]LowerX/TwitterIndividual posts
[ ]LowerFacebookPosts and videos
[ ]LowerVimeoVideos
[ ]LowerTwitchChannels, 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:

bash
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:

bash
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.

RankURL typeRepresentative shapesCurrent embed support
1YouTube videos and shared video linksyoutube.com/watch?v=ID, youtu.be/IDSupported; start time and playlist context are not passed into the player
2Instagram reels and postsinstagram.com/reel/ID/, instagram.com/p/ID/Linked preview or plain card, not inline playback
3Spotify songs, albums, and playlistsopen.spotify.com/track/ID, /album/ID, /playlist/IDSupported: link card or click-to-load player
4TikTok clipstiktok.com/@USER/video/IDSupported for direct video links; share redirects deferred
5YouTube Shortsyoutube.com/shorts/IDSupported: portrait click-to-load player
6SoundCloud tracks and setssoundcloud.com/USER/SLUG, soundcloud.com/USER/sets/SLUGSupported: link card or click-to-load player
7Articles, lyrics, and reference pagesNews articles, interviews, Genius song pages, Wikipedia articlesUnsupported; general link previews are a separate candidate
8Event, ticket, and venue pagesEventbrite events, venue calendars, club event pagesUnsupported as media embeds; separate from structured event fields
9Artist profiles and release landing pagesYouTube channels, Instagram profiles, artist websites, Linktree pagesUnsupported; a profile is not an individual video or post
10Bandcamp releasesARTIST.bandcamp.com/album/SLUG, ARTIST.bandcamp.com/track/SLUGSupported: link card or click-to-load player after ID discovery
11X/Twitter posts and Reddit discussionsx.com/USER/status/ID, reddit.com/r/COMMUNITY/comments/ID/...Unsupported; Reddit is an additional candidate, outside the existing provider backlog
12Other music and podcast servicesApple Music releases, podcast episode pages, Mixcloud mixesUnsupported; additional candidates to scope only if demand appears
13Shared files and direct mediaGoogle Drive or Dropbox links; direct .jpg, .png, .mp3, .mp4 URLsUnsupported as URL embeds; owned image uploads are a separate feature
14Facebook posts, videos, and eventsFacebook post, reel, video, and event linksUnsupported
15Livestreams and less common video linksyoutube.com/live/ID, Twitch channels/clips, vimeo.com/IDUnsupported; 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.

Replace estimates with observed frequency