@audius/sdk 0.0.35 → 0.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import { Base, Services } from './base'
2
2
  import type { PlaylistMetadata } from '../services/creatorNode'
3
- import { Nullable, Utils } from '../utils'
3
+ import type { Nullable } from '../utils'
4
4
 
5
5
  export enum Action {
6
6
  CREATE = 'Create',
@@ -21,17 +21,23 @@ export interface PlaylistOperationResponse {
21
21
  * Block number of playlist transaction
22
22
  */
23
23
  blockNumber: Nullable<number>
24
- /**
25
- * ID of playlist being modified
26
- */
27
- playlistId: Nullable<number>
28
24
  /**
29
25
  * String error message returned
30
26
  */
31
27
  error: Nullable<string>
32
28
  }
33
-
34
- const { encodeHashId, decodeHashId } = Utils
29
+ type PlaylistTrack = { time: number; metadata_time?: number; track: number }
30
+
31
+ type PlaylistParam = {
32
+ playlist_id: number
33
+ playlist_name: string
34
+ artwork?: { file?: File; url?: string }
35
+ playlist_contents: { track_ids: PlaylistTrack[] } // number[] for playlist upload flow
36
+ cover_art_sizes: string
37
+ description: string
38
+ is_private: boolean
39
+ is_album: boolean
40
+ }
35
41
 
36
42
  /*
37
43
  API surface for updated data contract interactions.
@@ -48,30 +54,11 @@ export class EntityManager extends Base {
48
54
  return Math.floor(Math.random() * (max - min) + min)
49
55
  }
50
56
 
51
- async getFullPlaylist(playlistId: number, userId: number) {
52
- const encodedPlaylistId = encodeHashId(playlistId) as string
53
- const encodedUserId = encodeHashId(userId) as string
54
-
55
- const playlist: any = (
56
- await this.discoveryProvider.getFullPlaylist(
57
- encodedPlaylistId,
58
- encodedUserId
59
- )
60
- )[0]
61
- return playlist
62
- }
63
-
64
- mapAddedTimestamps(addedTimestamps: any) {
65
- const trackIds = addedTimestamps.map(
66
- (trackObj: {
67
- track_id: string
68
- metadata_timestamp?: number
69
- timestamp: number
70
- }) => ({
71
- track: decodeHashId(trackObj.track_id),
72
- time: trackObj.metadata_timestamp ?? trackObj.timestamp
73
- })
74
- )
57
+ mapTimestamps(addedTimestamps: PlaylistTrack[]) {
58
+ const trackIds = addedTimestamps.map((trackObj) => ({
59
+ track: trackObj.track,
60
+ time: trackObj.metadata_time ?? trackObj.time // default to time for legacy playlists
61
+ }))
75
62
 
76
63
  return trackIds
77
64
  }
@@ -83,7 +70,6 @@ export class EntityManager extends Base {
83
70
  return {
84
71
  blockHash: null,
85
72
  blockNumber: null,
86
- playlistId: null,
87
73
  error: null
88
74
  }
89
75
  }
@@ -91,72 +77,52 @@ export class EntityManager extends Base {
91
77
  /**
92
78
  * Create a playlist using updated data contracts flow
93
79
  */
94
- async createPlaylist({
95
- playlistId,
96
- playlistName,
97
- trackIds,
98
- description,
99
- isAlbum,
100
- isPrivate,
101
- coverArt,
102
- logger = console
103
- }: {
104
- playlistId: number
105
- playlistName: string
106
- trackIds: number[]
107
- description: string
108
- isAlbum: boolean
109
- isPrivate: boolean
110
- coverArt: string
111
- logger: Console
112
- }): Promise<PlaylistOperationResponse> {
80
+ async createPlaylist(
81
+ playlist: PlaylistParam
82
+ ): Promise<PlaylistOperationResponse> {
113
83
  const responseValues: PlaylistOperationResponse =
114
84
  this.getDefaultPlaylistReponseValues()
115
85
  try {
116
- const currentUserId: string | null =
117
- this.userStateManager.getCurrentUserId()
118
- if (!currentUserId) {
86
+ const userId: number | null = this.userStateManager.getCurrentUserId()
87
+ if (!userId) {
119
88
  responseValues.error = 'Missing current user ID'
120
89
  return responseValues
121
90
  }
122
- const userId: number = parseInt(currentUserId)
123
91
  const createAction = Action.CREATE
124
92
  const entityType = EntityType.PLAYLIST
125
93
  this.REQUIRES(Services.CREATOR_NODE)
126
- const updatedPlaylistImage = await this.creatorNode.uploadImage(
127
- coverArt,
128
- true // square
129
- )
130
- const web3 = this.web3Manager.getWeb3()
131
- const currentBlockNumber = await web3.eth.getBlockNumber()
132
- const currentBlock = await web3.eth.getBlock(currentBlockNumber)
133
- const tracks = trackIds.map((trackId) => ({
134
- track: trackId,
135
- time: currentBlock.timestamp as number
136
- }))
137
- const dirCID = updatedPlaylistImage.dirCID
94
+ let dirCID
95
+ if (playlist?.artwork?.file) {
96
+ const updatedPlaylistImage = await this.creatorNode.uploadImage(
97
+ playlist.artwork.file,
98
+ true // square
99
+ )
100
+ dirCID = updatedPlaylistImage.dirCID
101
+ }
102
+ const tracks = this.mapTimestamps(playlist.playlist_contents.track_ids)
103
+
138
104
  const metadata: PlaylistMetadata = {
139
- playlist_id: playlistId,
105
+ playlist_id: playlist.playlist_id,
140
106
  playlist_contents: { track_ids: tracks },
141
- playlist_name: playlistName,
142
- playlist_image_sizes_multihash: dirCID,
143
- description,
144
- is_album: isAlbum,
145
- is_private: isPrivate
107
+ playlist_name: playlist.playlist_name,
108
+ playlist_image_sizes_multihash: dirCID ?? playlist.cover_art_sizes, // default to cover_art_sizes for new playlists from tracks
109
+ description: playlist.description,
110
+ is_album: playlist.is_album,
111
+ is_private: playlist.is_private
146
112
  }
113
+
147
114
  const { metadataMultihash } =
148
115
  await this.creatorNode.uploadPlaylistMetadata(metadata)
149
116
  const manageEntityResponse = await this.manageEntity({
150
117
  userId: userId,
151
118
  entityType,
152
- entityId: playlistId,
119
+ entityId: playlist.playlist_id,
153
120
  action: createAction,
154
121
  metadataMultihash
155
122
  })
156
123
  const txReceipt = manageEntityResponse.txReceipt
157
124
  responseValues.blockHash = txReceipt.blockHash
158
125
  responseValues.blockNumber = txReceipt.blockNumber
159
- responseValues.playlistId = playlistId
160
126
  return responseValues
161
127
  } catch (e) {
162
128
  const error = (e as Error).message
@@ -168,22 +134,14 @@ export class EntityManager extends Base {
168
134
  /**
169
135
  * Delete a playlist using updated data contracts flow
170
136
  */
171
- async deletePlaylist({
172
- playlistId,
173
- logger = console
174
- }: {
175
- playlistId: number
176
- logger: any
177
- }): Promise<{ blockHash: any; blockNumber: any }> {
137
+ async deletePlaylist(playlistId: number): Promise<PlaylistOperationResponse> {
178
138
  const responseValues: PlaylistOperationResponse =
179
139
  this.getDefaultPlaylistReponseValues()
180
- const currentUserId: string | null =
181
- this.userStateManager.getCurrentUserId()
182
- if (!currentUserId) {
140
+ const userId: number | null = this.userStateManager.getCurrentUserId()
141
+ if (!userId) {
183
142
  responseValues.error = 'Missing current user ID'
184
143
  return responseValues
185
144
  }
186
- const userId: number = parseInt(currentUserId)
187
145
  try {
188
146
  const resp = await this.manageEntity({
189
147
  userId,
@@ -195,7 +153,6 @@ export class EntityManager extends Base {
195
153
  const txReceipt = resp.txReceipt
196
154
  responseValues.blockHash = txReceipt.blockHash
197
155
  responseValues.blockNumber = txReceipt.blockNumber
198
- responseValues.playlistId = playlistId
199
156
  return responseValues
200
157
  } catch (e) {
201
158
  const error = (e as Error).message
@@ -206,306 +163,59 @@ export class EntityManager extends Base {
206
163
 
207
164
  /**
208
165
  * Update a playlist using updated data contracts flow
209
- **/
210
- async editPlaylist({
211
- playlistId,
212
- playlistName,
213
- description,
214
- isAlbum,
215
- isPrivate,
216
- coverArt,
217
- logger = console
218
- }: {
219
- playlistId: number
220
- playlistName: Nullable<string>
221
- description: Nullable<string>
222
- isAlbum: Nullable<boolean>
223
- isPrivate: Nullable<boolean>
224
- coverArt: Nullable<string>
225
- logger: Console
226
- }): Promise<PlaylistOperationResponse> {
166
+ */
167
+ async updatePlaylist(
168
+ playlist: PlaylistParam
169
+ ): Promise<PlaylistOperationResponse> {
227
170
  const responseValues: PlaylistOperationResponse =
228
171
  this.getDefaultPlaylistReponseValues()
229
172
 
230
173
  try {
231
- const currentUserId: string | null =
232
- this.userStateManager.getCurrentUserId()
233
- if (!playlistId || playlistId === undefined) {
234
- responseValues.error = 'Missing current playlistId'
174
+ const userId: number | null = this.userStateManager.getCurrentUserId()
175
+
176
+ if (!playlist || playlist === undefined) {
177
+ responseValues.error = 'Missing current playlist'
235
178
  return responseValues
236
179
  }
237
- if (!currentUserId) {
180
+ if (!userId) {
238
181
  responseValues.error = 'Missing current user ID'
239
182
  return responseValues
240
183
  }
241
- const userId: number = parseInt(currentUserId)
242
184
  const updateAction = Action.UPDATE
243
185
  const entityType = EntityType.PLAYLIST
244
186
  this.REQUIRES(Services.CREATOR_NODE)
245
187
  let dirCID
246
- if (coverArt) {
247
- // @ts-expect-error
188
+ if (playlist?.artwork?.file) {
248
189
  const updatedPlaylistImage = await this.creatorNode.uploadImage(
249
- coverArt,
190
+ playlist.artwork.file,
250
191
  true // square
251
192
  )
252
193
  dirCID = updatedPlaylistImage.dirCID
253
194
  }
254
- const playlist = await this.getFullPlaylist(playlistId, userId)
255
- const existingPlaylistTracks = this.mapAddedTimestamps(
256
- playlist.added_timestamps
257
- )
258
- const metadata: PlaylistMetadata = {
259
- playlist_id: playlistId,
260
- playlist_contents: { track_ids: existingPlaylistTracks },
261
- playlist_name: playlistName ?? playlist.playlist_name,
262
- playlist_image_sizes_multihash: dirCID ?? playlist.cover_art,
263
- description: description ?? playlist.description,
264
- is_album: isAlbum ?? playlist.is_album,
265
- is_private: isPrivate ?? playlist.is_private
266
- }
267
- const { metadataMultihash } =
268
- await this.creatorNode.uploadPlaylistMetadata(metadata)
269
- const resp = await this.manageEntity({
270
- userId,
271
- entityType,
272
- entityId: playlistId,
273
- action: updateAction,
274
- metadataMultihash
275
- })
276
- const txReceipt = resp.txReceipt
277
- responseValues.blockHash = txReceipt.blockHash
278
- responseValues.blockNumber = txReceipt.blockNumber
279
- responseValues.playlistId = playlistId
280
- return responseValues
281
- } catch (e) {
282
- const error = (e as Error).message
283
- responseValues.error = error
284
- return responseValues
285
- }
286
- }
287
-
288
- async addPlaylistTrack({
289
- playlistId,
290
- trackId,
291
- timestamp,
292
- logger = console
293
- }: {
294
- playlistId: number
295
- trackId: number
296
- timestamp: number
297
- logger: Console
298
- }): Promise<PlaylistOperationResponse> {
299
- const responseValues: PlaylistOperationResponse =
300
- this.getDefaultPlaylistReponseValues()
301
-
302
- try {
303
- const currentUserId: string | null =
304
- this.userStateManager.getCurrentUserId()
305
- if (!playlistId || playlistId === undefined) {
306
- responseValues.error = 'Missing current playlistId'
307
- return responseValues
308
- }
309
- if (!currentUserId) {
310
- responseValues.error = 'Missing current user ID'
311
- return responseValues
312
- }
313
- const userId: number = parseInt(currentUserId)
314
- const updateAction = Action.UPDATE
315
- const entityType = EntityType.PLAYLIST
316
- this.REQUIRES(Services.CREATOR_NODE)
317
-
318
- const playlist = await this.getFullPlaylist(playlistId, userId)
319
-
320
- const updatedPlaylistTracks = this.mapAddedTimestamps(
321
- playlist.added_timestamps
322
- )
323
-
324
- updatedPlaylistTracks.push({
325
- track: trackId,
326
- time: timestamp
327
- })
328
-
329
- const metadata: PlaylistMetadata = {
330
- playlist_id: playlistId,
331
- playlist_contents: { track_ids: updatedPlaylistTracks },
332
- playlist_name: playlist.playlist_name,
333
- playlist_image_sizes_multihash: playlist.cover_art,
334
- description: playlist.description,
335
- is_album: playlist.is_album,
336
- is_private: playlist.is_private
337
- }
338
- const { metadataMultihash } =
339
- await this.creatorNode.uploadPlaylistMetadata(metadata)
340
- const resp = await this.manageEntity({
341
- userId,
342
- entityType,
343
- entityId: playlistId,
344
- action: updateAction,
345
- metadataMultihash
346
- })
347
- const txReceipt = resp.txReceipt
348
- responseValues.blockHash = txReceipt.blockHash
349
- responseValues.blockNumber = txReceipt.blockNumber
350
- responseValues.playlistId = playlistId
351
- return responseValues
352
- } catch (e) {
353
- const error = (e as Error).message
354
- responseValues.error = error
355
- return responseValues
356
- }
357
- }
358
-
359
- async deletePlaylistTrack({
360
- playlistId,
361
- trackId,
362
- timestamp,
363
- logger = console
364
- }: {
365
- playlistId: number
366
- trackId: number
367
- timestamp: number
368
- logger: Console
369
- }): Promise<PlaylistOperationResponse> {
370
- const responseValues: PlaylistOperationResponse =
371
- this.getDefaultPlaylistReponseValues()
372
-
373
- try {
374
- const currentUserId: string | null =
375
- this.userStateManager.getCurrentUserId()
376
- if (!playlistId || playlistId === undefined) {
377
- responseValues.error = 'Missing current playlistId'
378
- return responseValues
379
- }
380
- if (!currentUserId) {
381
- responseValues.error = 'Missing current user ID'
382
- return responseValues
383
- }
384
- const userId: number = parseInt(currentUserId)
385
- const updateAction = Action.UPDATE
386
- const entityType = EntityType.PLAYLIST
387
- this.REQUIRES(Services.CREATOR_NODE)
388
- const playlist = await this.getFullPlaylist(playlistId, userId)
389
-
390
- const existingPlaylistTracks = this.mapAddedTimestamps(
391
- playlist.added_timestamps
392
- )
393
-
394
- const updatedTrackIds = existingPlaylistTracks.filter(
395
- (trackObj: { track: number; metadata_time?: number; time: number }) =>
396
- (trackObj.track !== trackId &&
397
- timestamp !== trackObj.metadata_time) ??
398
- trackObj.time
399
- )
400
-
401
- const metadata: PlaylistMetadata = {
402
- playlist_id: playlistId,
403
- playlist_contents: { track_ids: updatedTrackIds },
404
- playlist_name: playlist.playlist_name,
405
- playlist_image_sizes_multihash: playlist.cover_art,
406
- description: playlist.description,
407
- is_album: playlist.is_album,
408
- is_private: playlist.is_private
409
- }
410
- const { metadataMultihash } =
411
- await this.creatorNode.uploadPlaylistMetadata(metadata)
412
- const resp = await this.manageEntity({
413
- userId,
414
- entityType,
415
- entityId: playlistId,
416
- action: updateAction,
417
- metadataMultihash
418
- })
419
- const txReceipt = resp.txReceipt
420
- responseValues.blockHash = txReceipt.blockHash
421
- responseValues.blockNumber = txReceipt.blockNumber
422
- responseValues.playlistId = playlistId
423
- return responseValues
424
- } catch (e) {
425
- const error = (e as Error).message
426
- responseValues.error = error
427
- return responseValues
428
- }
429
- }
430
-
431
- /**
432
- * Update a playlist using updated data contracts flow
433
- **/
434
- async orderPlaylist({
435
- playlistId,
436
- trackIds,
437
- logger = console
438
- }: {
439
- playlistId: number
440
- trackIds: number[]
441
- logger: Console
442
- }): Promise<PlaylistOperationResponse> {
443
- const responseValues: PlaylistOperationResponse =
444
- this.getDefaultPlaylistReponseValues()
445
-
446
- try {
447
- const currentUserId: string | null =
448
- this.userStateManager.getCurrentUserId()
449
- if (!playlistId || playlistId === undefined) {
450
- responseValues.error = 'Missing current playlistId'
451
- return responseValues
452
- }
453
- if (!currentUserId) {
454
- responseValues.error = 'Missing current user ID'
455
- return responseValues
456
- }
457
- const userId: number = parseInt(currentUserId)
458
- const updateAction = Action.UPDATE
459
- const entityType = EntityType.PLAYLIST
460
- this.REQUIRES(Services.CREATOR_NODE)
461
- const playlist = await this.getFullPlaylist(playlistId, userId)
462
195
 
463
- const existingPlaylistTracks = this.mapAddedTimestamps(
464
- playlist.added_timestamps
465
- )
466
-
467
- let trackIdsWithTimes = []
468
- const trackIdTimes = {}
469
- existingPlaylistTracks.forEach(
470
- (trackObj: { track: number; metadata_time?: number; time: number }) => {
471
- const trackId = trackObj.track
472
- const timestamp = trackObj.metadata_time ?? trackObj.time
473
- if (trackId in trackIdTimes) {
474
- trackIdTimes[trackId].push(timestamp)
475
- } else {
476
- trackIdTimes[trackId] = [timestamp]
477
- }
478
- }
479
- )
196
+ const trackIds = this.mapTimestamps(playlist.playlist_contents.track_ids)
480
197
 
481
- // new tracks default to currentBlock timestamp
482
- trackIdsWithTimes = trackIds.map((trackId: number) => ({
483
- track: trackId,
484
- time: trackIdTimes[trackId].pop()
485
- }))
486
198
  const metadata: PlaylistMetadata = {
487
- playlist_id: playlistId,
488
- playlist_contents: { track_ids: trackIdsWithTimes },
199
+ playlist_id: playlist.playlist_id,
200
+ playlist_contents: { track_ids: trackIds },
489
201
  playlist_name: playlist.playlist_name,
490
- playlist_image_sizes_multihash: playlist.cover_art,
202
+ playlist_image_sizes_multihash: dirCID ?? playlist.cover_art_sizes,
491
203
  description: playlist.description,
492
204
  is_album: playlist.is_album,
493
205
  is_private: playlist.is_private
494
206
  }
495
207
  const { metadataMultihash } =
496
208
  await this.creatorNode.uploadPlaylistMetadata(metadata)
497
-
498
209
  const resp = await this.manageEntity({
499
210
  userId,
500
211
  entityType,
501
- entityId: playlistId,
212
+ entityId: playlist.playlist_id,
502
213
  action: updateAction,
503
214
  metadataMultihash
504
215
  })
505
216
  const txReceipt = resp.txReceipt
506
217
  responseValues.blockHash = txReceipt.blockHash
507
218
  responseValues.blockNumber = txReceipt.blockNumber
508
- responseValues.playlistId = playlistId
509
219
  return responseValues
510
220
  } catch (e) {
511
221
  const error = (e as Error).message
@@ -134,5 +134,11 @@ export interface Track {
134
134
  * @memberof Track
135
135
  */
136
136
  permalink?: string;
137
+ /**
138
+ *
139
+ * @type {boolean}
140
+ * @memberof Track
141
+ */
142
+ is_streamable?: boolean;
137
143
  }
138
144
 
@@ -170,6 +170,12 @@ export interface TrackFull {
170
170
  * @memberof TrackFull
171
171
  */
172
172
  permalink?: string;
173
+ /**
174
+ *
175
+ * @type {boolean}
176
+ * @memberof TrackFull
177
+ */
178
+ is_streamable?: boolean;
173
179
  /**
174
180
  *
175
181
  * @type {number}
@@ -1,7 +1,7 @@
1
1
  import solanaWeb3, { Connection, Keypair, PublicKey } from '@solana/web3.js'
2
2
  import type BN from 'bn.js'
3
3
  import splToken from '@solana/spl-token'
4
- import anchor, { Address, Idl, Program } from '@project-serum/anchor'
4
+ import anchor, { Address, Idl, Program, Wallet } from '@project-serum/anchor'
5
5
  import { idl } from '@audius/anchor-audius-data'
6
6
 
7
7
  import { transferWAudioBalance } from './transfer'
@@ -166,7 +166,7 @@ export class SolanaWeb3Manager {
166
166
  } = this.solanaWeb3Config
167
167
 
168
168
  this.solanaClusterEndpoint = solanaClusterEndpoint
169
- this.connection = new solanaWeb3.Connection(this.solanaClusterEndpoint, {
169
+ this.connection = new Connection(this.solanaClusterEndpoint, {
170
170
  confirmTransactionInitialTimeout:
171
171
  confirmationTimeout || DEFAULT_CONNECTION_CONFIRMATION_TIMEOUT_MS
172
172
  })
@@ -230,14 +230,13 @@ export class SolanaWeb3Manager {
230
230
  this.audiusDataAdminStorageKeypairPublicKey &&
231
231
  this.audiusDataIdl
232
232
  ) {
233
- const connection = new solanaWeb3.Connection(
233
+ const connection = new Connection(
234
234
  this.solanaClusterEndpoint,
235
235
  anchor.AnchorProvider.defaultOptions()
236
236
  )
237
237
  const anchorProvider = new anchor.AnchorProvider(
238
238
  connection,
239
- // @ts-expect-error weirdness with 3rd party types
240
- solanaWeb3.Keypair.generate(),
239
+ Keypair.generate() as unknown as Wallet,
241
240
  anchor.AnchorProvider.defaultOptions()
242
241
  )
243
242
  this.anchorProgram = new anchor.Program(
@@ -3,6 +3,7 @@ import type Wallet from 'ethereumjs-wallet'
3
3
 
4
4
  export type Web3Config = {
5
5
  registryAddress: string
6
+ entityManagerAddress: string
6
7
  useExternalWeb3: boolean
7
8
  internalWeb3Config: {
8
9
  web3ProviderEndpoints: string[]