@audius/sdk 0.0.0
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.
- package/.eslintrc +38 -0
- package/.prettierrc.js +1 -0
- package/.python-version +1 -0
- package/Dockerfile +15 -0
- package/README.md +3 -0
- package/babel.config.js +3 -0
- package/data-contracts/ABIs/AdminUpgradeabilityProxy.json +132 -0
- package/data-contracts/ABIs/BaseAdminUpgradeabilityProxy.json +113 -0
- package/data-contracts/ABIs/BaseUpgradeabilityProxy.json +22 -0
- package/data-contracts/ABIs/DiscoveryProviderFactory.json +189 -0
- package/data-contracts/ABIs/DiscoveryProviderFactoryInterface.json +61 -0
- package/data-contracts/ABIs/DiscoveryProviderStorage.json +205 -0
- package/data-contracts/ABIs/DiscoveryProviderStorageInterface.json +65 -0
- package/data-contracts/ABIs/ECDSA.json +4 -0
- package/data-contracts/ABIs/IPLDBlacklistFactory.json +168 -0
- package/data-contracts/ABIs/Initializable.json +4 -0
- package/data-contracts/ABIs/Migrations.json +67 -0
- package/data-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
- package/data-contracts/ABIs/Ownable.json +79 -0
- package/data-contracts/ABIs/PlaylistFactory.json +669 -0
- package/data-contracts/ABIs/PlaylistFactoryInterface.json +42 -0
- package/data-contracts/ABIs/PlaylistStorage.json +250 -0
- package/data-contracts/ABIs/PlaylistStorageInterface.json +129 -0
- package/data-contracts/ABIs/Proxy.json +10 -0
- package/data-contracts/ABIs/Registry.json +240 -0
- package/data-contracts/ABIs/RegistryContract.json +102 -0
- package/data-contracts/ABIs/RegistryContractInterface.json +28 -0
- package/data-contracts/ABIs/RegistryInterface.json +66 -0
- package/data-contracts/ABIs/SigningLogic.json +43 -0
- package/data-contracts/ABIs/SigningLogicInitializable.json +46 -0
- package/data-contracts/ABIs/SocialFeatureFactory.json +460 -0
- package/data-contracts/ABIs/SocialFeatureStorage.json +225 -0
- package/data-contracts/ABIs/SocialFeatureStorageInterface.json +123 -0
- package/data-contracts/ABIs/TestContract.json +135 -0
- package/data-contracts/ABIs/TestContractInterface.json +19 -0
- package/data-contracts/ABIs/TestContractWithStorage.json +165 -0
- package/data-contracts/ABIs/TestContractWithStorageInterface.json +24 -0
- package/data-contracts/ABIs/TestStorage.json +144 -0
- package/data-contracts/ABIs/TestStorageInterface.json +42 -0
- package/data-contracts/ABIs/TestUserReplicaSetManager.json +432 -0
- package/data-contracts/ABIs/TrackFactory.json +391 -0
- package/data-contracts/ABIs/TrackFactoryInterface.json +73 -0
- package/data-contracts/ABIs/TrackStorage.json +223 -0
- package/data-contracts/ABIs/TrackStorageInterface.json +121 -0
- package/data-contracts/ABIs/UpgradeabilityProxy.json +37 -0
- package/data-contracts/ABIs/UserFactory.json +657 -0
- package/data-contracts/ABIs/UserFactoryInterface.json +65 -0
- package/data-contracts/ABIs/UserLibraryFactory.json +334 -0
- package/data-contracts/ABIs/UserReplicaSetManager.json +418 -0
- package/data-contracts/ABIs/UserStorage.json +233 -0
- package/data-contracts/ABIs/UserStorageInterface.json +93 -0
- package/data-contracts/signatureSchemas.ts +1236 -0
- package/dist/core.d.ts +446 -0
- package/dist/core.js +769 -0
- package/dist/core.js.map +1 -0
- package/dist/index.d.ts +689 -0
- package/dist/index.js +72850 -0
- package/dist/index.js.map +1 -0
- package/eth-contracts/ABIs/Address.json +4 -0
- package/eth-contracts/ABIs/AudiusAdminUpgradeabilityProxy.json +105 -0
- package/eth-contracts/ABIs/AudiusClaimDistributor.json +4968 -0
- package/eth-contracts/ABIs/AudiusToken.json +724 -0
- package/eth-contracts/ABIs/BaseUpgradeabilityProxy.json +23 -0
- package/eth-contracts/ABIs/Checkpointing.json +4 -0
- package/eth-contracts/ABIs/ClaimsManager.json +539 -0
- package/eth-contracts/ABIs/Context.json +11 -0
- package/eth-contracts/ABIs/DelegateManager.json +989 -0
- package/eth-contracts/ABIs/DelegateManagerV2.json +1049 -0
- package/eth-contracts/ABIs/DelegateManagerV2Bad.json +1049 -0
- package/eth-contracts/ABIs/ERC20.json +252 -0
- package/eth-contracts/ABIs/ERC20Burnable.json +287 -0
- package/eth-contracts/ABIs/ERC20Detailed.json +270 -0
- package/eth-contracts/ABIs/ERC20Mintable.json +364 -0
- package/eth-contracts/ABIs/ERC20Pausable.json +397 -0
- package/eth-contracts/ABIs/EthRewardsManager.json +174 -0
- package/eth-contracts/ABIs/Governance.json +938 -0
- package/eth-contracts/ABIs/GovernanceUpgraded.json +953 -0
- package/eth-contracts/ABIs/GovernanceV2.json +938 -0
- package/eth-contracts/ABIs/IERC20.json +200 -0
- package/eth-contracts/ABIs/Initializable.json +4 -0
- package/eth-contracts/ABIs/InitializableV2.json +14 -0
- package/eth-contracts/ABIs/Migrations.json +71 -0
- package/eth-contracts/ABIs/MinterRole.json +91 -0
- package/eth-contracts/ABIs/MockAccount.json +62 -0
- package/eth-contracts/ABIs/MockDelegateManager.json +55 -0
- package/eth-contracts/ABIs/MockStakingCaller.json +259 -0
- package/eth-contracts/ABIs/MockWormhole.json +106 -0
- package/eth-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
- package/eth-contracts/ABIs/Ownable.json +93 -0
- package/eth-contracts/ABIs/Pausable.json +150 -0
- package/eth-contracts/ABIs/PauserRole.json +91 -0
- package/eth-contracts/ABIs/Proxy.json +10 -0
- package/eth-contracts/ABIs/Registry.json +288 -0
- package/eth-contracts/ABIs/Roles.json +4 -0
- package/eth-contracts/ABIs/SafeERC20.json +4 -0
- package/eth-contracts/ABIs/SafeMath.json +4 -0
- package/eth-contracts/ABIs/ServiceProviderFactory.json +1153 -0
- package/eth-contracts/ABIs/ServiceTypeManager.json +337 -0
- package/eth-contracts/ABIs/Staking.json +555 -0
- package/eth-contracts/ABIs/StakingUpgraded.json +570 -0
- package/eth-contracts/ABIs/TestContract.json +44 -0
- package/eth-contracts/ABIs/TrustedNotifierManager.json +265 -0
- package/eth-contracts/ABIs/Uint256Helpers.json +4 -0
- package/eth-contracts/ABIs/UpgradeabilityProxy.json +40 -0
- package/eth-contracts/ABIs/Wormhole.json +45 -0
- package/eth-contracts/ABIs/WormholeClient.json +155 -0
- package/examples/file.mp3 +0 -0
- package/examples/initAudiusLibs.js +86 -0
- package/examples/initializeVersions.js +95 -0
- package/examples/pic.jpg +0 -0
- package/initScripts/configureLocalDiscProv.js +167 -0
- package/initScripts/helpers/claim.js +43 -0
- package/initScripts/helpers/distributeTokens.js +24 -0
- package/initScripts/helpers/spRegistration.js +138 -0
- package/initScripts/helpers/utils.js +34 -0
- package/initScripts/helpers/version.js +93 -0
- package/initScripts/local.js +617 -0
- package/initScripts/mainnet.js +131 -0
- package/initScripts/manageProdRelayerWallets.js +191 -0
- package/package.json +125 -0
- package/rollup.config.js +164 -0
- package/scripts/AudiusClaimDistributor.json +4968 -0
- package/scripts/Wormhole.json +155 -0
- package/scripts/addCIDToIpldBlacklist.js +124 -0
- package/scripts/circleci-test.sh +53 -0
- package/scripts/communityRewards/transferCommunityRewardsToSolana.js +222 -0
- package/scripts/ipfs.sh +58 -0
- package/scripts/migrate_contracts.sh +25 -0
- package/scripts/reset.sh +65 -0
- package/scripts/test.sh +77 -0
- package/src/api/account.js +670 -0
- package/src/api/base.js +122 -0
- package/src/api/file.js +168 -0
- package/src/api/playlist.js +328 -0
- package/src/api/rewards.d.ts +4 -0
- package/src/api/rewards.js +682 -0
- package/src/api/serviceProvider.js +154 -0
- package/src/api/track.js +604 -0
- package/src/api/user.js +888 -0
- package/src/api/user.test.js +172 -0
- package/src/constants.ts +7 -0
- package/src/core.ts +3 -0
- package/src/index.js +6 -0
- package/src/libs.d.ts +3 -0
- package/src/libs.js +619 -0
- package/src/sanityChecks/addSecondaries.js +40 -0
- package/src/sanityChecks/assignReplicaSetIfNecessary.js +10 -0
- package/src/sanityChecks/index.d.ts +9 -0
- package/src/sanityChecks/index.js +31 -0
- package/src/sanityChecks/isCreator.js +73 -0
- package/src/sanityChecks/needsRecoveryEmail.js +20 -0
- package/src/sanityChecks/rolloverNodes.js +74 -0
- package/src/sanityChecks/sanitizeNodes.js +24 -0
- package/src/sanityChecks/syncNodes.js +28 -0
- package/src/sdk/constants.ts +10 -0
- package/src/sdk/index.ts +1 -0
- package/src/sdk/oauth/Oauth.ts +265 -0
- package/src/sdk/oauth/index.ts +1 -0
- package/src/sdk/sdk.ts +102 -0
- package/src/service-selection/ServiceSelection.test.ts +320 -0
- package/src/service-selection/ServiceSelection.ts +460 -0
- package/src/service-selection/constants.ts +14 -0
- package/src/service-selection/index.ts +1 -0
- package/src/services/ABIDecoder/AudiusABIDecoder.ts +71 -0
- package/src/services/ABIDecoder/index.ts +1 -0
- package/src/services/comstock/Comstock.ts +39 -0
- package/src/services/comstock/index.ts +1 -0
- package/src/services/contracts/ContractClient.ts +227 -0
- package/src/services/contracts/GovernedContractClient.ts +53 -0
- package/src/services/contracts/ProviderSelection.ts +42 -0
- package/src/services/creatorNode/CreatorNode.ts +1065 -0
- package/src/services/creatorNode/CreatorNodeSelection.test.ts +997 -0
- package/src/services/creatorNode/CreatorNodeSelection.ts +488 -0
- package/src/services/creatorNode/constants.ts +10 -0
- package/src/services/creatorNode/index.ts +2 -0
- package/src/services/dataContracts/AudiusContracts.ts +234 -0
- package/src/services/dataContracts/IPLDBlacklistFactoryClient.ts +73 -0
- package/src/services/dataContracts/PlaylistFactoryClient.ts +370 -0
- package/src/services/dataContracts/RegistryClient.ts +95 -0
- package/src/services/dataContracts/SocialFeatureFactoryClient.ts +196 -0
- package/src/services/dataContracts/TrackFactoryClient.ts +131 -0
- package/src/services/dataContracts/UserFactoryClient.ts +351 -0
- package/src/services/dataContracts/UserLibraryFactoryClient.ts +115 -0
- package/src/services/dataContracts/UserReplicaSetManagerClient.ts +206 -0
- package/src/services/dataContracts/index.ts +1 -0
- package/src/services/discoveryProvider/DiscoveryProvider.ts +1168 -0
- package/src/services/discoveryProvider/DiscoveryProviderSelection.test.ts +536 -0
- package/src/services/discoveryProvider/DiscoveryProviderSelection.ts +383 -0
- package/src/services/discoveryProvider/constants.ts +13 -0
- package/src/services/discoveryProvider/index.ts +1 -0
- package/src/services/discoveryProvider/requests.ts +629 -0
- package/src/services/ethContracts/AudiusTokenClient.ts +163 -0
- package/src/services/ethContracts/ClaimDistributionClient.ts +45 -0
- package/src/services/ethContracts/ClaimsManagerClient.ts +102 -0
- package/src/services/ethContracts/DelegateManagerClient.ts +480 -0
- package/src/services/ethContracts/EthContracts.ts +359 -0
- package/src/services/ethContracts/EthRewardsManagerClient.ts +33 -0
- package/src/services/ethContracts/GovernanceClient.ts +451 -0
- package/src/services/ethContracts/RegistryClient.ts +33 -0
- package/src/services/ethContracts/ServiceProviderFactoryClient.ts +691 -0
- package/src/services/ethContracts/ServiceTypeManagerClient.ts +112 -0
- package/src/services/ethContracts/StakingProxyClient.ts +97 -0
- package/src/services/ethContracts/TrustedNotifierManagerClient.ts +101 -0
- package/src/services/ethContracts/WormholeClient.ts +97 -0
- package/src/services/ethContracts/index.ts +1 -0
- package/src/services/ethWeb3Manager/EthWeb3Manager.ts +239 -0
- package/src/services/ethWeb3Manager/index.ts +1 -0
- package/src/services/hedgehog/Hedgehog.ts +96 -0
- package/src/services/hedgehog/index.ts +1 -0
- package/src/services/identity/IdentityService.ts +551 -0
- package/src/services/identity/index.ts +1 -0
- package/src/services/identity/requests.ts +65 -0
- package/src/services/schemaValidator/SchemaValidator.ts +105 -0
- package/src/services/schemaValidator/index.ts +1 -0
- package/src/services/schemaValidator/schemas/trackSchema.json +267 -0
- package/src/services/schemaValidator/schemas/userSchema.json +230 -0
- package/src/services/solanaAudiusData/errors.ts +20 -0
- package/src/services/solanaAudiusData/index.ts +1189 -0
- package/src/services/solanaWeb3Manager/errors.js +101 -0
- package/src/services/solanaWeb3Manager/index.d.ts +46 -0
- package/src/services/solanaWeb3Manager/index.js +655 -0
- package/src/services/solanaWeb3Manager/padBNToUint8Array.ts +7 -0
- package/src/services/solanaWeb3Manager/rewards.js +941 -0
- package/src/services/solanaWeb3Manager/rewardsAttester.ts +1093 -0
- package/src/services/solanaWeb3Manager/tokenAccount.js +149 -0
- package/src/services/solanaWeb3Manager/transactionHandler.js +345 -0
- package/src/services/solanaWeb3Manager/transfer.js +272 -0
- package/src/services/solanaWeb3Manager/userBank.js +160 -0
- package/src/services/solanaWeb3Manager/utils.d.ts +31 -0
- package/src/services/solanaWeb3Manager/utils.js +163 -0
- package/src/services/solanaWeb3Manager/wAudio.js +28 -0
- package/src/services/solanaWeb3Manager/wAudio.test.js +30 -0
- package/src/services/web3Manager/Web3Config.ts +14 -0
- package/src/services/web3Manager/Web3Manager.ts +360 -0
- package/src/services/web3Manager/XMLHttpRequest.ts +11 -0
- package/src/services/web3Manager/index.ts +2 -0
- package/src/services/wormhole/index.js +424 -0
- package/src/types.ts +8 -0
- package/src/userStateManager.ts +53 -0
- package/src/utils/apiSigning.ts +51 -0
- package/src/utils/captcha.ts +97 -0
- package/src/utils/estimateGas.ts +64 -0
- package/src/utils/fileHasher.ts +278 -0
- package/src/utils/importContractABI.d.ts +9 -0
- package/src/utils/importContractABI.js +19 -0
- package/src/utils/index.ts +11 -0
- package/src/utils/multiProvider.ts +72 -0
- package/src/utils/network.test.ts +127 -0
- package/src/utils/network.ts +308 -0
- package/src/utils/promiseFight.test.ts +87 -0
- package/src/utils/promiseFight.ts +36 -0
- package/src/utils/signatures.ts +139 -0
- package/src/utils/types.ts +34 -0
- package/src/utils/utils.test.ts +36 -0
- package/src/utils/utils.ts +235 -0
- package/src/utils/uuid.ts +14 -0
- package/src/web3.d.ts +9 -0
- package/src/web3.js +8 -0
- package/tests/assets/static_image.png +0 -0
- package/tests/assets/static_text.txt +1 -0
- package/tests/audiusTokenClientTest.js +37 -0
- package/tests/creatorNodeTest.js +19 -0
- package/tests/fileHasherTest.js +125 -0
- package/tests/governanceTest.js +382 -0
- package/tests/helpers.js +105 -0
- package/tests/index.js +14 -0
- package/tests/playlistClientTest.js +157 -0
- package/tests/providerSelectionTest.js +241 -0
- package/tests/registryClientTest.js +19 -0
- package/tests/rewardsAttesterTest.js +373 -0
- package/tests/serviceTypeManagerClientTest.js +33 -0
- package/tests/socialFeatureClientTest.js +79 -0
- package/tests/stakingTest.js +302 -0
- package/tests/trackClientTest.js +86 -0
- package/tests/userClientTest.js +121 -0
- package/tsconfig.json +10 -0
- package/types/@audius-hedgehog/index.d.ts +39 -0
- package/types/abi-decoder/index.d.ts +41 -0
package/src/api/base.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
const Services = Object.freeze({
|
|
2
|
+
IDENTITY_SERVICE: 'Identity Service',
|
|
3
|
+
HEDGEHOG: 'Hedgehog',
|
|
4
|
+
DISCOVERY_PROVIDER: 'Discovery Provider',
|
|
5
|
+
CREATOR_NODE: 'Creator Node',
|
|
6
|
+
COMSTOCK: 'Comstock',
|
|
7
|
+
SOLANA_WEB3_MANAGER: 'Solana Web3 Manager'
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
class Base {
|
|
11
|
+
constructor (
|
|
12
|
+
userStateManager,
|
|
13
|
+
identityService,
|
|
14
|
+
hedgehog,
|
|
15
|
+
discoveryProvider,
|
|
16
|
+
web3Manager,
|
|
17
|
+
contracts,
|
|
18
|
+
ethWeb3Manager,
|
|
19
|
+
ethContracts,
|
|
20
|
+
solanaWeb3Manager,
|
|
21
|
+
anchorAudiusData,
|
|
22
|
+
wormholeClient,
|
|
23
|
+
creatorNode,
|
|
24
|
+
comstock,
|
|
25
|
+
captcha,
|
|
26
|
+
isServer,
|
|
27
|
+
logger = console
|
|
28
|
+
) {
|
|
29
|
+
this.userStateManager = userStateManager
|
|
30
|
+
this.identityService = identityService
|
|
31
|
+
this.hedgehog = hedgehog
|
|
32
|
+
this.discoveryProvider = discoveryProvider
|
|
33
|
+
this.web3Manager = web3Manager
|
|
34
|
+
this.contracts = contracts
|
|
35
|
+
this.ethWeb3Manager = ethWeb3Manager
|
|
36
|
+
this.ethContracts = ethContracts
|
|
37
|
+
this.solanaWeb3Manager = solanaWeb3Manager
|
|
38
|
+
this.anchorAudiusData = anchorAudiusData
|
|
39
|
+
this.wormholeClient = wormholeClient
|
|
40
|
+
this.creatorNode = creatorNode
|
|
41
|
+
this.comstock = comstock
|
|
42
|
+
this.captcha = captcha
|
|
43
|
+
this.isServer = isServer
|
|
44
|
+
this.logger = logger
|
|
45
|
+
|
|
46
|
+
this._serviceMapping = {
|
|
47
|
+
[Services.IDENTITY_SERVICE]: this.identityService,
|
|
48
|
+
[Services.HEDGEHOG]: this.hedgehog,
|
|
49
|
+
[Services.DISCOVERY_PROVIDER]: this.discoveryProvider,
|
|
50
|
+
[Services.CREATOR_NODE]: this.creatorNode,
|
|
51
|
+
[Services.COMSTOCK]: this.comstock,
|
|
52
|
+
[Services.SOLANA_WEB3_MANAGER]: this.solanaWeb3Manager
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
REQUIRES (...services) {
|
|
57
|
+
services.forEach(s => {
|
|
58
|
+
if (!this._serviceMapping[s]) return Base._missingService(services)
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
IS_OBJECT (o) {
|
|
63
|
+
if (typeof (o) !== 'object') return Base._invalidType('object')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
OBJECT_HAS_PROPS (o, props, requiredProps) {
|
|
67
|
+
const missingProps = []
|
|
68
|
+
props.forEach(prop => {
|
|
69
|
+
if (!Object.prototype.hasOwnProperty.call(o, prop)) missingProps.push(prop)
|
|
70
|
+
})
|
|
71
|
+
if (missingProps.length > 0) return Base._missingProps(missingProps)
|
|
72
|
+
|
|
73
|
+
const missingRequiredProps = []
|
|
74
|
+
requiredProps.forEach(prop => {
|
|
75
|
+
if (!Object.prototype.hasOwnProperty.call(o, prop) || o[prop] === '') missingRequiredProps.push(prop)
|
|
76
|
+
})
|
|
77
|
+
if (missingRequiredProps.length > 0) return Base._missingPropValues(missingRequiredProps)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
FILE_IS_VALID (file) {
|
|
81
|
+
if (this.isServer) {
|
|
82
|
+
if (!file ||
|
|
83
|
+
typeof file !== 'object' ||
|
|
84
|
+
typeof file.pipe !== 'function' ||
|
|
85
|
+
!file.readable) { return Base._invalidFile() }
|
|
86
|
+
} else {
|
|
87
|
+
if (!file ||
|
|
88
|
+
typeof file !== 'object') { return Base._missingFile() }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* ------- PRIVATE ------- */
|
|
93
|
+
|
|
94
|
+
static _missingService (...serviceNames) {
|
|
95
|
+
throw new Error(`Requires the following services: ${serviceNames.join(', ')}`)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static _invalidType (type) {
|
|
99
|
+
throw new Error(`Argument must be of type ${type}`)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static _missingProps (props) {
|
|
103
|
+
throw new Error(`Missing props ${props.join(', ')}`)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static _missingPropValues (props) {
|
|
107
|
+
throw new Error(`Missing field values ${props.join(', ')}`)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static _invalidFile () {
|
|
111
|
+
throw new Error('Expected file as readable stream')
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static _missingFile () {
|
|
115
|
+
throw new Error('Missing or malformed file')
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = {
|
|
120
|
+
Base,
|
|
121
|
+
Services
|
|
122
|
+
}
|
package/src/api/file.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
let urlJoin = require('proper-url-join')
|
|
2
|
+
if (urlJoin && urlJoin.default) urlJoin = urlJoin.default
|
|
3
|
+
|
|
4
|
+
const axios = require('axios')
|
|
5
|
+
const { Base, Services } = require('./base')
|
|
6
|
+
const { raceRequests } = require('../utils/network')
|
|
7
|
+
const retry = require('async-retry')
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Downloads a file using an element in the DOM
|
|
11
|
+
* @param {*} url
|
|
12
|
+
* @param {*} filename
|
|
13
|
+
*/
|
|
14
|
+
const downloadURL = (url, filename) => {
|
|
15
|
+
if (document) {
|
|
16
|
+
const link = document.createElement('a')
|
|
17
|
+
link.href = url
|
|
18
|
+
link.target = '_blank'
|
|
19
|
+
link.download = filename
|
|
20
|
+
link.click()
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
throw new Error('No body document found')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
class File extends Base {
|
|
27
|
+
constructor (user, ...args) {
|
|
28
|
+
super(...args)
|
|
29
|
+
|
|
30
|
+
this.User = user
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Fetches a file from Content Node with a given CID.
|
|
35
|
+
* @param {string} cid IPFS content identifier
|
|
36
|
+
* @param {Array<string>} creatorNodeGateways Content Node gateways to fetch content from
|
|
37
|
+
* @param {?function} callback callback called on each successful/failed fetch with
|
|
38
|
+
* [String, Bool](gateway, succeeded)
|
|
39
|
+
* Can be used for tracking metrics on which gateways were used.
|
|
40
|
+
*/
|
|
41
|
+
async fetchCID (
|
|
42
|
+
cid,
|
|
43
|
+
creatorNodeGateways,
|
|
44
|
+
callback = null,
|
|
45
|
+
responseType = 'blob',
|
|
46
|
+
trackId = null
|
|
47
|
+
) {
|
|
48
|
+
const urls = []
|
|
49
|
+
|
|
50
|
+
creatorNodeGateways.forEach(gateway => {
|
|
51
|
+
let gatewayWithCid = urlJoin(gateway, cid)
|
|
52
|
+
if (trackId) gatewayWithCid = urlJoin(gatewayWithCid, { query: { trackId } })
|
|
53
|
+
urls.push(gatewayWithCid)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
return retry(async (bail) => {
|
|
57
|
+
try {
|
|
58
|
+
const { response, errored } = await raceRequests(urls, callback, {
|
|
59
|
+
method: 'get',
|
|
60
|
+
responseType
|
|
61
|
+
}, /* timeout */ null)
|
|
62
|
+
|
|
63
|
+
if (!response) {
|
|
64
|
+
const allUnauthorized = errored.every(error => error.response.status === 403)
|
|
65
|
+
if (allUnauthorized) {
|
|
66
|
+
// In the case for a 403, do not retry fetching
|
|
67
|
+
bail(new Error('Unauthorized'))
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
throw new Error(`Could not fetch ${cid}`)
|
|
71
|
+
}
|
|
72
|
+
return response
|
|
73
|
+
} catch (e) {
|
|
74
|
+
// TODO: Remove this fallback logic when no more users/tracks/playlists
|
|
75
|
+
// contain "legacy" image formats (no dir cid)
|
|
76
|
+
if (cid.includes('/')) { // dirCID -- an image
|
|
77
|
+
console.debug(`Attempted to fetch image ${cid} via legacy method`)
|
|
78
|
+
// Try legacy image format
|
|
79
|
+
// Lop off anything like /480x480.jpg in the CID
|
|
80
|
+
const legacyUrls = creatorNodeGateways.map(gateway => urlJoin(gateway, cid.split('/')[0]))
|
|
81
|
+
try {
|
|
82
|
+
const { response } = await raceRequests(legacyUrls, callback, {
|
|
83
|
+
method: 'get',
|
|
84
|
+
responseType
|
|
85
|
+
}, /* timeout */ null)
|
|
86
|
+
if (!response) throw new Error(`Could not fetch ${cid} via legacy method`)
|
|
87
|
+
return response
|
|
88
|
+
} catch (e) {
|
|
89
|
+
throw new Error(`Failed to retrieve ${cid} by legacy method`)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Throw so we can retry
|
|
94
|
+
throw new Error(`Failed to retrieve ${cid}`)
|
|
95
|
+
}
|
|
96
|
+
}, {
|
|
97
|
+
minTimeout: 500,
|
|
98
|
+
maxTimeout: 4000,
|
|
99
|
+
factor: 3,
|
|
100
|
+
retries: 5,
|
|
101
|
+
onRetry: (err, i) => {
|
|
102
|
+
// eslint-disable-next-line no-console
|
|
103
|
+
console.log(`FetchCID attempt ${i} error: ${err}`)
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Fetches a file from Content Node with a given CID. Follows the same pattern
|
|
110
|
+
* as fetchCID, but resolves with a download of the file rather than
|
|
111
|
+
* returning the response content.
|
|
112
|
+
* @param {string} cid IPFS content identifier
|
|
113
|
+
* @param {Array<string>} creatorNodeGateways Content Node gateways to fetch content from
|
|
114
|
+
* @param {string?} filename optional filename for the download
|
|
115
|
+
*/
|
|
116
|
+
async downloadCID (cid, creatorNodeGateways, filename) {
|
|
117
|
+
const urls = creatorNodeGateways.map(gateway => urlJoin(gateway, cid, { query: { filename } }))
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
// Races requests and fires the download callback for the first endpoint to
|
|
121
|
+
// respond with a valid response to a `head` request.
|
|
122
|
+
const { response } = await raceRequests(urls, (url) => downloadURL(url, filename), {
|
|
123
|
+
method: 'head'
|
|
124
|
+
}, /* timeout */ 10000)
|
|
125
|
+
return response
|
|
126
|
+
} catch (e) {
|
|
127
|
+
throw new Error(`Failed to retrieve ${cid}`)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Checks if a CID exists on a Content Node.
|
|
133
|
+
* @param {string} cid IPFS content identifier
|
|
134
|
+
* @param {Array<string>} creatorNodeGateways Content Node gateways to fetch content from
|
|
135
|
+
* Eg. creatorNodeGateways = ["https://creatornode.audius.co/ipfs/", "https://creatornode2.audius.co/ipfs/"]
|
|
136
|
+
*/
|
|
137
|
+
async checkIfCidAvailable (cid, creatorNodeGateways) {
|
|
138
|
+
const exists = {}
|
|
139
|
+
|
|
140
|
+
await Promise.all(creatorNodeGateways.map(async (gateway) => {
|
|
141
|
+
try {
|
|
142
|
+
const { status } = await axios({ url: urlJoin(gateway, cid), method: 'head' })
|
|
143
|
+
exists[gateway] = status === 200
|
|
144
|
+
} catch (err) {
|
|
145
|
+
exists[gateway] = false
|
|
146
|
+
}
|
|
147
|
+
}))
|
|
148
|
+
|
|
149
|
+
return exists
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Uploads an image to the connected Content Node.
|
|
154
|
+
* @param {File} file
|
|
155
|
+
*/
|
|
156
|
+
async uploadImage (file, square, timeoutMs = null) {
|
|
157
|
+
this.REQUIRES(Services.CREATOR_NODE)
|
|
158
|
+
this.FILE_IS_VALID(file)
|
|
159
|
+
|
|
160
|
+
// Assign a creator_node_endpoint to the user if necessary
|
|
161
|
+
await this.User.assignReplicaSetIfNecessary()
|
|
162
|
+
|
|
163
|
+
const resp = await this.creatorNode.uploadImage(file, square, /* onProgress */ undefined, timeoutMs)
|
|
164
|
+
return resp
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
module.exports = File
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
const { Base, Services } = require('./base')
|
|
2
|
+
const { Utils } = require('../utils')
|
|
3
|
+
|
|
4
|
+
const MAX_PLAYLIST_LENGTH = 200
|
|
5
|
+
|
|
6
|
+
class Playlists extends Base {
|
|
7
|
+
constructor (...args) {
|
|
8
|
+
super(...args)
|
|
9
|
+
this.getPlaylists = this.getPlaylists.bind(this)
|
|
10
|
+
this.getSavedPlaylists = this.getSavedPlaylists.bind(this)
|
|
11
|
+
this.getSavedAlbums = this.getSavedAlbums.bind(this)
|
|
12
|
+
this.createPlaylist = this.createPlaylist.bind(this)
|
|
13
|
+
this.addPlaylistTrack = this.addPlaylistTrack.bind(this)
|
|
14
|
+
this.orderPlaylistTracks = this.orderPlaylistTracks.bind(this)
|
|
15
|
+
this.validateTracksInPlaylist = this.validateTracksInPlaylist.bind(this)
|
|
16
|
+
this.uploadPlaylistCoverPhoto = this.uploadPlaylistCoverPhoto.bind(this)
|
|
17
|
+
this.updatePlaylistCoverPhoto = this.updatePlaylistCoverPhoto.bind(this)
|
|
18
|
+
this.updatePlaylistName = this.updatePlaylistName.bind(this)
|
|
19
|
+
this.updatePlaylistDescription = this.updatePlaylistDescription.bind(this)
|
|
20
|
+
this.updatePlaylistPrivacy = this.updatePlaylistPrivacy.bind(this)
|
|
21
|
+
this.addPlaylistRepost = this.addPlaylistRepost.bind(this)
|
|
22
|
+
this.deletePlaylistRepost = this.deletePlaylistRepost.bind(this)
|
|
23
|
+
this.deletePlaylistTrack = this.deletePlaylistTrack.bind(this)
|
|
24
|
+
this.addPlaylistSave = this.addPlaylistSave.bind(this)
|
|
25
|
+
this.deletePlaylistSave = this.deletePlaylistSave.bind(this)
|
|
26
|
+
this.deletePlaylist = this.deletePlaylist.bind(this)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* ------- GETTERS ------- */
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* get full playlist objects, including tracks, for passed in array of playlistId
|
|
33
|
+
* @param {number} limit max # of items to return
|
|
34
|
+
* @param {number} offset offset into list to return from (for pagination)
|
|
35
|
+
* @param {Array} idsArray list of playlist ids
|
|
36
|
+
* @param {number} targetUserId the user whose playlists we're trying to get
|
|
37
|
+
* @param {boolean} withUsers whether to return users nested within the collection objects
|
|
38
|
+
* @returns {Array} array of playlist objects
|
|
39
|
+
* additional metadata fields on playlist objects:
|
|
40
|
+
* {Integer} repost_count - repost count for given playlist
|
|
41
|
+
* {Integer} save_count - save count for given playlist
|
|
42
|
+
* {Boolean} has_current_user_reposted - has current user reposted given playlist
|
|
43
|
+
* {Array} followee_reposts - followees of current user that have reposted given playlist
|
|
44
|
+
* {Boolean} has_current_user_reposted - has current user reposted given playlist
|
|
45
|
+
* {Boolean} has_current_user_saved - has current user saved given playlist
|
|
46
|
+
*/
|
|
47
|
+
async getPlaylists (limit = 100, offset = 0, idsArray = null, targetUserId = null, withUsers = false) {
|
|
48
|
+
this.REQUIRES(Services.DISCOVERY_PROVIDER)
|
|
49
|
+
return this.discoveryProvider.getPlaylists(limit, offset, idsArray, targetUserId, withUsers)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Return saved playlists for current user
|
|
54
|
+
* NOTE in returned JSON, SaveType string one of track, playlist, album
|
|
55
|
+
* @param {number} limit - max # of items to return
|
|
56
|
+
* @param {number} offset - offset into list to return from (for pagination)
|
|
57
|
+
*/
|
|
58
|
+
async getSavedPlaylists (limit = 100, offset = 0, withUsers = false) {
|
|
59
|
+
this.REQUIRES(Services.DISCOVERY_PROVIDER)
|
|
60
|
+
return this.discoveryProvider.getSavedPlaylists(limit, offset, withUsers)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Return saved albums for current user
|
|
65
|
+
* NOTE in returned JSON, SaveType string one of track, playlist, album
|
|
66
|
+
* @param {number} limit - max # of items to return
|
|
67
|
+
* @param {number} offset - offset into list to return from (for pagination)
|
|
68
|
+
*/
|
|
69
|
+
async getSavedAlbums (limit = 100, offset = 0, withUsers = false) {
|
|
70
|
+
this.REQUIRES(Services.DISCOVERY_PROVIDER)
|
|
71
|
+
return this.discoveryProvider.getSavedAlbums(limit, offset, withUsers)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* ------- SETTERS ------- */
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Creates a new playlist
|
|
78
|
+
* @param {number} userId
|
|
79
|
+
* @param {string} playlistName
|
|
80
|
+
* @param {boolean} isPrivate
|
|
81
|
+
* @param {boolean} isAlbum
|
|
82
|
+
* @param {Array<number>} trackIds
|
|
83
|
+
*/
|
|
84
|
+
async createPlaylist (userId, playlistName, isPrivate, isAlbum, trackIds) {
|
|
85
|
+
const maxInitialTracks = 50
|
|
86
|
+
const createInitialIdsArray = trackIds.slice(0, maxInitialTracks)
|
|
87
|
+
const postInitialIdsArray = trackIds.slice(maxInitialTracks)
|
|
88
|
+
let playlistId
|
|
89
|
+
let receipt = {}
|
|
90
|
+
try {
|
|
91
|
+
const response = await this.contracts.PlaylistFactoryClient.createPlaylist(
|
|
92
|
+
userId, playlistName, isPrivate, isAlbum, createInitialIdsArray
|
|
93
|
+
)
|
|
94
|
+
playlistId = response.playlistId
|
|
95
|
+
receipt = response.txReceipt
|
|
96
|
+
|
|
97
|
+
// Add remaining tracks
|
|
98
|
+
await Promise.all(postInitialIdsArray.map(trackId => {
|
|
99
|
+
return this.contracts.PlaylistFactoryClient.addPlaylistTrack(playlistId, trackId)
|
|
100
|
+
}))
|
|
101
|
+
|
|
102
|
+
// Order tracks
|
|
103
|
+
if (postInitialIdsArray.length > 0) {
|
|
104
|
+
receipt = await this.contracts.PlaylistFactoryClient.orderPlaylistTracks(playlistId, trackIds)
|
|
105
|
+
}
|
|
106
|
+
} catch (e) {
|
|
107
|
+
console.debug(`Reached libs createPlaylist catch block with playlist id ${playlistId}`)
|
|
108
|
+
console.error(e)
|
|
109
|
+
return { playlistId, error: true }
|
|
110
|
+
}
|
|
111
|
+
return { blockHash: receipt.blockHash, blockNumber: receipt.blockNumber, playlistId, error: false }
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Adds a track to a given playlist
|
|
116
|
+
* @param {number} playlistId
|
|
117
|
+
* @param {number} trackId
|
|
118
|
+
*/
|
|
119
|
+
async addPlaylistTrack (playlistId, trackId) {
|
|
120
|
+
this.REQUIRES(Services.DISCOVERY_PROVIDER)
|
|
121
|
+
|
|
122
|
+
const userId = this.userStateManager.getCurrentUserId()
|
|
123
|
+
const playlist = await this.discoveryProvider.getPlaylists(100, 0, [playlistId], userId)
|
|
124
|
+
|
|
125
|
+
// error if playlist does not exist or hasn't been indexed by discovery provider
|
|
126
|
+
if (!Array.isArray(playlist) || !playlist.length) {
|
|
127
|
+
throw new Error('Cannot add track - Playlist does not exist or has not yet been indexed by discovery provider')
|
|
128
|
+
}
|
|
129
|
+
// error if playlist already at max length
|
|
130
|
+
if (playlist[0].playlist_contents.track_ids.length >= MAX_PLAYLIST_LENGTH) {
|
|
131
|
+
throw new Error(`Cannot add track - playlist is already at max length of ${MAX_PLAYLIST_LENGTH}`)
|
|
132
|
+
}
|
|
133
|
+
return this.contracts.PlaylistFactoryClient.addPlaylistTrack(playlistId, trackId)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Reorders the tracks in a playlist
|
|
138
|
+
* @param {number} playlistId
|
|
139
|
+
* @param {Array<number>} trackIds
|
|
140
|
+
* @param {number?} retriesOverride [Optional, defaults to web3Manager.sendTransaction retries default]
|
|
141
|
+
*/
|
|
142
|
+
async orderPlaylistTracks (playlistId, trackIds, retriesOverride) {
|
|
143
|
+
this.REQUIRES(Services.DISCOVERY_PROVIDER)
|
|
144
|
+
if (!Array.isArray(trackIds)) {
|
|
145
|
+
throw new Error('Cannot order playlist - trackIds must be array')
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const userId = this.userStateManager.getCurrentUserId()
|
|
149
|
+
const playlist = await this.discoveryProvider.getPlaylists(100, 0, [playlistId], userId)
|
|
150
|
+
|
|
151
|
+
// error if playlist does not exist or hasn't been indexed by discovery provider
|
|
152
|
+
if (!Array.isArray(playlist) || !playlist.length) {
|
|
153
|
+
throw new Error('Cannot order playlist - Playlist does not exist or has not yet been indexed by discovery provider')
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const playlistTrackIds = playlist[0].playlist_contents.track_ids.map(a => a.track)
|
|
157
|
+
// error if trackIds arg array length does not match playlist length
|
|
158
|
+
if (trackIds.length !== playlistTrackIds.length) {
|
|
159
|
+
throw new Error('Cannot order playlist - trackIds length must match playlist length')
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ensure existing playlist tracks and trackIds have same content, regardless of order
|
|
163
|
+
const trackIdsSorted = [...trackIds].sort()
|
|
164
|
+
const playlistTrackIdsSorted = playlistTrackIds.sort()
|
|
165
|
+
for (let i = 0; i < trackIdsSorted.length; i++) {
|
|
166
|
+
if (trackIdsSorted[i] !== playlistTrackIdsSorted[i]) {
|
|
167
|
+
throw new Error('Cannot order playlist - trackIds must have same content as playlist tracks')
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return this.contracts.PlaylistFactoryClient.orderPlaylistTracks(playlistId, trackIds, retriesOverride)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Checks if a playlist has entered a corrupted state
|
|
176
|
+
* Check that each of the tracks within a playlist retrieved from discprov are in the onchain playlist
|
|
177
|
+
* Note: the onchain playlists stores the tracks as a mapping of track ID to track count and the
|
|
178
|
+
* track order is an event that is indexed by discprov. The track order event does not validate that the
|
|
179
|
+
* updated order of tracks has the correct track count, so a track order event w/ duplicate tracks can
|
|
180
|
+
* lead the playlist entering a corrupted state.
|
|
181
|
+
* @param {number} playlistId
|
|
182
|
+
*/
|
|
183
|
+
async validateTracksInPlaylist (playlistId) {
|
|
184
|
+
this.REQUIRES(Services.DISCOVERY_PROVIDER, Services.CREATOR_NODE)
|
|
185
|
+
|
|
186
|
+
const userId = this.userStateManager.getCurrentUserId()
|
|
187
|
+
const playlistsReponse = await this.discoveryProvider.getPlaylists(1, 0, [playlistId], userId)
|
|
188
|
+
|
|
189
|
+
// error if playlist does not exist or hasn't been indexed by discovery provider
|
|
190
|
+
if (!Array.isArray(playlistsReponse) || !playlistsReponse.length) {
|
|
191
|
+
throw new Error('Cannot validate playlist - Playlist does not exist, is private and not owned by current user or has not yet been indexed by discovery provider')
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const playlist = playlistsReponse[0]
|
|
195
|
+
const playlistTrackIds = playlist.playlist_contents.track_ids.map(a => a.track)
|
|
196
|
+
|
|
197
|
+
// Check if each track is in the playlist
|
|
198
|
+
const invalidTrackIds = []
|
|
199
|
+
for (const trackId of playlistTrackIds) {
|
|
200
|
+
const trackInPlaylist = await this.contracts.PlaylistFactoryClient.isTrackInPlaylist(playlistId, trackId)
|
|
201
|
+
if (!trackInPlaylist) invalidTrackIds.push(trackId)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
isValid: invalidTrackIds.length === 0,
|
|
206
|
+
invalidTrackIds
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Uploads a cover photo for a playlist without updating the actual playlist
|
|
212
|
+
* @param {File} coverPhotoFile the file to upload as the cover photo
|
|
213
|
+
* @return {string} CID of the uploaded cover photo
|
|
214
|
+
*/
|
|
215
|
+
async uploadPlaylistCoverPhoto (coverPhotoFile) {
|
|
216
|
+
this.REQUIRES(Services.CREATOR_NODE)
|
|
217
|
+
|
|
218
|
+
const updatedPlaylistImage = await this.creatorNode.uploadImage(
|
|
219
|
+
coverPhotoFile,
|
|
220
|
+
true // square
|
|
221
|
+
)
|
|
222
|
+
return updatedPlaylistImage.dirCID
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Updates the cover photo for a playlist
|
|
227
|
+
* @param {number} playlistId
|
|
228
|
+
* @param {File} coverPhoto
|
|
229
|
+
*/
|
|
230
|
+
async updatePlaylistCoverPhoto (playlistId, coverPhoto) {
|
|
231
|
+
this.REQUIRES(Services.CREATOR_NODE)
|
|
232
|
+
|
|
233
|
+
const updatedPlaylistImageDirCid = await this.uploadPlaylistCoverPhoto(coverPhoto, true)
|
|
234
|
+
return this.contracts.PlaylistFactoryClient.updatePlaylistCoverPhoto(
|
|
235
|
+
playlistId,
|
|
236
|
+
Utils.formatOptionalMultihash(updatedPlaylistImageDirCid)
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Updates a playlist name
|
|
242
|
+
* @param {number} playlistId
|
|
243
|
+
* @param {string} playlistName
|
|
244
|
+
*/
|
|
245
|
+
async updatePlaylistName (playlistId, playlistName) {
|
|
246
|
+
return this.contracts.PlaylistFactoryClient.updatePlaylistName(playlistId, playlistName)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Updates a playlist description
|
|
251
|
+
* @param {number} playlistId
|
|
252
|
+
* @param {string} updatedPlaylistDescription
|
|
253
|
+
*/
|
|
254
|
+
async updatePlaylistDescription (playlistId, updatedPlaylistDescription) {
|
|
255
|
+
return this.contracts.PlaylistFactoryClient.updatePlaylistDescription(playlistId, updatedPlaylistDescription)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Updates whether a playlist is public or private
|
|
260
|
+
* @param {number} playlistId
|
|
261
|
+
* @param {boolean} updatedPlaylistPrivacy
|
|
262
|
+
*/
|
|
263
|
+
async updatePlaylistPrivacy (playlistId, updatedPlaylistPrivacy) {
|
|
264
|
+
return this.contracts.PlaylistFactoryClient.updatePlaylistPrivacy(playlistId, updatedPlaylistPrivacy)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Reposts a playlist for a user
|
|
269
|
+
* @param {number} userId
|
|
270
|
+
* @param {number} playlistId
|
|
271
|
+
*/
|
|
272
|
+
async addPlaylistRepost (playlistId) {
|
|
273
|
+
const userId = this.userStateManager.getCurrentUserId()
|
|
274
|
+
return this.contracts.SocialFeatureFactoryClient.addPlaylistRepost(userId, playlistId)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Undoes a repost on a playlist for a user
|
|
279
|
+
* @param {number} userId
|
|
280
|
+
* @param {number} playlistId
|
|
281
|
+
*/
|
|
282
|
+
async deletePlaylistRepost (playlistId) {
|
|
283
|
+
const userId = this.userStateManager.getCurrentUserId()
|
|
284
|
+
return this.contracts.SocialFeatureFactoryClient.deletePlaylistRepost(userId, playlistId)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Marks a track to be deleted from a playlist. The playlist entry matching
|
|
289
|
+
* the provided timestamp is deleted in the case of duplicates.
|
|
290
|
+
* @param {number} playlistId
|
|
291
|
+
* @param {number} deletedTrackId
|
|
292
|
+
* @param {string} deletedPlaylistTimestamp parseable timestamp (to be copied from playlist metadata)
|
|
293
|
+
* @param {number?} retriesOverride [Optional, defaults to web3Manager.sendTransaction retries default]
|
|
294
|
+
*/
|
|
295
|
+
async deletePlaylistTrack (playlistId, deletedTrackId, deletedPlaylistTimestamp, retriesOverride) {
|
|
296
|
+
return this.contracts.PlaylistFactoryClient.deletePlaylistTrack(playlistId, deletedTrackId, deletedPlaylistTimestamp, retriesOverride)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Saves a playlist on behalf of a user
|
|
301
|
+
* @param {number} userId
|
|
302
|
+
* @param {number} playlistId
|
|
303
|
+
*/
|
|
304
|
+
async addPlaylistSave (playlistId) {
|
|
305
|
+
const userId = this.userStateManager.getCurrentUserId()
|
|
306
|
+
return this.contracts.UserLibraryFactoryClient.addPlaylistSave(userId, playlistId)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Unsaves a playlist on behalf of a user
|
|
311
|
+
* @param {number} userId
|
|
312
|
+
* @param {number} playlistId
|
|
313
|
+
*/
|
|
314
|
+
async deletePlaylistSave (playlistId) {
|
|
315
|
+
const userId = this.userStateManager.getCurrentUserId()
|
|
316
|
+
return this.contracts.UserLibraryFactoryClient.deletePlaylistSave(userId, playlistId)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Marks a playlist as deleted
|
|
321
|
+
* @param {number} playlistId
|
|
322
|
+
*/
|
|
323
|
+
async deletePlaylist (playlistId) {
|
|
324
|
+
return this.contracts.PlaylistFactoryClient.deletePlaylist(playlistId)
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
module.exports = Playlists
|