Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

Commit

Permalink
[PAY-1590] Hook up content previews for USDC content (#3968)
Browse files Browse the repository at this point in the history
  • Loading branch information
schottra authored Aug 30, 2023
1 parent 0ce85a2 commit 83b7ae5
Show file tree
Hide file tree
Showing 15 changed files with 121 additions and 36 deletions.
1 change: 1 addition & 0 deletions packages/common/src/models/Analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,7 @@ export enum PlaybackSource {
type PlaybackPlay = {
eventName: Name.PLAYBACK_PLAY
id?: string
isPreview?: boolean
source: PlaybackSource
}
type PlaybackPause = {
Expand Down
3 changes: 2 additions & 1 deletion packages/common/src/models/Track.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ export type TrackMetadata = {
category: StemCategory
}
remix_of: Nullable<RemixOf>
preview_start_seconds?: number
preview_cid?: Nullable<CID>
preview_start_seconds?: Nullable<number>

// Added fields
dateListened?: string
Expand Down
5 changes: 3 additions & 2 deletions packages/common/src/store/lineup/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,11 @@ export class LineupActions {
}
}

play(uid?: UID) {
play(uid?: UID, { isPreview = false }: { isPreview?: boolean } = {}) {
return {
type: addPrefix(this.prefix, PLAY),
uid
uid,
isPreview
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/common/src/store/player/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const getTrackId = (state: CommonState) => state.player.trackId
export const getCollectible = (state: CommonState) => state.player.collectible

export const getPlaying = (state: CommonState) => state.player.playing
export const getPreviewing = (state: CommonState) => state.player.previewing
export const getPaused = (state: CommonState) => !state.player.playing
export const getCounter = (state: CommonState) => state.player.counter
export const getBuffering = (state: CommonState) => state.player.buffering
Expand Down
7 changes: 7 additions & 0 deletions packages/common/src/store/player/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ export type PlayerState = {
// object to allow components to subscribe to changes.
playing: boolean

// Indicates that current playback session is a track preview
previewing: boolean

// Keep 'buffering' in the store separately from the audio
// object to allow components to subscribe to changes.
buffering: boolean
Expand All @@ -42,6 +45,7 @@ export const initialState: PlayerState = {
collectible: null,

playing: false,
previewing: false,
buffering: false,
counter: 0,
playbackRate: '1x',
Expand All @@ -52,10 +56,12 @@ export const initialState: PlayerState = {
type PlayPayload = Maybe<{
uid?: Nullable<UID>
trackId?: ID
isPreview?: boolean
onEnd?: (...args: any) => any
}>

type PlaySucceededPayload = {
isPreview?: boolean
uid?: Nullable<UID>
trackId?: ID
}
Expand Down Expand Up @@ -122,6 +128,7 @@ const slice = createSlice({
state.trackId = trackId || state.trackId
state.collectible = null
state.counter = state.counter + 1
state.previewing = !!action.payload.isPreview
},
playCollectible: (
_state,
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/store/queue/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const initialState: State = {

type PlayPayload = {
uid?: Nullable<UID>
isPreview?: boolean
trackId?: Nullable<ID>
collectible?: Collectible
source?: Nullable<string>
Expand Down
12 changes: 11 additions & 1 deletion packages/web/src/common/store/lineup/sagas.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import {
queueSelectors,
getContext,
FeatureFlags,
isPremiumContentUSDCPurchaseGated
isPremiumContentUSDCPurchaseGated,
doesUserHaveTrackAccess
} from '@audius/common'
import {
all,
Expand Down Expand Up @@ -350,6 +351,14 @@ function* updateQueueLineup(lineupPrefix, source, lineupEntries) {
function* play(lineupActions, lineupSelector, prefix, action) {
const lineup = yield select(lineupSelector)
const requestedPlayTrack = yield select(getTrack, { uid: action.uid })
let isPreview = !!action.isPreview

// If preview isn't forced, check for track acccess and switch to preview
// if the user doesn't have access but the track is previewable
if (!isPreview && requestedPlayTrack.is_premium) {
const hasAccess = yield call(doesUserHaveTrackAccess, requestedPlayTrack)
isPreview = !hasAccess && !!requestedPlayTrack.preview_cid
}

if (action.uid) {
const source = yield select(getSource)
Expand All @@ -370,6 +379,7 @@ function* play(lineupActions, lineupSelector, prefix, action) {
yield put(
queueActions.play({
uid: action.uid,
isPreview,
trackId: requestedPlayTrack && requestedPlayTrack.track_id,
source: prefix
})
Expand Down
24 changes: 19 additions & 5 deletions packages/web/src/common/store/player/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,12 @@ const { getIsReachable } = reachabilitySelectors
const PLAYER_SUBSCRIBER_NAME = 'PLAYER'
const RECORD_LISTEN_SECONDS = 1
const RECORD_LISTEN_INTERVAL = 1000
const PREVIEW_LENGTH_SECONDS = 30

export function* watchPlay() {
const getFeatureEnabled = yield* getContext('getFeatureEnabled')
yield* takeLatest(play.type, function* (action: ReturnType<typeof play>) {
const { uid, trackId, onEnd } = action.payload ?? {}
const { uid, trackId, isPreview, onEnd } = action.payload ?? {}

const audioPlayer = yield* getContext('audioPlayer')
const isNativeMobile = yield getContext('isNativeMobile')
Expand Down Expand Up @@ -113,6 +114,19 @@ export function* watchPlay() {
audiusBackendInstance,
premiumContentSignature
})

let trackDuration = track.duration

if (isPreview) {
// Add preview query string and calculate preview duration for use later
const previewStartSeconds = track.preview_start_seconds || 0
queryParams.preview = true
trackDuration = Math.min(
track.duration - previewStartSeconds,
PREVIEW_LENGTH_SECONDS
)
}

const mp3Url = apiClient.makeUrl(
`/tracks/${encodedTrackId}/stream`,
queryParams
Expand All @@ -124,7 +138,7 @@ export function* watchPlay() {
const currentUserId = yield* select(getUserId)
const endChannel = eventChannel((emitter) => {
audioPlayer.load(
track.duration ||
trackDuration ||
track.track_segments.reduce(
(duration, segment) => duration + parseFloat(segment.duration),
0
Expand Down Expand Up @@ -182,7 +196,7 @@ export function* watchPlay() {
)
} else {
audioPlayer.play()
yield* put(playSucceeded({ uid, trackId }))
yield* put(playSucceeded({ uid, trackId, isPreview }))
yield* put(seek({ seconds: trackPlaybackInfo.playbackPosition }))
return
}
Expand All @@ -196,9 +210,9 @@ export function* watchPlay() {
// Play if user has access to track.
const track = yield* select(getTrack, { id: trackId })
const doesUserHaveAccess = yield* call(doesUserHaveTrackAccess, track)
if (doesUserHaveAccess) {
if (doesUserHaveAccess || isPreview) {
audioPlayer.play()
yield* put(playSucceeded({ uid, trackId }))
yield* put(playSucceeded({ uid, trackId, isPreview }))
} else {
yield* put(queueActions.next({}))
}
Expand Down
17 changes: 13 additions & 4 deletions packages/web/src/common/store/queue/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ const {
getUndershot
} = queueSelectors

const { getTrackId: getPlayerTrackId, getUid: getPlayerUid } = playerSelectors
const {
getTrackId: getPlayerTrackId,
getUid: getPlayerUid,
getPreviewing: getPlayerPreviewing
} = playerSelectors

const { add, clear, next, pause, play, queueAutoplay, previous, remove } =
queueActions
Expand Down Expand Up @@ -144,11 +148,13 @@ function* handleQueueAutoplay({
*/
export function* watchPlay() {
yield* takeLatest(play.type, function* (action: ReturnType<typeof play>) {
const { uid, trackId, collectible } = action.payload
const { uid, trackId, isPreview, collectible } = action.payload

// Play a specific uid
const playerUid = yield* select(getPlayerUid)
const playerTrackId = yield* select(getPlayerTrackId)
const playerIsPreviewing = yield* select(getPlayerPreviewing)

if (uid || trackId) {
const playActionTrack = yield* select(
getTrack,
Expand Down Expand Up @@ -181,13 +187,16 @@ export function* watchPlay() {
const noTrackPlaying = !playerTrackId
const trackIsDifferent = playerTrackId !== playActionTrack.track_id
const trackIsSameButDifferentUid =
playerTrackId === playActionTrack.track_id && uid !== playerUid
playerTrackId === playActionTrack.track_id &&
(uid !== playerUid || !!isPreview !== playerIsPreviewing)
if (noTrackPlaying || trackIsDifferent || trackIsSameButDifferentUid) {
yield* put(
playerActions.play({
uid,
isPreview,
trackId: playActionTrack.track_id,
onEnd: next
// Don't auto-advance after previews
onEnd: isPreview ? playerActions.stop : next
})
)
} else {
Expand Down
13 changes: 6 additions & 7 deletions packages/web/src/components/track/GiantTrackTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,13 @@ export type GiantTrackTileProps = {
onMakePublic: (trackId: ID) => void
onFollow: () => void
onPlay: () => void
onPreview: () => void
onRepost: () => void
onSave: () => void
onShare: () => void
onUnfollow: () => void
playing: boolean
previewing: boolean
premiumConditions: Nullable<PremiumConditions>
released: string
repostCount: number
Expand Down Expand Up @@ -150,6 +152,7 @@ export const GiantTrackTile = ({
onFollow,
onMakePublic,
onPlay,
onPreview,
onSave,
onShare,
onRepost,
Expand All @@ -158,6 +161,7 @@ export const GiantTrackTile = ({
repostCount,
saveCount,
playing,
previewing,
premiumConditions,
tags,
trackId,
Expand All @@ -183,11 +187,6 @@ export const GiantTrackTile = ({
// Play button is conditionally hidden for USDC-gated tracks when the user does not have access
const showPlay = isUSDCPurchaseGated ? doesUserHaveAccess : true

// TODO: https://linear.app/audius/issue/PAY-1590/[webmobileweb]-add-support-for-playing-previews
const onPreview = useCallback(() => {
console.info('Preview Clicked')
}, [])

const renderCardTitle = (className: string) => {
return (
<CardTitle
Expand Down Expand Up @@ -531,14 +530,14 @@ export const GiantTrackTile = ({
{showPlay ? (
<PlayPauseButton
disabled={!doesUserHaveAccess}
playing={playing}
playing={playing && !previewing}
onPlay={onPlay}
trackId={trackId}
/>
) : null}
{showPreview ? (
<PlayPauseButton
playing={playing}
playing={playing && previewing}
onPlay={onPreview}
trackId={trackId}
isPreview
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ const ConnectedTrackTile = ({
const isTrackPlaying = isActive && isPlaying
const isOwner = handle === userHandle
const isArtistPick = showArtistPick && artist_pick_track_id === trackId
const hasPreview = !!track?.preview_cid

const { isUserAccessTBD, doesUserHaveAccess } =
usePremiumContentAccess(trackWithFallback)
Expand Down Expand Up @@ -187,7 +188,7 @@ const ConnectedTrackTile = ({
showSkeleton: loading,
callback: () => setArtworkLoaded(true),
label: `${title} by ${name}`,
doesUserHaveAccess
doesUserHaveAccess: doesUserHaveAccess || hasPreview
}
return <TrackArtwork {...artworkProps} />
}
Expand Down Expand Up @@ -317,7 +318,7 @@ const ConnectedTrackTile = ({

// Show the locked content modal if gated track and user does not have access.
// Also skip toggle play in this case.
if (trackId && !doesUserHaveAccess) {
if (trackId && !doesUserHaveAccess && !hasPreview) {
dispatch(setLockedContentId({ id: trackId }))
setLockedContentVisibility(true)
return
Expand All @@ -327,6 +328,7 @@ const ConnectedTrackTile = ({
},
[
togglePlay,
hasPreview,
uid,
trackId,
doesUserHaveAccess,
Expand Down
Loading

0 comments on commit 83b7ae5

Please sign in to comment.