import type { UploadResponse } from '../../services/Storage/types' import { decodeHashId } from '../../utils/hashId' import { BaseAPI, type CreateTrackRequestBody, type UpdateTrackRequestBody } from '../generated/default' import type { PlaylistTrackMetadata } from '../playlists/types' export class TrackUploadHelper extends BaseAPI { public async generateId(type: 'track' | 'playlist') { const response = await this.request({ path: `/${type}s/unclaimed_id`, method: 'GET', headers: {}, query: { noCache: Math.floor(Math.random() * 1000).toString() } }) const { data } = await response.json() const id = decodeHashId(data) if (id === null) { throw new Error(`Could not generate ${type} id`) } return id } public transformTrackUploadMetadata< // TrackMetadata is a less strict type // only requiring the fields used in this function. // This supports both track/playlist uploads and edits TrackMetadata extends Pick< PlaylistTrackMetadata, 'isStreamGated' | 'streamConditions' | 'isUnlisted' | 'fieldVisibility' > >(inputMetadata: TrackMetadata, userId: number) { const metadata = { ...inputMetadata, ownerId: userId } const isStreamGated = metadata.isStreamGated const isUsdcGated = 'usdc_purchase' in (metadata.streamConditions ?? {}) const isUnlisted = metadata.isUnlisted // If track is stream gated and not usdc purchase gated, set remixes to false if (isStreamGated && !isUsdcGated && metadata.fieldVisibility) { metadata.fieldVisibility.remixes = false } // If track is public, set required visibility fields to true if (!isUnlisted) { metadata.fieldVisibility = { ...metadata.fieldVisibility, genre: true, mood: true, tags: true, share: true, playCount: true } } return metadata } public transformTrackUploadMetadataV2< T extends CreateTrackRequestBody | UpdateTrackRequestBody >(inputMetadata: T, userId: number): T { const metadata: T = { ...inputMetadata, ownerId: userId } const isStreamGated = metadata.streamConditions !== undefined const isUsdcGated = 'usdc_purchase' in (metadata.streamConditions ?? {}) const isUnlisted = metadata.isUnlisted // If track is stream gated and not usdc purchase gated, set remixes to false if (isStreamGated && !isUsdcGated && metadata.fieldVisibility) { metadata.fieldVisibility.remixes = false } // If track is public, set required visibility fields to true if (!isUnlisted) { metadata.fieldVisibility = { remixes: true, // default, but overwritten ...metadata.fieldVisibility, genre: true, mood: true, tags: true, share: true, playCount: true } } return metadata } public populateTrackMetadataWithUploadResponseV2< T extends CreateTrackRequestBody | UpdateTrackRequestBody >( trackMetadata: T, audioResponse?: UploadResponse, coverArtResponse?: UploadResponse ): T { let updated = { ...trackMetadata } if (audioResponse) { updated = { ...updated, trackCid: audioResponse.results['320'], previewCid: trackMetadata.previewStartSeconds !== undefined && trackMetadata.previewStartSeconds !== null ? audioResponse.results[ `320_preview|${trackMetadata.previewStartSeconds}` ] : trackMetadata.previewCid, origFileCid: audioResponse.orig_file_cid, origFilename: audioResponse.orig_filename || trackMetadata.origFilename, duration: parseInt(audioResponse?.probe?.format?.duration ?? '0', 10), bpm: audioResponse.audio_analysis_results?.bpm ? audioResponse.audio_analysis_results.bpm : trackMetadata.bpm, musicalKey: audioResponse.audio_analysis_results?.key ? audioResponse.audio_analysis_results.key : trackMetadata.musicalKey } } if (coverArtResponse) { updated = { ...updated, coverArtSizes: coverArtResponse.orig_file_cid } } return updated } public populateTrackMetadataWithUploadResponse( trackMetadata: Partial, audioResponse?: UploadResponse, coverArtResponse?: UploadResponse ) { let updated: Partial & { coverArtSizes?: string } = { ...trackMetadata } if (audioResponse) { updated = { ...updated, trackCid: audioResponse.results['320'], previewCid: trackMetadata.previewStartSeconds !== undefined && trackMetadata.previewStartSeconds !== null ? audioResponse.results[ `320_preview|${trackMetadata.previewStartSeconds}` ] : trackMetadata.previewCid, origFileCid: audioResponse.orig_file_cid, origFilename: audioResponse.orig_filename || trackMetadata.origFilename, audioUploadId: audioResponse.id, duration: parseInt(audioResponse?.probe?.format?.duration ?? '0', 10), bpm: audioResponse.audio_analysis_results?.bpm ? audioResponse.audio_analysis_results.bpm : trackMetadata.bpm, musicalKey: audioResponse.audio_analysis_results?.key ? audioResponse.audio_analysis_results.key : trackMetadata.musicalKey, audioAnalysisErrorCount: audioResponse.audio_analysis_error_count || 0 } } if (coverArtResponse) { updated = { ...updated, coverArtSizes: coverArtResponse.orig_file_cid } } return updated } }