From 3d898382d9624d50d988c51ab5accbc713cbf770 Mon Sep 17 00:00:00 2001 From: Randy Schott <1815175+schottra@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:30:14 -0400 Subject: [PATCH 01/10] migrate getUserTracksByHandle to sdk --- packages/common/src/api/track.ts | 25 ++++++---- packages/common/src/api/types.ts | 6 +++ packages/common/src/api/user.ts | 28 ++++++----- .../audius-api-client/AudiusAPIClient.ts | 50 ------------------- packages/common/src/store/account/sagas.ts | 23 +++++---- .../lineups/tracks/retrieveUserTracks.ts | 30 ++++++----- 6 files changed, 70 insertions(+), 92 deletions(-) create mode 100644 packages/common/src/api/types.ts diff --git a/packages/common/src/api/track.ts b/packages/common/src/api/track.ts index 98414440a3d..7cd0250accd 100644 --- a/packages/common/src/api/track.ts +++ b/packages/common/src/api/track.ts @@ -1,8 +1,12 @@ +import { full } from '@audius/sdk' + import { transformAndCleanList, userTrackMetadataFromSDK } from '~/adapters' import { createApi } from '~/audius-query' import { ID, Id, Kind, OptionalId } from '~/models' import { Nullable } from '~/utils/typeUtils' +import { SDKRequest } from './types' + const trackApi = createApi({ reducerPath: 'trackApi', endpoints: { @@ -84,18 +88,21 @@ const trackApi = createApi({ getUserTracksByHandle: { fetch: async ( { - handle, currentUserId, - limit - }: { handle: string; currentUserId: Nullable; limit?: number }, - { apiClient } + filterTracks = 'public', + sort = 'date', + ...params + }: SDKRequest, + { audiusSdk } ) => { - return await apiClient.getUserTracksByHandle({ - handle, - currentUserId, - getUnlisted: false, - limit + const sdk = await audiusSdk() + const { data = [] } = await sdk.full.users.getTracksByUserHandle({ + ...params, + userId: OptionalId.parse(currentUserId), + sort, + filterTracks }) + return transformAndCleanList(data, userTrackMetadataFromSDK) }, options: { idListArgKey: 'ids', diff --git a/packages/common/src/api/types.ts b/packages/common/src/api/types.ts new file mode 100644 index 00000000000..c513b439054 --- /dev/null +++ b/packages/common/src/api/types.ts @@ -0,0 +1,6 @@ +import { ID } from '~/models' + +export type SDKRequest = Omit< + T, + 'encodedDataMessage' | 'encodedDataSignature' +> & { currentUserId?: ID | null } diff --git a/packages/common/src/api/user.ts b/packages/common/src/api/user.ts index 48bc66a3a31..f0bb7bf3656 100644 --- a/packages/common/src/api/user.ts +++ b/packages/common/src/api/user.ts @@ -1,5 +1,6 @@ import { full } from '@audius/sdk' +import { transformAndCleanList, userTrackMetadataFromSDK } from '~/adapters' import { userMetadataListFromSDK } from '~/adapters/user' import { createApi } from '~/audius-query' import { ID, Kind, OptionalId, StringUSDC } from '~/models' @@ -10,6 +11,7 @@ import { } from '~/models/USDCTransactions' import { Nullable } from '~/utils/typeUtils' +import { SDKRequest } from './types' import { Id } from './utils' type GetUSDCTransactionListArgs = { @@ -103,20 +105,22 @@ const userApi = createApi({ }, getTracksByUser: { fetch: async ( - { userId, currentUserId }: { userId: ID; currentUserId: Nullable }, - audiusQueryContext - ) => { - const { apiClient } = audiusQueryContext - const { handle } = await userApiFetch.getUserById( - { id: userId, currentUserId }, - audiusQueryContext - ) - const tracks = await apiClient.getUserTracksByHandle({ - handle, + { + id, currentUserId, - getUnlisted: userId === currentUserId + ...params + }: { + id: ID + } & SDKRequest, + { audiusSdk } + ) => { + const sdk = await audiusSdk() + const { data = [] } = await sdk.full.users.getTracksByUser({ + ...params, + id: Id.parse(id), + userId: OptionalId.parse(currentUserId) }) - return tracks + return transformAndCleanList(data, userTrackMetadataFromSDK) }, options: { kind: Kind.TRACKS, diff --git a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts index 798a8e4530c..adf4be8b11a 100644 --- a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts +++ b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts @@ -54,7 +54,6 @@ const FULL_ENDPOINT_MAP = { experiment ? `/playlists/trending/${experiment}` : '/playlists/trending', playlistUpdates: (userId: OpaqueID) => `/notifications/${userId}/playlist_updates`, - userTracksByHandle: (handle: OpaqueID) => `/users/handle/${handle}/tracks`, userAiTracksByHandle: (handle: OpaqueID) => `/users/handle/${handle}/tracks/ai_attributed`, getPlaylist: (playlistId: OpaqueID) => `/playlists/${playlistId}`, @@ -92,15 +91,6 @@ type GetTrackStreamUrlArgs = { abortOnUnreachable?: boolean } -type GetUserTracksByHandleArgs = { - handle: string - currentUserId: Nullable - sort?: 'date' | 'plays' - offset?: number - limit?: number - getUnlisted: boolean -} - type GetUserAiTracksByHandleArgs = { handle: string currentUserId: Nullable @@ -415,46 +405,6 @@ export class AudiusAPIClient { return tracks } - async getUserTracksByHandle({ - handle, - currentUserId, - sort = 'date', - limit, - offset, - getUnlisted - }: GetUserTracksByHandleArgs) { - this._assertInitialized() - const encodedCurrentUserId = encodeHashId(currentUserId) - const params = { - user_id: encodedCurrentUserId || undefined, - sort, - limit, - offset - } - - let headers = {} - if (encodedCurrentUserId && getUnlisted) { - const { data, signature } = await this.audiusBackendInstance.signData() - headers = { - [AuthHeaders.Message]: data, - [AuthHeaders.Signature]: signature - } - } - - const response = await this._getResponse>( - FULL_ENDPOINT_MAP.userTracksByHandle(handle), - params, - true, - PathType.VersionFullPath, - headers - ) - - if (!response) return [] - - const adapted = response.data.map(adapter.makeTrack).filter(removeNullable) - return adapted - } - async getUserAiTracksByHandle({ handle, currentUserId, diff --git a/packages/common/src/store/account/sagas.ts b/packages/common/src/store/account/sagas.ts index 0f96dc02cea..182d86610c0 100644 --- a/packages/common/src/store/account/sagas.ts +++ b/packages/common/src/store/account/sagas.ts @@ -1,26 +1,31 @@ import { call, put, select, takeLatest } from 'typed-redux-saga' -import { getContext } from '~/store/effects' +import { Id } from '~/models' import { UPLOAD_TRACKS_SUCCEEDED } from '~/store/upload/actions' +import { getSDK } from '../sdkUtils' + import { getUserId, getUserHandle } from './selectors' import { fetchAccountSucceeded, fetchHasTracks, setHasTracks } from './slice' function* handleFetchTrackCount() { const currentUserId = yield* select(getUserId) const handle = yield* select(getUserHandle) - const apiClient = yield* getContext('apiClient') + const sdk = yield* getSDK() if (!currentUserId || !handle) return try { - const tracks = yield* call([apiClient, apiClient.getUserTracksByHandle], { - handle, - currentUserId, - getUnlisted: true - }) - - yield* put(setHasTracks(tracks.length > 0)) + const { data = [] } = yield* call( + [sdk.full.users, sdk.full.users.getTracksByUserHandle], + { + handle, + userId: Id.parse(currentUserId), + limit: 1 + } + ) + + yield* put(setHasTracks(data.length > 0)) } catch (e) { console.warn('failed to fetch own user tracks') } diff --git a/packages/web/src/common/store/pages/profile/lineups/tracks/retrieveUserTracks.ts b/packages/web/src/common/store/pages/profile/lineups/tracks/retrieveUserTracks.ts index f4f3646647b..5a142ae4544 100644 --- a/packages/web/src/common/store/pages/profile/lineups/tracks/retrieveUserTracks.ts +++ b/packages/web/src/common/store/pages/profile/lineups/tracks/retrieveUserTracks.ts @@ -1,5 +1,9 @@ -import { ID, Track } from '@audius/common/models' -import { getContext } from '@audius/common/store' +import { + transformAndCleanList, + userTrackMetadataFromSDK +} from '@audius/common/adapters' +import { ID, OptionalId, Track } from '@audius/common/models' +import { getSDK } from '@audius/common/store' import { call } from 'typed-redux-saga' import { processAndCacheTracks } from 'common/store/cache/tracks/utils' @@ -25,16 +29,18 @@ export function* retrieveUserTracks({ limit, getUnlisted = false }: RetrieveUserTracksArgs): Generator { - const apiClient = yield* getContext('apiClient') - const apiTracks = yield* call([apiClient, apiClient.getUserTracksByHandle], { - handle, - currentUserId, - sort, - limit, - offset, - getUnlisted - }) - + const sdk = yield* getSDK() + const { data = [] } = yield* call( + [sdk.full.users, sdk.full.users.getTracksByUserHandle], + { + handle, + sort, + limit, + offset, + userId: OptionalId.parse(currentUserId) + } + ) + const apiTracks = transformAndCleanList(data, userTrackMetadataFromSDK) const processed: Track[] = yield processAndCacheTracks(apiTracks) return processed } From 91205dc877383345cab85f011905d61b39c2fa94 Mon Sep 17 00:00:00 2001 From: Randy Schott <1815175+schottra@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:38:06 -0400 Subject: [PATCH 02/10] migrate getUserAiTracksByHandle to sdk --- .../audius-api-client/AudiusAPIClient.ts | 53 ------------------- .../store/pages/ai/lineups/tracks/sagas.ts | 30 +++++++---- .../lineups/tracks/retrieveUserTracks.ts | 3 +- 3 files changed, 21 insertions(+), 65 deletions(-) diff --git a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts index adf4be8b11a..9f0d922df6a 100644 --- a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts +++ b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts @@ -7,7 +7,6 @@ import { } from '../../store/pages/search-results/types' import { decodeHashId, encodeHashId } from '../../utils/hashIds' import { Nullable, removeNullable } from '../../utils/typeUtils' -import { AuthHeaders } from '../audius-backend' import type { AudiusBackend } from '../audius-backend' import { getEagerDiscprov } from '../audius-backend/eagerLoadUtils' import { Env } from '../env' @@ -54,8 +53,6 @@ const FULL_ENDPOINT_MAP = { experiment ? `/playlists/trending/${experiment}` : '/playlists/trending', playlistUpdates: (userId: OpaqueID) => `/notifications/${userId}/playlist_updates`, - userAiTracksByHandle: (handle: OpaqueID) => - `/users/handle/${handle}/tracks/ai_attributed`, getPlaylist: (playlistId: OpaqueID) => `/playlists/${playlistId}`, getPlaylists: '/playlists', getPlaylistByPermalink: (handle: string, slug: string) => @@ -91,15 +88,6 @@ type GetTrackStreamUrlArgs = { abortOnUnreachable?: boolean } -type GetUserAiTracksByHandleArgs = { - handle: string - currentUserId: Nullable - sort?: 'date' | 'plays' - offset?: number - limit?: number - getUnlisted: boolean -} - type GetPremiumTracksArgs = { currentUserId: Nullable offset?: number @@ -405,47 +393,6 @@ export class AudiusAPIClient { return tracks } - async getUserAiTracksByHandle({ - handle, - currentUserId, - sort = 'date', - limit, - offset, - getUnlisted - }: GetUserAiTracksByHandleArgs) { - this._assertInitialized() - const encodedCurrentUserId = encodeHashId(currentUserId) - const params = { - user_id: encodedCurrentUserId || undefined, - sort, - limit, - offset - } - - let headers = {} - if (encodedCurrentUserId && getUnlisted) { - const { data, signature } = await this.audiusBackendInstance.signData() - headers = { - [AuthHeaders.Message]: data, - - [AuthHeaders.Signature]: signature - } - } - - const response = await this._getResponse>( - FULL_ENDPOINT_MAP.userAiTracksByHandle(handle), - params, - true, - PathType.VersionFullPath, - headers - ) - - if (!response) return [] - - const adapted = response.data.map(adapter.makeTrack).filter(removeNullable) - return adapted - } - async getPremiumTracks({ currentUserId, limit, diff --git a/packages/web/src/common/store/pages/ai/lineups/tracks/sagas.ts b/packages/web/src/common/store/pages/ai/lineups/tracks/sagas.ts index ea508e99d41..01da679282f 100644 --- a/packages/web/src/common/store/pages/ai/lineups/tracks/sagas.ts +++ b/packages/web/src/common/store/pages/ai/lineups/tracks/sagas.ts @@ -1,11 +1,15 @@ -import { Track } from '@audius/common/models' +import { + transformAndCleanList, + userTrackMetadataFromSDK +} from '@audius/common/adapters' +import { OptionalId, Track } from '@audius/common/models' import { accountSelectors, aiPageLineupActions as tracksActions, aiPageActions, aiPageSelectors, - getContext, - CommonState + CommonState, + getSDK } from '@audius/common/store' import { call, put, select } from 'typed-redux-saga' @@ -25,20 +29,24 @@ function* getTracks({ limit: number payload?: { aiUserHandle: string | null } }) { - const apiClient = yield* getContext('apiClient') + const sdk = yield* getSDK() const { aiUserHandle } = payload ?? {} if (!aiUserHandle) return [] yield* waitForRead() const currentUserId = yield* select(getUserId) - const tracks = yield* call([apiClient, apiClient.getUserAiTracksByHandle], { - handle: aiUserHandle, - offset, - limit, - currentUserId, - getUnlisted: false - }) + const { data = [] } = yield* call( + [sdk.full.users, sdk.full.users.getAIAttributedTracksByUserHandle], + { + handle: aiUserHandle, + offset, + limit, + userId: OptionalId.parse(currentUserId), + filterTracks: 'public' + } + ) + const tracks = transformAndCleanList(data, userTrackMetadataFromSDK) const count = tracks.length yield* put(setCount({ count })) diff --git a/packages/web/src/common/store/pages/profile/lineups/tracks/retrieveUserTracks.ts b/packages/web/src/common/store/pages/profile/lineups/tracks/retrieveUserTracks.ts index 5a142ae4544..d823067d6b3 100644 --- a/packages/web/src/common/store/pages/profile/lineups/tracks/retrieveUserTracks.ts +++ b/packages/web/src/common/store/pages/profile/lineups/tracks/retrieveUserTracks.ts @@ -37,7 +37,8 @@ export function* retrieveUserTracks({ sort, limit, offset, - userId: OptionalId.parse(currentUserId) + userId: OptionalId.parse(currentUserId), + filterTracks: getUnlisted ? 'all' : 'public' } ) const apiTracks = transformAndCleanList(data, userTrackMetadataFromSDK) From e9c1c73d95b23332566ab40cd925a62ddfa5c5a4 Mon Sep 17 00:00:00 2001 From: Randy Schott <1815175+schottra@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:46:39 -0400 Subject: [PATCH 03/10] migrate getPremiumTracks to sdk --- .../audius-api-client/AudiusAPIClient.ts | 35 +------------------ .../store/pages/ai/lineups/tracks/sagas.ts | 3 +- .../premium-tracks/lineups/tracks/sagas.ts | 20 ++++++----- 3 files changed, 15 insertions(+), 43 deletions(-) diff --git a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts index 9f0d922df6a..b1c4b843614 100644 --- a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts +++ b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts @@ -69,8 +69,7 @@ const FULL_ENDPOINT_MAP = { getReaction: '/reactions', getTips: '/tips', getNFTGatedTrackSignatures: (userId: OpaqueID) => - `/tracks/${userId}/nft-gated-signatures`, - getPremiumTracks: '/tracks/usdc-purchase' + `/tracks/${userId}/nft-gated-signatures` } export type QueryParams = { @@ -88,12 +87,6 @@ type GetTrackStreamUrlArgs = { abortOnUnreachable?: boolean } -type GetPremiumTracksArgs = { - currentUserId: Nullable - offset?: number - limit?: number -} - type GetCollectionMetadataArgs = { collectionId: ID currentUserId: ID @@ -393,32 +386,6 @@ export class AudiusAPIClient { return tracks } - async getPremiumTracks({ - currentUserId, - limit, - offset - }: GetPremiumTracksArgs) { - this._assertInitialized() - const encodedCurrentUserId = encodeHashId(currentUserId) - const params = { - user_id: encodedCurrentUserId || undefined, - limit, - offset - } - - const response = await this._getResponse>( - FULL_ENDPOINT_MAP.getPremiumTracks, - params, - true, - PathType.VersionFullPath - ) - - if (!response) return [] - - const adapted = response.data.map(adapter.makeTrack).filter(removeNullable) - return adapted - } - async getCollectionMetadata({ collectionId, currentUserId, diff --git a/packages/web/src/common/store/pages/ai/lineups/tracks/sagas.ts b/packages/web/src/common/store/pages/ai/lineups/tracks/sagas.ts index 01da679282f..39669d1020f 100644 --- a/packages/web/src/common/store/pages/ai/lineups/tracks/sagas.ts +++ b/packages/web/src/common/store/pages/ai/lineups/tracks/sagas.ts @@ -42,7 +42,8 @@ function* getTracks({ offset, limit, userId: OptionalId.parse(currentUserId), - filterTracks: 'public' + filterTracks: 'public', + sort: 'date' } ) diff --git a/packages/web/src/common/store/pages/premium-tracks/lineups/tracks/sagas.ts b/packages/web/src/common/store/pages/premium-tracks/lineups/tracks/sagas.ts index ee642a3bf92..c025966d8a8 100644 --- a/packages/web/src/common/store/pages/premium-tracks/lineups/tracks/sagas.ts +++ b/packages/web/src/common/store/pages/premium-tracks/lineups/tracks/sagas.ts @@ -1,9 +1,13 @@ -import { Track } from '@audius/common/models' +import { + transformAndCleanList, + userTrackMetadataFromSDK +} from '@audius/common/adapters' +import { OptionalId, Track } from '@audius/common/models' import { accountSelectors, premiumTracksPageLineupSelectors, premiumTracksPageLineupActions, - getContext + getSDK } from '@audius/common/store' import { call, select } from 'typed-redux-saga' @@ -22,13 +26,13 @@ function* getPremiumTracks({ limit: number }) { yield* waitForRead() - const apiClient = yield* getContext('apiClient') + const sdk = yield* getSDK() const currentUserId = yield* select(getUserId) - const tracks = yield* call([apiClient, apiClient.getPremiumTracks], { - offset, - limit, - currentUserId - }) + const { data = [] } = yield* call( + [sdk.full.tracks, sdk.full.tracks.getTrendingUSDCPurchaseTracks], + { limit, offset, userId: OptionalId.parse(currentUserId) } + ) + const tracks = transformAndCleanList(data, userTrackMetadataFromSDK) const processedTracks = yield* call(processAndCacheTracks, tracks) return processedTracks } From 8800512539649b171b0f0ec21cb03747080bf413 Mon Sep 17 00:00:00 2001 From: Randy Schott <1815175+schottra@users.noreply.github.com> Date: Thu, 22 Aug 2024 13:16:19 -0400 Subject: [PATCH 04/10] Add sdk docs for nft gated signatures endpoint --- .../src/api/v1/models/tracks.py | 33 ++++ .../discovery-provider/src/api/v1/tracks.py | 12 +- .../generated/full/.openapi-generator/FILES | 3 + .../sdk/api/generated/full/apis/TracksApi.ts | 76 +++++----- .../full/models/NftGatedTrackSignature.ts | 83 ++++++++++ .../full/models/NftGatedTrackSignatureData.ts | 76 ++++++++++ .../models/NftGatedTrackSignaturesResponse.ts | 142 ++++++++++++++++++ .../sdk/api/generated/full/models/index.ts | 3 + 8 files changed, 390 insertions(+), 38 deletions(-) create mode 100644 packages/libs/src/sdk/api/generated/full/models/NftGatedTrackSignature.ts create mode 100644 packages/libs/src/sdk/api/generated/full/models/NftGatedTrackSignatureData.ts create mode 100644 packages/libs/src/sdk/api/generated/full/models/NftGatedTrackSignaturesResponse.ts diff --git a/packages/discovery-provider/src/api/v1/models/tracks.py b/packages/discovery-provider/src/api/v1/models/tracks.py index 631575080be..2f531416e7f 100644 --- a/packages/discovery-provider/src/api/v1/models/tracks.py +++ b/packages/discovery-provider/src/api/v1/models/tracks.py @@ -3,6 +3,7 @@ from .access_gate import access_gate, extended_access_gate from .common import favorite, ns, repost from .extensions.fields import NestedOneOf +from .extensions.models import WildcardModel from .users import user_model, user_model_full track_artwork = ns.model( @@ -258,3 +259,35 @@ ), }, ) + +track_signature_data = ns.model( + "nft_gated_track_signature_data", + { + "data": fields.String(required=True), + "signature": fields.String(required=True), + }, +) + +nft_gated_track_signature = ns.model( + "nft_gated_track_signature", + { + "mp3": fields.Nested( + track_signature_data, + required=True, + ), + "original": fields.Nested( + track_signature_data, + required=True, + ), + }, +) + +signature_data_wild = fields.Wildcard( + fields.Nested(nft_gated_track_signature, required=True) +) + +nft_gated_track_signature_mapping = WildcardModel( + "nft_gated_track_signature_mapping", + {"*": signature_data_wild}, +) +ns.add_model("nft_gated_track_signature_mapping", nft_gated_track_signature_mapping) diff --git a/packages/discovery-provider/src/api/v1/tracks.py b/packages/discovery-provider/src/api/v1/tracks.py index d0c1ea6eee3..f3b01b1f854 100644 --- a/packages/discovery-provider/src/api/v1/tracks.py +++ b/packages/discovery-provider/src/api/v1/tracks.py @@ -88,7 +88,7 @@ from src.utils.redis_metrics import record_metrics from src.utils.rendezvous import RendezvousHash -from .models.tracks import blob_info +from .models.tracks import blob_info, nft_gated_track_signature_mapping from .models.tracks import remixes_response as remixes_response_model from .models.tracks import stem_full, track, track_access_info, track_full @@ -1749,17 +1749,25 @@ def get(self, version): return success_response(premium_tracks) +full_nft_gated_track_signatures_response = make_full_response( + "nft_gated_track_signatures_response", + full_ns, + fields.Nested(nft_gated_track_signature_mapping), +) + + @full_ns.route("//nft-gated-signatures") class NFTGatedTrackSignatures(Resource): @record_metrics @full_ns.doc( - id="""Get Gated Track Signatures""", + id="""Get NFT Gated Track Signatures""", description="""Gets gated track signatures for passed in gated track ids""", params={ "user_id": """The user for whom we are generating gated track signatures.""" }, ) @full_ns.expect(track_signatures_parser) + @full_ns.marshal_with(full_nft_gated_track_signatures_response) @cache(ttl_sec=5) def get(self, user_id): decoded_user_id = decode_with_abort(user_id, full_ns) diff --git a/packages/libs/src/sdk/api/generated/full/.openapi-generator/FILES b/packages/libs/src/sdk/api/generated/full/.openapi-generator/FILES index 959b1548d4e..15c3c304087 100644 --- a/packages/libs/src/sdk/api/generated/full/.openapi-generator/FILES +++ b/packages/libs/src/sdk/api/generated/full/.openapi-generator/FILES @@ -54,6 +54,9 @@ models/ManagedUsersResponse.ts models/ManagersResponse.ts models/NftCollection.ts models/NftGate.ts +models/NftGatedTrackSignature.ts +models/NftGatedTrackSignatureData.ts +models/NftGatedTrackSignaturesResponse.ts models/PlaylistAddedTimestamp.ts models/PlaylistArtwork.ts models/PlaylistFull.ts diff --git a/packages/libs/src/sdk/api/generated/full/apis/TracksApi.ts b/packages/libs/src/sdk/api/generated/full/apis/TracksApi.ts index ef2d2dbbdf8..7c90a16e980 100644 --- a/packages/libs/src/sdk/api/generated/full/apis/TracksApi.ts +++ b/packages/libs/src/sdk/api/generated/full/apis/TracksApi.ts @@ -19,6 +19,7 @@ import type { FullTopListener, FullTrackResponse, FullTracksResponse, + NftGatedTrackSignaturesResponse, RemixablesResponse, RemixesResponseFull, RemixingResponse, @@ -34,6 +35,8 @@ import { FullTrackResponseToJSON, FullTracksResponseFromJSON, FullTracksResponseToJSON, + NftGatedTrackSignaturesResponseFromJSON, + NftGatedTrackSignaturesResponseToJSON, RemixablesResponseFromJSON, RemixablesResponseToJSON, RemixesResponseFullFromJSON, @@ -63,18 +66,18 @@ export interface GetFeelingLuckyTracksRequest { minFollowers?: number; } -export interface GetGatedTrackSignaturesRequest { - userId: string; - trackIds?: Array; - tokenIds?: Array; -} - export interface GetMostLovedTracksRequest { userId?: string; limit?: number; withUsers?: boolean; } +export interface GetNFTGatedTrackSignaturesRequest { + userId: string; + trackIds?: Array; + tokenIds?: Array; +} + export interface GetRecommendedTracksRequest { limit?: number; genre?: string; @@ -323,78 +326,79 @@ export class TracksApi extends runtime.BaseAPI { /** * @hidden - * Gets gated track signatures for passed in gated track ids + * Gets the tracks found on the \"Most Loved\" smart playlist */ - async getGatedTrackSignaturesRaw(params: GetGatedTrackSignaturesRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { - if (params.userId === null || params.userId === undefined) { - throw new runtime.RequiredError('userId','Required parameter params.userId was null or undefined when calling getGatedTrackSignatures.'); - } - + async getMostLovedTracksRaw(params: GetMostLovedTracksRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { const queryParameters: any = {}; - if (params.trackIds) { - queryParameters['track_ids'] = params.trackIds; + if (params.userId !== undefined) { + queryParameters['user_id'] = params.userId; } - if (params.tokenIds) { - queryParameters['token_ids'] = params.tokenIds; + if (params.limit !== undefined) { + queryParameters['limit'] = params.limit; + } + + if (params.withUsers !== undefined) { + queryParameters['with_users'] = params.withUsers; } const headerParameters: runtime.HTTPHeaders = {}; const response = await this.request({ - path: `/tracks/{user_id}/nft-gated-signatures`.replace(`{${"user_id"}}`, encodeURIComponent(String(params.userId))), + path: `/tracks/most_loved`, method: 'GET', headers: headerParameters, query: queryParameters, }, initOverrides); - return new runtime.VoidApiResponse(response); + return new runtime.JSONApiResponse(response, (jsonValue) => FullTracksResponseFromJSON(jsonValue)); } /** - * Gets gated track signatures for passed in gated track ids + * Gets the tracks found on the \"Most Loved\" smart playlist */ - async getGatedTrackSignatures(params: GetGatedTrackSignaturesRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { - await this.getGatedTrackSignaturesRaw(params, initOverrides); + async getMostLovedTracks(params: GetMostLovedTracksRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + const response = await this.getMostLovedTracksRaw(params, initOverrides); + return await response.value(); } /** * @hidden - * Gets the tracks found on the \"Most Loved\" smart playlist + * Gets gated track signatures for passed in gated track ids */ - async getMostLovedTracksRaw(params: GetMostLovedTracksRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { - const queryParameters: any = {}; - - if (params.userId !== undefined) { - queryParameters['user_id'] = params.userId; + async getNFTGatedTrackSignaturesRaw(params: GetNFTGatedTrackSignaturesRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + if (params.userId === null || params.userId === undefined) { + throw new runtime.RequiredError('userId','Required parameter params.userId was null or undefined when calling getNFTGatedTrackSignatures.'); } - if (params.limit !== undefined) { - queryParameters['limit'] = params.limit; + const queryParameters: any = {}; + + if (params.trackIds) { + queryParameters['track_ids'] = params.trackIds; } - if (params.withUsers !== undefined) { - queryParameters['with_users'] = params.withUsers; + if (params.tokenIds) { + queryParameters['token_ids'] = params.tokenIds; } const headerParameters: runtime.HTTPHeaders = {}; const response = await this.request({ - path: `/tracks/most_loved`, + path: `/tracks/{user_id}/nft-gated-signatures`.replace(`{${"user_id"}}`, encodeURIComponent(String(params.userId))), method: 'GET', headers: headerParameters, query: queryParameters, }, initOverrides); - return new runtime.JSONApiResponse(response, (jsonValue) => FullTracksResponseFromJSON(jsonValue)); + return new runtime.JSONApiResponse(response, (jsonValue) => NftGatedTrackSignaturesResponseFromJSON(jsonValue)); } /** - * Gets the tracks found on the \"Most Loved\" smart playlist + * Gets gated track signatures for passed in gated track ids */ - async getMostLovedTracks(params: GetMostLovedTracksRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { - const response = await this.getMostLovedTracksRaw(params, initOverrides); + async getNFTGatedTrackSignatures(params: GetNFTGatedTrackSignaturesRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + const response = await this.getNFTGatedTrackSignaturesRaw(params, initOverrides); return await response.value(); } diff --git a/packages/libs/src/sdk/api/generated/full/models/NftGatedTrackSignature.ts b/packages/libs/src/sdk/api/generated/full/models/NftGatedTrackSignature.ts new file mode 100644 index 00000000000..6d58f0e05b6 --- /dev/null +++ b/packages/libs/src/sdk/api/generated/full/models/NftGatedTrackSignature.ts @@ -0,0 +1,83 @@ +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck +/** + * API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { NftGatedTrackSignatureData } from './NftGatedTrackSignatureData'; +import { + NftGatedTrackSignatureDataFromJSON, + NftGatedTrackSignatureDataFromJSONTyped, + NftGatedTrackSignatureDataToJSON, +} from './NftGatedTrackSignatureData'; + +/** + * + * @export + * @interface NftGatedTrackSignature + */ +export interface NftGatedTrackSignature { + /** + * + * @type {NftGatedTrackSignatureData} + * @memberof NftGatedTrackSignature + */ + mp3: NftGatedTrackSignatureData; + /** + * + * @type {NftGatedTrackSignatureData} + * @memberof NftGatedTrackSignature + */ + original: NftGatedTrackSignatureData; +} + +/** + * Check if a given object implements the NftGatedTrackSignature interface. + */ +export function instanceOfNftGatedTrackSignature(value: object): value is NftGatedTrackSignature { + let isInstance = true; + isInstance = isInstance && "mp3" in value && value["mp3"] !== undefined; + isInstance = isInstance && "original" in value && value["original"] !== undefined; + + return isInstance; +} + +export function NftGatedTrackSignatureFromJSON(json: any): NftGatedTrackSignature { + return NftGatedTrackSignatureFromJSONTyped(json, false); +} + +export function NftGatedTrackSignatureFromJSONTyped(json: any, ignoreDiscriminator: boolean): NftGatedTrackSignature { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'mp3': NftGatedTrackSignatureDataFromJSON(json['mp3']), + 'original': NftGatedTrackSignatureDataFromJSON(json['original']), + }; +} + +export function NftGatedTrackSignatureToJSON(value?: NftGatedTrackSignature | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'mp3': NftGatedTrackSignatureDataToJSON(value.mp3), + 'original': NftGatedTrackSignatureDataToJSON(value.original), + }; +} + diff --git a/packages/libs/src/sdk/api/generated/full/models/NftGatedTrackSignatureData.ts b/packages/libs/src/sdk/api/generated/full/models/NftGatedTrackSignatureData.ts new file mode 100644 index 00000000000..2f685332c97 --- /dev/null +++ b/packages/libs/src/sdk/api/generated/full/models/NftGatedTrackSignatureData.ts @@ -0,0 +1,76 @@ +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck +/** + * API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface NftGatedTrackSignatureData + */ +export interface NftGatedTrackSignatureData { + /** + * + * @type {string} + * @memberof NftGatedTrackSignatureData + */ + data: string; + /** + * + * @type {string} + * @memberof NftGatedTrackSignatureData + */ + signature: string; +} + +/** + * Check if a given object implements the NftGatedTrackSignatureData interface. + */ +export function instanceOfNftGatedTrackSignatureData(value: object): value is NftGatedTrackSignatureData { + let isInstance = true; + isInstance = isInstance && "data" in value && value["data"] !== undefined; + isInstance = isInstance && "signature" in value && value["signature"] !== undefined; + + return isInstance; +} + +export function NftGatedTrackSignatureDataFromJSON(json: any): NftGatedTrackSignatureData { + return NftGatedTrackSignatureDataFromJSONTyped(json, false); +} + +export function NftGatedTrackSignatureDataFromJSONTyped(json: any, ignoreDiscriminator: boolean): NftGatedTrackSignatureData { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'data': json['data'], + 'signature': json['signature'], + }; +} + +export function NftGatedTrackSignatureDataToJSON(value?: NftGatedTrackSignatureData | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'data': value.data, + 'signature': value.signature, + }; +} + diff --git a/packages/libs/src/sdk/api/generated/full/models/NftGatedTrackSignaturesResponse.ts b/packages/libs/src/sdk/api/generated/full/models/NftGatedTrackSignaturesResponse.ts new file mode 100644 index 00000000000..209bfdd6b65 --- /dev/null +++ b/packages/libs/src/sdk/api/generated/full/models/NftGatedTrackSignaturesResponse.ts @@ -0,0 +1,142 @@ +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck +/** + * API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { NftGatedTrackSignature } from './NftGatedTrackSignature'; +import { + NftGatedTrackSignatureFromJSON, + NftGatedTrackSignatureFromJSONTyped, + NftGatedTrackSignatureToJSON, +} from './NftGatedTrackSignature'; +import type { VersionMetadata } from './VersionMetadata'; +import { + VersionMetadataFromJSON, + VersionMetadataFromJSONTyped, + VersionMetadataToJSON, +} from './VersionMetadata'; + +/** + * + * @export + * @interface NftGatedTrackSignaturesResponse + */ +export interface NftGatedTrackSignaturesResponse { + /** + * + * @type {number} + * @memberof NftGatedTrackSignaturesResponse + */ + latestChainBlock: number; + /** + * + * @type {number} + * @memberof NftGatedTrackSignaturesResponse + */ + latestIndexedBlock: number; + /** + * + * @type {number} + * @memberof NftGatedTrackSignaturesResponse + */ + latestChainSlotPlays: number; + /** + * + * @type {number} + * @memberof NftGatedTrackSignaturesResponse + */ + latestIndexedSlotPlays: number; + /** + * + * @type {string} + * @memberof NftGatedTrackSignaturesResponse + */ + signature: string; + /** + * + * @type {string} + * @memberof NftGatedTrackSignaturesResponse + */ + timestamp: string; + /** + * + * @type {VersionMetadata} + * @memberof NftGatedTrackSignaturesResponse + */ + version: VersionMetadata; + /** + * + * @type {{ [key: string]: NftGatedTrackSignature; }} + * @memberof NftGatedTrackSignaturesResponse + */ + data?: { [key: string]: NftGatedTrackSignature; }; +} + +/** + * Check if a given object implements the NftGatedTrackSignaturesResponse interface. + */ +export function instanceOfNftGatedTrackSignaturesResponse(value: object): value is NftGatedTrackSignaturesResponse { + let isInstance = true; + isInstance = isInstance && "latestChainBlock" in value && value["latestChainBlock"] !== undefined; + isInstance = isInstance && "latestIndexedBlock" in value && value["latestIndexedBlock"] !== undefined; + isInstance = isInstance && "latestChainSlotPlays" in value && value["latestChainSlotPlays"] !== undefined; + isInstance = isInstance && "latestIndexedSlotPlays" in value && value["latestIndexedSlotPlays"] !== undefined; + isInstance = isInstance && "signature" in value && value["signature"] !== undefined; + isInstance = isInstance && "timestamp" in value && value["timestamp"] !== undefined; + isInstance = isInstance && "version" in value && value["version"] !== undefined; + + return isInstance; +} + +export function NftGatedTrackSignaturesResponseFromJSON(json: any): NftGatedTrackSignaturesResponse { + return NftGatedTrackSignaturesResponseFromJSONTyped(json, false); +} + +export function NftGatedTrackSignaturesResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): NftGatedTrackSignaturesResponse { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'latestChainBlock': json['latest_chain_block'], + 'latestIndexedBlock': json['latest_indexed_block'], + 'latestChainSlotPlays': json['latest_chain_slot_plays'], + 'latestIndexedSlotPlays': json['latest_indexed_slot_plays'], + 'signature': json['signature'], + 'timestamp': json['timestamp'], + 'version': VersionMetadataFromJSON(json['version']), + 'data': !exists(json, 'data') ? undefined : (mapValues(json['data'], NftGatedTrackSignatureFromJSON)), + }; +} + +export function NftGatedTrackSignaturesResponseToJSON(value?: NftGatedTrackSignaturesResponse | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'latest_chain_block': value.latestChainBlock, + 'latest_indexed_block': value.latestIndexedBlock, + 'latest_chain_slot_plays': value.latestChainSlotPlays, + 'latest_indexed_slot_plays': value.latestIndexedSlotPlays, + 'signature': value.signature, + 'timestamp': value.timestamp, + 'version': VersionMetadataToJSON(value.version), + 'data': value.data === undefined ? undefined : (mapValues(value.data, NftGatedTrackSignatureToJSON)), + }; +} + diff --git a/packages/libs/src/sdk/api/generated/full/models/index.ts b/packages/libs/src/sdk/api/generated/full/models/index.ts index ef9dc61747c..32751248032 100644 --- a/packages/libs/src/sdk/api/generated/full/models/index.ts +++ b/packages/libs/src/sdk/api/generated/full/models/index.ts @@ -45,6 +45,9 @@ export * from './ManagedUsersResponse'; export * from './ManagersResponse'; export * from './NftCollection'; export * from './NftGate'; +export * from './NftGatedTrackSignature'; +export * from './NftGatedTrackSignatureData'; +export * from './NftGatedTrackSignaturesResponse'; export * from './PlaylistAddedTimestamp'; export * from './PlaylistArtwork'; export * from './PlaylistFull'; From 82a741792050783742484f7a2dc9f4c0a8bf7f82 Mon Sep 17 00:00:00 2001 From: Randy Schott <1815175+schottra@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:42:23 -0400 Subject: [PATCH 05/10] migrate getNftGatedTrackSignatures endpoint to sdk --- .../audius-api-client/AudiusAPIClient.ts | 47 +------------------ .../src/services/audius-api-client/types.ts | 8 +--- .../common/src/store/gated-content/sagas.ts | 28 +++++++++-- 3 files changed, 25 insertions(+), 58 deletions(-) diff --git a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts index b1c4b843614..e190993656f 100644 --- a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts +++ b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts @@ -23,7 +23,6 @@ import { APISearchAutocomplete, APIStem, APITrack, - GetNFTGatedTrackSignaturesResponse, GetTipsResponse, OpaqueID } from './types' @@ -67,9 +66,7 @@ const FULL_ENDPOINT_MAP = { searchFull: `/search/full`, searchAutocomplete: `/search/autocomplete`, getReaction: '/reactions', - getTips: '/tips', - getNFTGatedTrackSignatures: (userId: OpaqueID) => - `/tracks/${userId}/nft-gated-signatures` + getTips: '/tips' } export type QueryParams = { @@ -200,13 +197,6 @@ export type GetTipsArgs = { txSignatures?: string[] } -export type GetNFTGatedTrackSignaturesArgs = { - userId: ID - trackMap: { - [id: ID]: string[] - } -} - type InitializationState = | { state: 'uninitialized' } | { @@ -742,41 +732,6 @@ export class AudiusAPIClient { return null } - async getNFTGatedTrackSignatures({ - userId, - trackMap - }: GetNFTGatedTrackSignaturesArgs) { - if (!Object.keys(trackMap).length) return null - - const encodedUserId = this._encodeOrThrow(userId) - this._assertInitialized() - - // To avoid making a POST request and thereby introducing a new pattern in the DN, - // we build a param string that represents the info we need to verify nft collection ownership. - // The trackMap is a map of track ids -> token ids. - // If the nft collection is not ERC1155, then there are no token ids. - // We append the track ids and token ids as query params, making sure they're the same length - // so that DN knows which token ids belong to which track ids. - // Example: - // trackMap: { 1: [1, 2], 2: [], 3: [1]} - // query params: '?track_ids=1&token_ids=1-2&track_ids=2&token_ids=&track_ids=3&token_ids=1' - const trackIdParams: string[] = [] - const tokenIdParams: string[] = [] - Object.keys(trackMap).forEach((trackId) => { - trackIdParams.push(trackId) - tokenIdParams.push(trackMap[trackId].join('-')) - }) - const params = { - track_ids: trackIdParams, - token_ids: tokenIdParams - } - - const response = await this._getResponse< - APIResponse - >(FULL_ENDPOINT_MAP.getNFTGatedTrackSignatures(encodedUserId), params) - return response ? response.data : null - } - async getPlaylistUpdates(userId: number) { type ApiPlaylistUpdate = { playlist_id: string diff --git a/packages/common/src/services/audius-api-client/types.ts b/packages/common/src/services/audius-api-client/types.ts index 97901bbc175..9e38f5e23d5 100644 --- a/packages/common/src/services/audius-api-client/types.ts +++ b/packages/common/src/services/audius-api-client/types.ts @@ -15,9 +15,7 @@ import { Supporting, UserTip, AccessConditions, - ID, - AccessPermissions, - NFTAccessSignature + AccessPermissions } from '../../models' import { License, Nullable } from '../../utils' @@ -296,7 +294,3 @@ export type GetTipsResponse = Omit & { receiver: APIUser followee_supporters: { user_id: string }[] } - -export type GetNFTGatedTrackSignaturesResponse = { - [id: ID]: NFTAccessSignature -} diff --git a/packages/common/src/store/gated-content/sagas.ts b/packages/common/src/store/gated-content/sagas.ts index cee676b15a8..ff30a45ffe2 100644 --- a/packages/common/src/store/gated-content/sagas.ts +++ b/packages/common/src/store/gated-content/sagas.ts @@ -258,13 +258,31 @@ function* updateCollectibleGatedTracks(trackMap: { [id: ID]: string[] }) { const account = yield* select(getAccountUser) if (!account) return - const apiClient = yield* getContext('apiClient') + const sdk = yield* getSDK() - const nftGatedTrackSignatureResponse = yield* call( - [apiClient, apiClient.getNFTGatedTrackSignatures], + /** Endpoint accepts an array of track_ids and an array of token_id specifications which map to them + * The entry in each token_id array is a hyphen-delimited list of tokenIds. + * Example: + * trackMap: { 1: [1, 2], 2: [], 3: [1]} + * query params: '?track_ids=1&token_ids=1-2&track_ids=2&token_ids=&track_ids=3&token_ids=1' + */ + const trackIds: number[] = [] + const tokenIds: string[] = [] + Object.keys(trackMap).forEach((trackId) => { + const id = parseInt(trackId) + if (Number.isNaN(id)) { + console.warn(`Invalid track id: ${trackId}`) + return + } + trackIds.push(id) + tokenIds.push(trackMap[trackId].join('-')) + }) + const { data: nftGatedTrackSignatureResponse = {} } = yield* call( + [sdk.full.tracks, sdk.full.tracks.getNFTGatedTrackSignatures], { - userId: account.user_id, - trackMap + userId: Id.parse(account.user_id), + trackIds, + tokenIds } ) From 18c9403790c2d9e3341937cc14ea776470a88fbe Mon Sep 17 00:00:00 2001 From: Randy Schott <1815175+schottra@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:50:21 -0400 Subject: [PATCH 06/10] document type adapter --- packages/common/src/api/types.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/common/src/api/types.ts b/packages/common/src/api/types.ts index c513b439054..847a47a1714 100644 --- a/packages/common/src/api/types.ts +++ b/packages/common/src/api/types.ts @@ -1,5 +1,9 @@ import { ID } from '~/models' +/** Helper type for accepting args to a SDK method. It strips out the signature + * parameters (which are passed by SDK middleware) and adds the common + * `currentUserId` parameter that most functions calling SDK methods will convert + * and pass along. */ export type SDKRequest = Omit< T, 'encodedDataMessage' | 'encodedDataSignature' From be1224ce599d7185a4faeec82a1bca421db8d4ac Mon Sep 17 00:00:00 2001 From: Randy Schott <1815175+schottra@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:26:39 -0400 Subject: [PATCH 07/10] migrate getRemixes to sdk --- .../audius-api-client/AudiusAPIClient.ts | 35 ------------------- .../tracks/utils/fetchAndProcessRemixes.ts | 29 +++++++++------ .../remixes-page/lineups/tracks/sagas.ts | 32 +++++++++++------ 3 files changed, 39 insertions(+), 57 deletions(-) diff --git a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts index e190993656f..3fa32c7ae99 100644 --- a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts +++ b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts @@ -61,7 +61,6 @@ const FULL_ENDPOINT_MAP = { `/tracks/${trackId}/stems${ stemIds ? `?stemIds=${stemIds?.join(',')}` : '' }`, - getRemixes: (trackId: OpaqueID) => `/tracks/${trackId}/remixes`, getRemixing: (trackId: OpaqueID) => `/tracks/${trackId}/remixing`, searchFull: `/search/full`, searchAutocomplete: `/search/autocomplete`, @@ -112,18 +111,6 @@ type GetStemsArgs = { stemIds?: ID[] } -type GetRemixesArgs = { - trackId: ID - currentUserId: Nullable - limit: number - offset: number -} - -type RemixesResponse = { - tracks: APITrack[] - count: number -} - type GetRemixingArgs = { trackId: ID currentUserId: Nullable @@ -328,28 +315,6 @@ export class AudiusAPIClient { return adapted } - async getRemixes({ trackId, limit, offset, currentUserId }: GetRemixesArgs) { - this._assertInitialized() - const encodedTrackId = this._encodeOrThrow(trackId) - const encodedUserId = encodeHashId(currentUserId) - const params = { - userId: encodedUserId ?? undefined, - limit, - offset - } - - const remixesResponse = await this._getResponse< - APIResponse - >(FULL_ENDPOINT_MAP.getRemixes(encodedTrackId), params) - - if (!remixesResponse) return { count: 0, tracks: [] } - - const tracks = remixesResponse.data.tracks - .map(adapter.makeTrack) - .filter(removeNullable) - return { count: remixesResponse.data.count, tracks } - } - async getRemixing({ trackId, limit, diff --git a/packages/web/src/common/store/cache/tracks/utils/fetchAndProcessRemixes.ts b/packages/web/src/common/store/cache/tracks/utils/fetchAndProcessRemixes.ts index 823915dc6f7..aeb1c346948 100644 --- a/packages/web/src/common/store/cache/tracks/utils/fetchAndProcessRemixes.ts +++ b/packages/web/src/common/store/cache/tracks/utils/fetchAndProcessRemixes.ts @@ -1,9 +1,14 @@ -import { Kind, ID, UserTrackMetadata } from '@audius/common/models' +import { + transformAndCleanList, + userTrackMetadataFromSDK +} from '@audius/common/adapters' +import { Kind, ID, Id, OptionalId } from '@audius/common/models' import { accountSelectors, cacheTracksSelectors, cacheActions, - getContext + getContext, + getSDK } from '@audius/common/store' import { removeNullable, waitForValue } from '@audius/common/utils' import { select, call, put } from 'typed-redux-saga' @@ -25,22 +30,24 @@ const INITIAL_FETCH_LIMIT = 6 */ export function* fetchAndProcessRemixes(trackId: ID) { yield* waitForRead() - const apiClient = yield* getContext('apiClient') + + const sdk = yield* getSDK() const currentUserId = yield* select(getUserId) - const { - tracks: remixes, - count - }: { tracks: UserTrackMetadata[]; count: number } = yield* call( - [apiClient, 'getRemixes'], + + const { data } = yield* call( + [sdk.full.tracks, sdk.full.tracks.getTrackRemixes], { - trackId, + trackId: Id.parse(trackId), offset: 0, limit: INITIAL_FETCH_LIMIT, - currentUserId + userId: OptionalId.parse(currentUserId) } ) - if (!remixes) return + if (!data) return + + const { count, tracks } = data + const remixes = transformAndCleanList(tracks, userTrackMetadataFromSDK) if (remixes.length) { yield* call(processAndCacheTracks, remixes) diff --git a/packages/web/src/common/store/pages/remixes-page/lineups/tracks/sagas.ts b/packages/web/src/common/store/pages/remixes-page/lineups/tracks/sagas.ts index 07b7d8502f1..a6724d65a03 100644 --- a/packages/web/src/common/store/pages/remixes-page/lineups/tracks/sagas.ts +++ b/packages/web/src/common/store/pages/remixes-page/lineups/tracks/sagas.ts @@ -1,11 +1,15 @@ -import { Track } from '@audius/common/models' +import { + transformAndCleanList, + userTrackMetadataFromSDK +} from '@audius/common/adapters' +import { Id, OptionalId, Track } from '@audius/common/models' import { accountSelectors, remixesPageLineupActions as tracksActions, remixesPageActions, remixesPageSelectors, - getContext, - CommonState + CommonState, + getSDK } from '@audius/common/store' import { call, put, select } from 'typed-redux-saga' @@ -25,20 +29,26 @@ function* getTracks({ limit: number payload?: { trackId: number | null } }) { - const apiClient = yield* getContext('apiClient') + const sdk = yield* getSDK() const { trackId } = payload ?? {} if (!trackId) return [] yield* waitForRead() const currentUserId = yield* select(getUserId) - const { tracks, count } = yield* call([apiClient, 'getRemixes'], { - trackId, - offset, - limit, - currentUserId - }) - yield* put(setCount({ count })) + const { data = { count: 0, tracks: [] } } = yield* call( + [sdk.full.tracks, sdk.full.tracks.getTrackRemixes], + { + trackId: Id.parse(trackId), + offset, + limit, + userId: OptionalId.parse(currentUserId) + } + ) + + const tracks = transformAndCleanList(data.tracks, userTrackMetadataFromSDK) + + yield* put(setCount({ count: data.count })) const processedTracks = yield* call(processAndCacheTracks, tracks) From 018f57c53cd74f59d9b363c255f6bc4ff55a5c37 Mon Sep 17 00:00:00 2001 From: Randy Schott <1815175+schottra@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:32:51 -0400 Subject: [PATCH 08/10] migrate getRemixing to sdk --- .../audius-api-client/AudiusAPIClient.ts | 35 ------------------- .../tracks/utils/fetchAndProcessRemixes.ts | 22 +++++++----- 2 files changed, 13 insertions(+), 44 deletions(-) diff --git a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts index 3fa32c7ae99..617e50d62c2 100644 --- a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts +++ b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts @@ -22,7 +22,6 @@ import { APISearch, APISearchAutocomplete, APIStem, - APITrack, GetTipsResponse, OpaqueID } from './types' @@ -61,7 +60,6 @@ const FULL_ENDPOINT_MAP = { `/tracks/${trackId}/stems${ stemIds ? `?stemIds=${stemIds?.join(',')}` : '' }`, - getRemixing: (trackId: OpaqueID) => `/tracks/${trackId}/remixing`, searchFull: `/search/full`, searchAutocomplete: `/search/autocomplete`, getReaction: '/reactions', @@ -111,13 +109,6 @@ type GetStemsArgs = { stemIds?: ID[] } -type GetRemixingArgs = { - trackId: ID - currentUserId: Nullable - limit: number - offset: number -} - type GetSearchArgs = { currentUserId: Nullable query: string @@ -315,32 +306,6 @@ export class AudiusAPIClient { return adapted } - async getRemixing({ - trackId, - limit, - offset, - currentUserId - }: GetRemixingArgs) { - this._assertInitialized() - const encodedTrackId = this._encodeOrThrow(trackId) - const encodedUserId = encodeHashId(currentUserId) - const params = { - userId: encodedUserId ?? undefined, - limit, - offset - } - - const remixingResponse = await this._getResponse>( - FULL_ENDPOINT_MAP.getRemixing(encodedTrackId), - params - ) - - if (!remixingResponse) return [] - - const tracks = remixingResponse.data.map(adapter.makeTrack) - return tracks - } - async getCollectionMetadata({ collectionId, currentUserId, diff --git a/packages/web/src/common/store/cache/tracks/utils/fetchAndProcessRemixes.ts b/packages/web/src/common/store/cache/tracks/utils/fetchAndProcessRemixes.ts index aeb1c346948..b0709c1bada 100644 --- a/packages/web/src/common/store/cache/tracks/utils/fetchAndProcessRemixes.ts +++ b/packages/web/src/common/store/cache/tracks/utils/fetchAndProcessRemixes.ts @@ -7,10 +7,9 @@ import { accountSelectors, cacheTracksSelectors, cacheActions, - getContext, getSDK } from '@audius/common/store' -import { removeNullable, waitForValue } from '@audius/common/utils' +import { waitForValue } from '@audius/common/utils' import { select, call, put } from 'typed-redux-saga' import { waitForRead } from 'utils/sagaHelpers' @@ -85,14 +84,19 @@ export function* fetchAndProcessRemixes(trackId: ID) { */ export function* fetchAndProcessRemixParents(trackId: ID) { yield* waitForRead() - const apiClient = yield* getContext('apiClient') + const sdk = yield* getSDK() const currentUserId = yield* select(getUserId) - const remixParents = (yield* call([apiClient, 'getRemixing'], { - trackId, - limit: 1, - offset: 0, - currentUserId - })).filter(removeNullable) + + const { data = [] } = yield* call( + [sdk.full.tracks, sdk.full.tracks.getTrackRemixParents], + { + trackId: Id.parse(trackId), + offset: 0, + limit: 1, + userId: OptionalId.parse(currentUserId) + } + ) + const remixParents = transformAndCleanList(data, userTrackMetadataFromSDK) if (!remixParents) return From b843d4532f6c4a0a81c3fd50044bdc9228ea9180 Mon Sep 17 00:00:00 2001 From: Randy Schott <1815175+schottra@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:55:10 -0400 Subject: [PATCH 09/10] migrate getStems to SDK --- packages/common/src/adapters/track.ts | 63 ++++++++++++++++++- .../audius-api-client/AudiusAPIClient.ts | 30 +-------- .../tracks/utils/fetchAndProcessStems.ts | 32 +++++----- .../cache/tracks/utils/retrieveTracks.ts | 4 +- .../store/application/ui/stemsUpload/sagas.ts | 3 +- 5 files changed, 81 insertions(+), 51 deletions(-) diff --git a/packages/common/src/adapters/track.ts b/packages/common/src/adapters/track.ts index a131aea1ed7..e424d2cbee3 100644 --- a/packages/common/src/adapters/track.ts +++ b/packages/common/src/adapters/track.ts @@ -9,7 +9,7 @@ import { StemCategory, TrackSegment } from '~/models' -import { UserTrackMetadata } from '~/models/Track' +import { Stem, StemTrackMetadata, UserTrackMetadata } from '~/models/Track' import { License } from '~/utils' import { decodeHashId } from '~/utils/hashIds' @@ -151,3 +151,64 @@ export const userTrackMetadataFromSDK = ( return newTrack } + +export const stemTrackMetadataFromSDK = ( + input: full.StemFull +): StemTrackMetadata | undefined => { + const [id, parentId, ownerId] = [input.id, input.parentId, input.userId].map( + decodeHashId + ) + if (!(id && parentId && ownerId)) return undefined + + return { + blocknumber: input.blocknumber, + is_delete: false, + track_id: id, + created_at: '', + isrc: null, + iswc: null, + credits_splits: null, + create_date: null, + description: null, + followee_reposts: [], + followee_saves: [], + genre: '', + has_current_user_reposted: false, + has_current_user_saved: false, + license: null, + mood: null, + play_count: 0, + owner_id: ownerId, + release_date: null, + repost_count: 0, + save_count: 0, + tags: null, + title: '', + track_segments: [], + cover_art: null, + cover_art_sizes: null, + cover_art_cids: null, + is_scheduled_release: false, + is_unlisted: false, + stem_of: { + parent_track_id: parentId, + category: input.category as StemCategory + }, + remix_of: null, + duration: 0, + updated_at: '', + permalink: '', + is_available: true, + is_stream_gated: false, + stream_conditions: null, + is_download_gated: false, + download_conditions: null, + access: { stream: true, download: true }, + track_cid: input.cid, + orig_file_cid: '', + orig_filename: input.origFilename, + is_downloadable: true, + is_original_available: false, + is_playlist_upload: false + } +} diff --git a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts index 617e50d62c2..cda620acd8e 100644 --- a/packages/common/src/services/audius-api-client/AudiusAPIClient.ts +++ b/packages/common/src/services/audius-api-client/AudiusAPIClient.ts @@ -1,6 +1,6 @@ import type { AudiusLibs, Genre, Mood } from '@audius/sdk' -import { ID, StemTrackMetadata, CollectionMetadata } from '../../models' +import { ID, CollectionMetadata } from '../../models' import { SearchKind, SearchSortMethod @@ -21,7 +21,6 @@ import { APIResponse, APISearch, APISearchAutocomplete, - APIStem, GetTipsResponse, OpaqueID } from './types' @@ -56,10 +55,6 @@ const FULL_ENDPOINT_MAP = { getPlaylistByPermalink: (handle: string, slug: string) => `/playlists/by_permalink/${handle}/${slug}`, getTrackStreamUrl: (trackId: OpaqueID) => `/tracks/${trackId}/stream`, - getStems: (trackId: OpaqueID, stemIds?: ID[]) => - `/tracks/${trackId}/stems${ - stemIds ? `?stemIds=${stemIds?.join(',')}` : '' - }`, searchFull: `/search/full`, searchAutocomplete: `/search/autocomplete`, getReaction: '/reactions', @@ -104,11 +99,6 @@ type GetPlaylistByPermalinkArgs = { currentUserId: Nullable } -type GetStemsArgs = { - trackId: ID - stemIds?: ID[] -} - type GetSearchArgs = { currentUserId: Nullable query: string @@ -288,24 +278,6 @@ export class AudiusAPIClient { return trackUrl?.data } - async getStems({ - trackId, - stemIds - }: GetStemsArgs): Promise { - this._assertInitialized() - const encodedTrackId = this._encodeOrThrow(trackId) - const response = await this._getResponse>( - FULL_ENDPOINT_MAP.getStems(encodedTrackId, stemIds) - ) - - if (!response) return [] - - const adapted = response.data - .map(adapter.makeStemTrack) - .filter(removeNullable) - return adapted - } - async getCollectionMetadata({ collectionId, currentUserId, diff --git a/packages/web/src/common/store/cache/tracks/utils/fetchAndProcessStems.ts b/packages/web/src/common/store/cache/tracks/utils/fetchAndProcessStems.ts index 22997422627..8bf63b3e4a6 100644 --- a/packages/web/src/common/store/cache/tracks/utils/fetchAndProcessStems.ts +++ b/packages/web/src/common/store/cache/tracks/utils/fetchAndProcessStems.ts @@ -1,17 +1,15 @@ import { - Kind, - StemCategory, - ID, - Stem, - StemTrackMetadata -} from '@audius/common/models' + stemTrackMetadataFromSDK, + transformAndCleanList +} from '@audius/common/adapters' +import { Kind, StemCategory, ID, Stem, Id } from '@audius/common/models' import { cacheTracksSelectors, cacheActions, - getContext + getSDK } from '@audius/common/store' import { waitForValue } from '@audius/common/utils' -import { call, put } from 'redux-saga/effects' +import { call, put } from 'typed-redux-saga' import { waitForRead } from 'utils/sagaHelpers' @@ -25,21 +23,23 @@ const { getTrack } = cacheTracksSelectors * * @param trackId the parent track for which to fetch stems */ -export function* fetchAndProcessStems(trackId: ID, stemIds?: ID[]) { +export function* fetchAndProcessStems(trackId: ID) { yield* waitForRead() - const apiClient = yield* getContext('apiClient') + const sdk = yield* getSDK() - const stems: StemTrackMetadata[] = yield call( - [apiClient, apiClient.getStems], - { trackId, stemIds } + const { data = [] } = yield* call( + [sdk.full.tracks, sdk.full.tracks.getTrackStems], + { trackId: Id.parse(trackId) } ) + const stems = transformAndCleanList(data, stemTrackMetadataFromSDK) + if (stems.length) { - yield call(processAndCacheTracks, stems) + yield* call(processAndCacheTracks, stems) } // Don't update the original track with stems until it's in the cache - yield call(waitForValue, getTrack, { id: trackId }) + yield* call(waitForValue, getTrack, { id: trackId }) // Create the update const stemsUpdate: Stem[] = stems.map((s) => ({ @@ -48,7 +48,7 @@ export function* fetchAndProcessStems(trackId: ID, stemIds?: ID[]) { orig_filename: s.orig_filename ?? '' })) - yield put( + yield* put( cacheActions.update(Kind.TRACKS, [ { id: trackId, diff --git a/packages/web/src/common/store/cache/tracks/utils/retrieveTracks.ts b/packages/web/src/common/store/cache/tracks/utils/retrieveTracks.ts index 3553dd27f0d..981c73f35f7 100644 --- a/packages/web/src/common/store/cache/tracks/utils/retrieveTracks.ts +++ b/packages/web/src/common/store/cache/tracks/utils/retrieveTracks.ts @@ -50,7 +50,6 @@ type RetrieveTracksArgs = { /** deprecated */ canBeUnlisted?: boolean withStems?: boolean - stemIds?: ID[] withRemixes?: boolean withRemixParents?: boolean forceRetrieveFromSource?: boolean @@ -160,7 +159,6 @@ export function* retrieveTracks({ trackIds, canBeUnlisted = false, withStems = false, - stemIds, withRemixes = false, withRemixParents = false }: RetrieveTracksArgs) { @@ -254,7 +252,7 @@ export function* retrieveTracks({ console.error('Stems endpoint only supports fetching single tracks') return } - yield* call(fetchAndProcessStems, trackId, stemIds) + yield* call(fetchAndProcessStems, trackId) }) } diff --git a/packages/web/src/store/application/ui/stemsUpload/sagas.ts b/packages/web/src/store/application/ui/stemsUpload/sagas.ts index 9a1f31d8607..ad45372049c 100644 --- a/packages/web/src/store/application/ui/stemsUpload/sagas.ts +++ b/packages/web/src/store/application/ui/stemsUpload/sagas.ts @@ -48,8 +48,7 @@ function* watchUploadStems() { // Retrieve the parent track to refresh stems yield* call(retrieveTracks, { trackIds: [parentId], - withStems: true, - stemIds: trackIds + withStems: true }) } ) From fb71905982d9f579eb475368c3e761064c7f70e6 Mon Sep 17 00:00:00 2001 From: Randy Schott <1815175+schottra@users.noreply.github.com> Date: Fri, 23 Aug 2024 10:30:08 -0400 Subject: [PATCH 10/10] fix lint error --- packages/common/src/adapters/track.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/common/src/adapters/track.ts b/packages/common/src/adapters/track.ts index e424d2cbee3..9447b9039f6 100644 --- a/packages/common/src/adapters/track.ts +++ b/packages/common/src/adapters/track.ts @@ -9,7 +9,7 @@ import { StemCategory, TrackSegment } from '~/models' -import { Stem, StemTrackMetadata, UserTrackMetadata } from '~/models/Track' +import { StemTrackMetadata, UserTrackMetadata } from '~/models/Track' import { License } from '~/utils' import { decodeHashId } from '~/utils/hashIds'