diff --git a/packages/embed/src/components/app.jsx b/packages/embed/src/components/app.jsx index ea82d64cc75..d089c5cd0a0 100644 --- a/packages/embed/src/components/app.jsx +++ b/packages/embed/src/components/app.jsx @@ -141,6 +141,10 @@ const App = (props) => { const searchParams = useSearchParams() const [didError, setDidError] = useState(false) // General errors const [did404, setDid404] = useState(false) // 404s indicate content was deleted + // A track whose owner is no longer active - the artist deactivated their own + // account, or the account was delisted by the trusted notifier. Rendered with + // the same "not available" treatment as a 404, but with its own copy. + const [isUnavailable, setIsUnavailable] = useState(false) const [requestState, setRequestState] = useState(null) // Parsed request state const [isRetrying, setIsRetrying] = useState(false) // Currently retrying? @@ -188,10 +192,20 @@ const App = (props) => { if (!track) { setDid404(true) + setIsUnavailable(false) + setTracksResponse(null) + } else if (track.isStreamable === false) { + // The stream endpoint refuses these, so there is nothing to play - + // don't render the title, artist and artwork either. Checked with an + // explicit `=== false` because an absent field must not read as + // unavailable. + setDid404(true) + setIsUnavailable(true) setTracksResponse(null) } else { const events = await getEntityEvents(track.id, 'track') setDid404(false) + setIsUnavailable(false) setTracksResponse({ ...track, events }) recordOpen( decodeHashId(track.id), @@ -234,9 +248,11 @@ const App = (props) => { if (!collection) { setDid404(true) + setIsUnavailable(false) setCollectionsResponse(null) } else { setDid404(false) + setIsUnavailable(false) setCollectionsResponse(collection) recordOpen( decodeHashId(collection.id), @@ -273,6 +289,7 @@ const App = (props) => { setDidError(true) setShowLoadingAnimation(false) setDid404(false) + setIsUnavailable(false) setTracksResponse(null) setCollectionsResponse(null) } @@ -334,7 +351,12 @@ const App = (props) => { // Tiny variant renders its own deleted content if (did404) { - return + return ( + + ) } if (showLoadingAnimation && !isTiny) { diff --git a/packages/embed/src/components/deleted/DeletedContent.jsx b/packages/embed/src/components/deleted/DeletedContent.jsx index 5fc1277d75b..c7b5c0ef2b2 100644 --- a/packages/embed/src/components/deleted/DeletedContent.jsx +++ b/packages/embed/src/components/deleted/DeletedContent.jsx @@ -12,22 +12,36 @@ import DeletedContentTiny from './DeletedContentTiny' const messages = { mainLabel: 'This content was removed by the creator.', deleted: 'Deleted', + unavailable: 'This track can no longer be streamed on Audius.', subLabel1: 'Unlimited Uploads.', subLabel2: '320kbps Streaming.', subLabel3: '100% Free.', buttonLabel: 'Find more on' } -const DeletedContent = ({ flavor, isBlocked }) => { +const DeletedContent = ({ flavor, isBlocked, isUnavailable }) => { const onClickFindMore = () => { window.open(getCopyableLink(), '_blank') } + // `unavailable` says nothing about the account on purpose: the same flag + // covers a self deactivation and a delisted account, and we shouldn't tell + // listeners the creator removed the track when moderation suppressed it. + const label = isUnavailable + ? messages.unavailable + : isBlocked + ? messages.deleted + : messages.mainLabel + const isCard = flavor === PlayerFlavor.CARD const isTiny = flavor === PlayerFlavor.TINY if (isTiny) { return ( - + ) } @@ -41,9 +55,7 @@ const DeletedContent = ({ flavor, isBlocked }) => { }} /> )} -
- {isBlocked ? messages.deleted : messages.mainLabel} -
+
{label}
{isCard && (
{messages.subLabel1} diff --git a/packages/embed/src/components/deleted/DeletedContentTiny.jsx b/packages/embed/src/components/deleted/DeletedContentTiny.jsx index cbdf502ff0f..62076b30a96 100644 --- a/packages/embed/src/components/deleted/DeletedContentTiny.jsx +++ b/packages/embed/src/components/deleted/DeletedContentTiny.jsx @@ -5,10 +5,19 @@ import styles from './DeletedContentTiny.module.css' const messages = { deletedBy: 'Track Deleted By Artist', - deleted: 'Deleted' + deleted: 'Deleted', + unavailable: 'Track Unavailable' } -const DeletedContentTiny = ({ onClick, isBlocked }) => { +const DeletedContentTiny = ({ onClick, isBlocked, isUnavailable }) => { + // `unavailable` says nothing about the account on purpose: the same flag + // covers a self deactivation and a delisted account. + const label = isUnavailable + ? messages.unavailable + : isBlocked + ? messages.deleted + : messages.deletedBy + return (
{ className={styles.playButton} />
-
- {isBlocked ? messages.deleted : messages.deletedBy} -
+
{label}