Skip to content

Commit 7555cd2

Browse files
committed
fix stem uploads by adding a new publishStems to SDK
1 parent 3ed452b commit 7555cd2

File tree

6 files changed

+164
-60
lines changed

6 files changed

+164
-60
lines changed

packages/common/src/api/tan-query/upload/usePublishStems.ts

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
import { HashId, Id, type UploadResponse } from '@audius/sdk'
2-
import { mutationOptions, useMutation } from '@tanstack/react-query'
2+
import {
3+
mutationOptions,
4+
useMutation,
5+
useQueryClient
6+
} from '@tanstack/react-query'
37

4-
import { trackMetadataForUploadToSdk } from '~/adapters'
5-
import { StemCategory, Name } from '~/models'
8+
import {
9+
StemCategory,
10+
Name,
11+
type StemUpload,
12+
type TrackMetadata
13+
} from '~/models'
614
import { ProgressStatus, uploadActions } from '~/store'
7-
import type { TrackMetadataForUpload } from '~/store'
815

16+
import { getStemsQueryKey } from '../tracks/useStems'
917
import { useCurrentUserId } from '../users/account/useCurrentUserId'
1018
import { useQueryContext, type QueryContextType } from '../utils'
1119

@@ -21,9 +29,11 @@ type PublishStemsContext = Pick<
2129
type PublishStemsParams = {
2230
clientId: string
2331
parentTrackId: number
24-
metadata: TrackMetadataForUpload
25-
imageUploadResponse: UploadResponse
26-
stemsUploadResponses: UploadResponse[]
32+
parentMetadata: Omit<TrackMetadata, 'artwork' | 'track_id'>
33+
stems: {
34+
metadata: StemUpload
35+
audioUploadResponse: UploadResponse
36+
}[]
2737
}
2838

2939
export const publishStems = async (
@@ -43,26 +53,16 @@ export const publishStems = async (
4353

4454
const sdk = await audiusSdk()
4555
return await Promise.all(
46-
(params.metadata.stems ?? []).map(async (stem, index) => {
56+
(params.stems ?? []).map(async (stem, index) => {
4757
try {
48-
const stemUploadResponse = params.stemsUploadResponses?.[index]
49-
if (!stemUploadResponse) {
50-
throw new Error(`No upload response found for stem ${index}`)
51-
}
5258
const metadata = {
53-
...stem.metadata,
54-
genre: params.metadata.genre,
55-
is_downloadable: true,
56-
stem_of: {
57-
category: stem.category ?? StemCategory.OTHER,
58-
parent_track_id: params.parentTrackId
59-
}
59+
category: stem.metadata.category ?? StemCategory.OTHER,
60+
parentTrackId: Id.parse(params.parentTrackId)
6061
}
61-
const stemRes = await sdk.tracks.publishTrack({
62+
const stemRes = await sdk.tracks.publishStem({
6263
userId: Id.parse(userId),
63-
metadata: trackMetadataForUploadToSdk(metadata),
64-
audioUploadResponse: stemUploadResponse,
65-
imageUploadResponse: params.imageUploadResponse
64+
metadata,
65+
audioUploadResponse: stem.audioUploadResponse
6666
})
6767
dispatch(
6868
updateProgress({
@@ -77,7 +77,7 @@ export const publishStems = async (
7777
eventName: Name.STEM_COMPLETE_UPLOAD,
7878
id: HashId.parse(stemRes.trackId),
7979
parent_track_id: params.parentTrackId,
80-
category: stem.category ?? StemCategory.OTHER
80+
category: stem.metadata.category ?? StemCategory.OTHER
8181
})
8282
)
8383
return { trackId: stemRes.trackId, error: null }
@@ -109,10 +109,16 @@ export const usePublishStems = (
109109
}
110110
) => {
111111
const context = useQueryContext()
112+
const queryClient = useQueryClient()
112113
const { data: userId } = useCurrentUserId()
113114

114115
return useMutation({
115116
...options,
116-
...getPublishStemsOptions({ ...context, userId: userId! })
117+
...getPublishStemsOptions({ ...context, userId: userId! }),
118+
onSuccess: (_, params) => {
119+
queryClient.invalidateQueries({
120+
queryKey: getStemsQueryKey(params.parentTrackId)
121+
})
122+
}
117123
})
118124
}

packages/common/src/api/tan-query/upload/usePublishTracks.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,12 @@ export const publishTracks = async (
136136
publishParentTrack(),
137137
publishStems(context, {
138138
clientId: param.clientId,
139-
metadata: param.metadata,
140-
imageUploadResponse: param.imageUploadResponse,
141-
stemsUploadResponses: param.stemsUploadResponses ?? [],
139+
parentMetadata: param.metadata,
140+
stems:
141+
param.metadata.stems?.map((stem, index) => ({
142+
metadata: stem,
143+
audioUploadResponse: param.stemsUploadResponses?.[index]!
144+
})) ?? [],
142145
parentTrackId: trackId
143146
})
144147
])

packages/discovery-provider/src/tasks/entity_manager/entities/track.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ def populate_track_record_metadata(track_record: Track, track_metadata, handle,
287287
track_record.remix_of = track_metadata["remix_of"]
288288

289289
elif key == "route_id":
290-
if "title" in track_metadata:
290+
if "title" in track_metadata and track_metadata["title"] is not None:
291291
track_record.route_id = helpers.create_track_route_id(
292292
track_metadata["title"], handle
293293
)

packages/sdk/src/sdk/api/tracks/TracksApi.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ import {
5858
ShareTrackSchema,
5959
ShareTrackRequest,
6060
type PublishTrackRequest,
61-
PublishTrackSchema
61+
PublishTrackSchema,
62+
type PublishStemRequest,
63+
PublishStemSchema
6264
} from './types'
6365

6466
// Extend that new class
@@ -231,6 +233,53 @@ export class TracksApi extends GeneratedTracksApi {
231233
)
232234
}
233235

236+
/** @hidden
237+
* Publishes a stem that was uploaded using storage node uploadFileV2 uploads.
238+
*/
239+
async publishStem(
240+
params: PublishStemRequest,
241+
advancedOptions?: AdvancedOptions
242+
) {
243+
const {
244+
userId,
245+
metadata: parsedMetadata,
246+
audioUploadResponse
247+
} = await parseParams('publishStem', PublishStemSchema)(params)
248+
249+
const trackMetadata = {
250+
title: audioUploadResponse.orig_filename || 'Untitled Stem',
251+
isStreamGated: false,
252+
streamConditions: undefined,
253+
isUnlisted: false,
254+
fieldVisibility: {
255+
genre: false,
256+
mood: false,
257+
tags: false,
258+
share: false,
259+
playCount: false
260+
},
261+
isDownloadable: true,
262+
stemOf: parsedMetadata
263+
}
264+
265+
const metadata = this.trackUploadHelper.transformTrackUploadMetadata(
266+
trackMetadata,
267+
userId
268+
)
269+
270+
const populatedMetadata =
271+
this.trackUploadHelper.populateTrackMetadataWithUploadResponse(
272+
metadata,
273+
audioUploadResponse
274+
)
275+
276+
return this.writeTrackToChain(
277+
params.userId,
278+
populatedMetadata,
279+
advancedOptions
280+
)
281+
}
282+
234283
/** @hidden
235284
* Write track upload to chain
236285
*/

packages/sdk/src/sdk/api/tracks/types.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ export const USDCPurchaseConditions = z
8686
})
8787
.strict()
8888

89+
export const UploadStemMetadataSchema = z.object({
90+
category: z
91+
.enum(Object.values(StemCategory) as [StemCategory, ...StemCategory[]])
92+
.default(StemCategory.OTHER),
93+
parentTrackId: HashId
94+
})
95+
8996
export const UploadTrackMetadataSchema = z.object({
9097
trackId: z.optional(HashId),
9198
aiAttributionUserId: z.optional(HashId),
@@ -152,14 +159,7 @@ export const UploadTrackMetadataSchema = z.object({
152159
})
153160
.strict()
154161
),
155-
stemOf: z.optional(
156-
z.object({
157-
category: z
158-
.enum(Object.values(StemCategory) as [StemCategory, ...StemCategory[]])
159-
.default(StemCategory.OTHER),
160-
parentTrackId: HashId
161-
})
162-
),
162+
stemOf: z.optional(UploadStemMetadataSchema.strict()),
163163
tags: z.optional(z.string()),
164164
title: z.string({
165165
required_error: messages.titleRequiredError
@@ -425,9 +425,18 @@ export const PublishTrackSchema = z
425425
userId: HashId,
426426
metadata: UploadTrackMetadataSchema.strict(),
427427
audioUploadResponse: UploadResponseSchema,
428-
imageUploadResponse: UploadResponseSchema,
429-
stemsUploadResponses: z.array(UploadResponseSchema).optional()
428+
imageUploadResponse: UploadResponseSchema
430429
})
431430
.strict()
432431

433432
export type PublishTrackRequest = z.input<typeof PublishTrackSchema>
433+
434+
export const PublishStemSchema = z
435+
.object({
436+
userId: HashId,
437+
metadata: UploadStemMetadataSchema.strict(),
438+
audioUploadResponse: UploadResponseSchema
439+
})
440+
.strict()
441+
442+
export type PublishStemRequest = z.input<typeof PublishStemSchema>

packages/web/src/store/application/ui/stemsUpload/sagas.ts

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import { getStemsQueryKey } from '@audius/common/api'
1+
import {
2+
getStemsQueryKey,
3+
queryCurrentUserId,
4+
queryTrack
5+
} from '@audius/common/api'
26
import { Name, StemCategory } from '@audius/common/models'
7+
import { publishStems } from '@audius/common/src/api/tan-query/upload/usePublishStems'
38
import { getContext, stemsUploadActions } from '@audius/common/store'
49
import { takeEvery, put, call } from 'typed-redux-saga'
510

611
import { make } from 'common/store/analytics/actions'
7-
import { handleUploads } from 'common/store/upload/sagas'
8-
import { createStemMetadata } from 'pages/upload-page/store/utils/stems'
912

1013
const { startStemUploads, stemUploadsSucceeded } = stemsUploadActions
1114

@@ -14,28 +17,62 @@ function* watchUploadStems() {
1417
startStemUploads.type,
1518
function* (action: ReturnType<typeof startStemUploads>) {
1619
const { uploads, parentId, batchUID } = action.payload
17-
const stemTracks = uploads.map((u) => {
18-
const metadata = createStemMetadata({
19-
parentTrackId: parentId,
20-
track: u.metadata,
21-
stemCategory: u.category ?? StemCategory.OTHER
20+
21+
const parentTrack = yield* call(queryTrack, parentId)
22+
if (!parentTrack) {
23+
throw new Error(`Parent track with ID ${parentId} not found`)
24+
}
25+
26+
const audiusSdk = yield* getContext('audiusSdk')
27+
const dispatch = yield* getContext('dispatch')
28+
const reportToSentry = yield* getContext('reportToSentry')
29+
const analytics = yield* getContext('analytics')
30+
const userId = yield* call(queryCurrentUserId)
31+
if (!userId) {
32+
throw new Error('No user ID found for stem upload')
33+
}
34+
35+
const results = yield* call(async () => {
36+
const sdk = await audiusSdk()
37+
const uploadHandles = uploads.map((stem, index) => {
38+
return sdk.tracks.uploadTrackFiles({
39+
audioFile: stem.file
40+
})
2241
})
23-
return {
24-
...u,
25-
metadata
26-
}
27-
})
28-
const trackIds = yield* call(handleUploads, {
29-
tracks: stemTracks,
30-
kind: 'stems'
42+
const uploadResponses = await Promise.all(
43+
uploadHandles.map((handle) => handle.start())
44+
)
45+
const res = await publishStems(
46+
{
47+
audiusSdk,
48+
dispatch,
49+
userId,
50+
reportToSentry,
51+
analytics
52+
},
53+
{
54+
clientId: batchUID,
55+
parentTrackId: parentId,
56+
parentMetadata: parentTrack,
57+
stems: uploadResponses.map((s, i) => ({
58+
metadata: uploads[i],
59+
audioUploadResponse: s.audioUploadResponse!
60+
}))
61+
}
62+
)
63+
return res
3164
})
3265

3366
yield* put(stemUploadsSucceeded({ parentId, batchUID }))
3467

35-
if (trackIds) {
36-
for (let i = 0; i < trackIds.length; i += 1) {
37-
const trackId = trackIds[i]
38-
const category = stemTracks[i].metadata.stem_of?.category
68+
if (results) {
69+
for (let i = 0; i < results.length; i += 1) {
70+
const { trackId, error } = results[i]
71+
if (error) {
72+
console.error(`Error uploading stem ${i}:`, error)
73+
continue
74+
}
75+
const category = uploads[i].category ?? StemCategory.OTHER
3976
const recordEvent = make(Name.STEM_COMPLETE_UPLOAD, {
4077
id: trackId,
4178
parent_track_id: parentId,

0 commit comments

Comments
 (0)