Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@ import { Text } from '@audius/harmony/src/components/text'
import { Link } from 'react-router'

const messages = {
heading: 'This Track Isn’t Available',
description: 'This track can no longer be streamed on Audius.',
heading: 'Whoops',
description: 'This is not the page you’re looking for...',
buttonText: 'Take Me Back To The Music'
}

/**
* Server-rendered twin of the unavailable-track message. Kept separate, and on
* deep harmony imports, so the SSR worker bundle doesn't pull in the client
* barrels - matching the other Server* page components.
* Server-rendered twin of NotFoundPage. Kept separate, and on deep harmony
* imports, so the SSR worker bundle doesn't pull in the client barrels -
* matching the other Server* page components. The Lottie animation and tiled
* background from the client page are deliberately left out: they'd pull a
* large animation payload into the worker bundle for a page the client
* replaces on hydration anyway.
*/
export const ServerUnavailableTrack = () => {
export const ServerNotFound = () => {
return (
<Flex
w='100%'
Expand Down
18 changes: 10 additions & 8 deletions packages/web/src/pages/track-page/components/desktop/TrackPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import { EmptyStatBanner } from 'components/stat-banner/StatBanner'
import { GiantTrackTile } from 'components/track/GiantTrackTile'
import DeletedPage from 'pages/deleted-page/DeletedPage'
import { getTrackDefaults, emptyStringGuard } from 'pages/track-page/utils'
import { UnavailableTrackPage } from 'pages/unavailable-track-page/UnavailableTrackPage'
import { getTrackPageContext } from 'ssr/metaTags'
import { parseTrackRoute } from 'utils/route/trackRouteParser'

Expand Down Expand Up @@ -79,12 +78,15 @@ const TrackPage = () => {
!!currentTrack &&
currentTrack.track_id === track.track_id

// Simple error handling
// Simple error handling. A track whose owner is no longer active - a self
// deactivation, or an account delisted by the trusted notifier - is treated
// the same as one that doesn't exist: the API already 404s its stream so it
// can't be told apart from a missing track, and the page shouldn't either.
useEffect(() => {
if (status === 'error') {
if (status === 'error' || isTrackUnavailable(track)) {
navigate(NOT_FOUND_PAGE)
}
}, [status, navigate])
}, [status, track, navigate])

// Simple cleanup
useEffect(() => {
Expand Down Expand Up @@ -263,11 +265,11 @@ const TrackPage = () => {
)
}

// The API reports tracks whose owner is no longer active as non-streamable.
// Honor that instead of rendering a playable track page. Checked after the
// deleted case above, which has its own more specific treatment.
// The redirect above runs in an effect, which fires after the first paint.
// Render nothing until it lands so the track's title and artwork never reach
// the screen, even for a frame.
if (isTrackUnavailable(track)) {
return <UnavailableTrackPage />
return null
}

const renderGiantTrackTile = () => (
Expand Down
18 changes: 10 additions & 8 deletions packages/web/src/pages/track-page/components/mobile/TrackPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ import NavContext, {
} from 'components/nav/mobile/NavContext'
import DeletedPage from 'pages/deleted-page/DeletedPage'
import { getTrackDefaults } from 'pages/track-page/utils'
import { UnavailableTrackPage } from 'pages/unavailable-track-page/UnavailableTrackPage'
import { getTrackPageContext } from 'ssr/metaTags'
import { parseTrackRoute } from 'utils/route/trackRouteParser'

Expand Down Expand Up @@ -85,12 +84,15 @@ const TrackPage = () => {
!!currentTrack &&
currentTrack.track_id === track.track_id

// Simple error handling
// Simple error handling. A track whose owner is no longer active - a self
// deactivation, or an account delisted by the trusted notifier - is treated
// the same as one that doesn't exist: the API already 404s its stream so it
// can't be told apart from a missing track, and the page shouldn't either.
useEffect(() => {
if (status === 'error') {
if (status === 'error' || isTrackUnavailable(track)) {
navigate(NOT_FOUND_PAGE)
}
}, [status, navigate])
}, [status, track, navigate])
const { setLeft, setCenter, setRight } = useContext(NavContext)!
useEffect(() => {
setLeft(LeftPreset.BACK)
Expand Down Expand Up @@ -277,11 +279,11 @@ const TrackPage = () => {
)
}

// The API reports tracks whose owner is no longer active as non-streamable.
// Honor that instead of rendering a playable track page. Checked after the
// deleted case above, which has its own more specific treatment.
// The redirect above runs in an effect, which fires after the first paint.
// Render nothing until it lands so the track's title and artwork never reach
// the screen, even for a frame.
if (isTrackUnavailable(track)) {
return <UnavailableTrackPage />
return null
}

return (
Expand Down

This file was deleted.

This file was deleted.

21 changes: 11 additions & 10 deletions packages/web/src/ssr/metaTags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,16 +163,17 @@ export const getDefaultContext = () => {
}

/**
* Meta tag context for a track the API reports as non-streamable (its owner is
* no longer active). Deliberately generic - none of the track's or the
* account's title, artwork, or canonical URL - and always paired with
* `noIndex` at the call site so these pages stay out of search results and
* social unfurls.
*/
export const getUnavailableTrackContext = () => ({
title: 'Track Unavailable',
description: 'This track can no longer be streamed on Audius.',
ogDescription: 'This track can no longer be streamed on Audius.',
* Meta tag context for a page served as a 404. Used for tracks the API reports
* as non-streamable (their owner is no longer active), which are rendered as
* plain not-found pages so they can't be told apart from a track that never
* existed. Carries none of the track's or the account's title, artwork, or
* canonical URL, and is always paired with `noIndex` at the call site so these
* pages stay out of search results and social unfurls.
*/
export const getNotFoundContext = () => ({
title: 'Not Found',
description: '404 - Page not found',
ogDescription: '404 - Page not found',
image: DEFAULT_IMAGE_URL,
imageAlt: 'The Audius Platform',
thumbnail: true
Expand Down
14 changes: 8 additions & 6 deletions packages/web/src/ssr/track/+onRenderHtml.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ import type { PageContextServer } from 'vike/types'

import { ServerWebPlayer } from 'app/web-player/ServerWebPlayer'
import { MetaTags } from 'components/meta-tags/MetaTags'
import { ServerNotFound } from 'pages/not-found-page/ServerNotFound'
import { DesktopServerTrackPage } from 'pages/track-page/DesktopServerTrackPage'
import { MobileServerTrackPage } from 'pages/track-page/MobileServerTrackPage'
import { ServerUnavailableTrack } from 'pages/unavailable-track-page/ServerUnavailableTrack'
import {
canEmbed,
DEFAULT_IMAGE_URL,
getAppUrl,
getEmbedUrl,
getTrackPageContext,
getUnavailableTrackContext,
getNotFoundContext,
getWebUrl,
isDiscord
} from 'ssr/metaTags'
Expand Down Expand Up @@ -53,8 +53,10 @@ export default function render(pageContext: TrackPageContext) {
const isMobile = isMobileUserAgent(userAgent)

// The API reports tracks whose owner is no longer active as non-streamable.
// Serve none of their metadata: no title, artwork, embed player, or index.
// Explicit `=== false` because the field is absent on older API responses.
// Serve none of their metadata: no title, artwork, embed player, or index -
// the page is rendered as a plain 404, matching what the client navigates to
// and what the API returns for these tracks. Explicit `=== false` because the
// field is absent on older API responses.
const isUnavailable = track?.is_streamable === false

// Check if this request can show an embed player (Twitter/Discord bots)
Expand All @@ -71,7 +73,7 @@ export default function render(pageContext: TrackPageContext) {
// Build meta tags - use comment-specific if we have comment data
let seoMetadata
if (isUnavailable) {
seoMetadata = getUnavailableTrackContext()
seoMetadata = getNotFoundContext()
} else if (commentData) {
const trackName = commentData.track.title
const artistName = commentData.track.user.name
Expand Down Expand Up @@ -135,7 +137,7 @@ export default function render(pageContext: TrackPageContext) {
noIndex={isUnavailable}
/>
{isUnavailable ? (
<ServerUnavailableTrack />
<ServerNotFound />
) : isMobile ? (
<MobileServerTrackPage track={track} user={user} />
) : (
Expand Down
Loading