tunecamp 1.0.0 → 1.0.1
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/.env.local +1 -1
- package/.vercel/project.json +1 -1
- package/README.md +3 -3
- package/dist/generator/feedGenerator.js +1 -1
- package/dist/tools/generate-codes.js +3 -0
- package/dist/tools/generate-codes.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/unlock-codes.js +40 -10
- package/templates/dark/assets/unlock-codes.js +255 -0
- package/templates/default/assets/unlock-codes.js +40 -10
- package/templates/default/layout.hbs +1 -1
- package/templates/default/release.hbs +8 -1
- package/templates/minimal/assets/unlock-codes.js +255 -0
- package/templates/retro/assets/unlock-codes.js +255 -0
- package/templates/translucent/assets/unlock-codes.js +255 -0
- package/website/index.html +1 -1
package/.env.local
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# Created by Vercel CLI
|
|
2
|
-
VERCEL_OIDC_TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im1yay00MzAyZWMxYjY3MGY0OGE5OGFkNjFkYWRlNGEyM2JlNyJ9.
|
|
2
|
+
VERCEL_OIDC_TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im1yay00MzAyZWMxYjY3MGY0OGE5OGFkNjFkYWRlNGEyM2JlNyJ9.eyJpc3MiOiJodHRwczovL29pZGMudmVyY2VsLmNvbS9zY29icnUtcy10ZWFtIiwic3ViIjoib3duZXI6c2NvYnJ1LXMtdGVhbTpwcm9qZWN0OnR1bmVjYW1wOmVudmlyb25tZW50OmRldmVsb3BtZW50Iiwic2NvcGUiOiJvd25lcjpzY29icnUtcy10ZWFtOnByb2plY3Q6dHVuZWNhbXA6ZW52aXJvbm1lbnQ6ZGV2ZWxvcG1lbnQiLCJhdWQiOiJodHRwczovL3ZlcmNlbC5jb20vc2NvYnJ1LXMtdGVhbSIsIm93bmVyIjoic2NvYnJ1LXMtdGVhbSIsIm93bmVyX2lkIjoidGVhbV9RTW9SVzBMZjk5emJBRk92eXNod3JwT0ciLCJwcm9qZWN0IjoidHVuZWNhbXAiLCJwcm9qZWN0X2lkIjoicHJqX0hXRUk3MzhVd1VHb3c5TzRFZTVpSGhnaHo3d2kiLCJlbnZpcm9ubWVudCI6ImRldmVsb3BtZW50IiwicGxhbiI6ImhvYmJ5IiwidXNlcl9pZCI6IkpITk02UkMyN2lEMHMxQ1JSa3o2dEJQRSIsIm5iZiI6MTc2ODM5ODI4MSwiaWF0IjoxNzY4Mzk4MjgxLCJleHAiOjE3Njg0NDE0ODF9.jOTfVH4x952dNJBYkQ-OZ9DR6bBBMc6EVrfeWn2CTKdB0-F35KU47JP5ProKru7EVNOpQpvW-ynJf2dfayAxAtq6xmxw8XZ6_7xV2alHYzdibeOhgKYTneNKqgYttP0eJiXhIho989K-AhKMN7Mp41lBzuBydqvpkY-NFwDL9mhSMN3YDAoQSoZylnZvPhK8-Z_5nRKtnIs37y5X-ChrLCgOyzFBULcGuEaNLbgGvcWTyPZfNw4aRsOG_yYrMYdvyrjtqsyvc7F7LDilVxkJI-os_IPLGMlNQwC-GkqpLn8LcawUelPA5h_WLrAOT74PpPBfB1tRqrE9uls7tYJK7g"
|
package/.vercel/project.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"projectId":"
|
|
1
|
+
{"projectId":"prj_HWEI738UwUGow9O4Ee5iHhghz7wi","orgId":"team_QMoRW0Lf99zbAFOvyshwrpOG","projectName":"tunecamp"}
|
package/README.md
CHANGED
|
@@ -282,7 +282,7 @@ unlockCodes:
|
|
|
282
282
|
namespace: tunecamp # Optional, default: tunecamp
|
|
283
283
|
```
|
|
284
284
|
|
|
285
|
-
Protect downloads with unlock codes validated via GunDB (decentralized, no backend required). See [Unlock Codes Guide](./docs/
|
|
285
|
+
Protect downloads with unlock codes validated via GunDB (decentralized, no backend required). See [Unlock Codes Guide](./docs/UNLOCK_CODES.md) for details.
|
|
286
286
|
|
|
287
287
|
**⚠️ Important - Self-Hosting Required**: The code generation tool (`generate-codes.ts`) must be run locally on your machine where you have access to the Tunecamp source code. If you deploy only the static HTML output (e.g., to Vercel, Netlify, GitHub Pages), you won't be able to generate new codes from the deployed site - it's just static HTML.
|
|
288
288
|
|
|
@@ -377,7 +377,7 @@ templates/my-theme/
|
|
|
377
377
|
└── player.js
|
|
378
378
|
```
|
|
379
379
|
|
|
380
|
-
For detailed information about themes, see [Theme
|
|
380
|
+
For detailed information about themes, see [Theme Showcase](./docs/THEME_SHOWCASE.md).
|
|
381
381
|
|
|
382
382
|
## Generated Files
|
|
383
383
|
|
|
@@ -549,6 +549,6 @@ body {
|
|
|
549
549
|
- [Deployment Guide](./docs/DEPLOYMENT.md)
|
|
550
550
|
- [API Documentation](./docs/API.md)
|
|
551
551
|
- [Theme Showcase](./docs/THEME_SHOWCASE.md)
|
|
552
|
-
- [Unlock Codes Guide](./docs/
|
|
552
|
+
- [Unlock Codes Guide](./docs/UNLOCK_CODES.md)
|
|
553
553
|
- [Examples](./examples)
|
|
554
554
|
- [Changelog](./CHANGELOG.md)
|
|
@@ -127,7 +127,7 @@ ${coverEnclosure}
|
|
|
127
127
|
<link href="${feedUrl}" rel="self" type="application/atom+xml"/>
|
|
128
128
|
<id>${link}</id>
|
|
129
129
|
<updated>${now}</updated>
|
|
130
|
-
<generator uri="https://github.com/scobru/tunecamp" version="
|
|
130
|
+
<generator uri="https://github.com/scobru/tunecamp" version="1.0.0">Tunecamp</generator>
|
|
131
131
|
<author>
|
|
132
132
|
<name>${this.escapeXml(artistName)}</name>
|
|
133
133
|
</author>
|
|
@@ -256,8 +256,11 @@ Examples:
|
|
|
256
256
|
console.log(` enabled: true`);
|
|
257
257
|
console.log(` namespace: ${namespace}`);
|
|
258
258
|
if (keypair) {
|
|
259
|
+
console.log(` publicKey: "${keypair.pub}" # <-- REQUIRED!`);
|
|
259
260
|
console.log(`\n🔒 Codes stored in your private GunDB space`);
|
|
260
261
|
console.log(` Only you can access and manage these codes`);
|
|
262
|
+
console.log(`\n⚠️ IMPORTANT: You MUST add the publicKey to release.yaml!`);
|
|
263
|
+
console.log(` Without it, the frontend won't find your codes.`);
|
|
261
264
|
}
|
|
262
265
|
else {
|
|
263
266
|
console.log(`\n⚠️ Codes stored in public space`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-codes.js","sourceRoot":"","sources":["../../src/tools/generate-codes.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"generate-codes.js","sourceRoot":"","sources":["../../src/tools/generate-codes.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
* 2. Include this script
|
|
8
8
|
* 3. Initialize: const unlockCodes = new TunecampUnlockCodes();
|
|
9
9
|
* 4. Validate: unlockCodes.validateCode(releaseSlug, userCode).then(valid => {...})
|
|
10
|
+
*
|
|
11
|
+
* For private space (with keypair):
|
|
12
|
+
* const unlockCodes = new TunecampUnlockCodes({
|
|
13
|
+
* publicKey: 'artist-public-key-here'
|
|
14
|
+
* });
|
|
10
15
|
*/
|
|
11
16
|
|
|
12
17
|
(function() {
|
|
@@ -14,8 +19,10 @@
|
|
|
14
19
|
|
|
15
20
|
// Default public GunDB peers
|
|
16
21
|
const DEFAULT_PEERS = [
|
|
17
|
-
'https://gun
|
|
18
|
-
'https://gun
|
|
22
|
+
'https://gun.defucc.me/gun',
|
|
23
|
+
'https://gun.o8.is/gun',
|
|
24
|
+
'https://shogun-relay.scobrudot.dev/gun',
|
|
25
|
+
'https://relay.peer.ooo/gun',
|
|
19
26
|
];
|
|
20
27
|
|
|
21
28
|
/**
|
|
@@ -28,10 +35,12 @@
|
|
|
28
35
|
* @param {Object} options - Configuration options
|
|
29
36
|
* @param {Array} options.peers - GunDB peer URLs (default: public peers)
|
|
30
37
|
* @param {string} options.namespace - GunDB namespace (default: 'tunecamp')
|
|
38
|
+
* @param {string} options.publicKey - Artist's public key (for reading from private space)
|
|
31
39
|
*/
|
|
32
40
|
constructor(options = {}) {
|
|
33
41
|
this.peers = options.peers || DEFAULT_PEERS;
|
|
34
42
|
this.namespace = options.namespace || 'tunecamp';
|
|
43
|
+
this.publicKey = options.publicKey || null; // Artist's public key for private space
|
|
35
44
|
this.gun = null;
|
|
36
45
|
this.initialized = false;
|
|
37
46
|
|
|
@@ -56,7 +65,22 @@
|
|
|
56
65
|
});
|
|
57
66
|
|
|
58
67
|
this.initialized = true;
|
|
59
|
-
|
|
68
|
+
const spaceType = this.publicKey ? 'private (artist space)' : 'public';
|
|
69
|
+
console.log(`🔐 Tunecamp Unlock Codes initialized (${spaceType})`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get the root node for code storage
|
|
74
|
+
* If publicKey is set, reads from artist's user space
|
|
75
|
+
* Otherwise reads from public space
|
|
76
|
+
*/
|
|
77
|
+
getCodesRoot() {
|
|
78
|
+
if (this.publicKey) {
|
|
79
|
+
// Read from artist's private/user space using their public key
|
|
80
|
+
return this.gun.user(this.publicKey).get(this.namespace);
|
|
81
|
+
}
|
|
82
|
+
// Read from public space
|
|
83
|
+
return this.gun.get(this.namespace);
|
|
60
84
|
}
|
|
61
85
|
|
|
62
86
|
/**
|
|
@@ -106,8 +130,7 @@
|
|
|
106
130
|
const codeHash = await this.hashCode(code);
|
|
107
131
|
|
|
108
132
|
return new Promise((resolve) => {
|
|
109
|
-
this.
|
|
110
|
-
.get(this.namespace)
|
|
133
|
+
this.getCodesRoot()
|
|
111
134
|
.get('releases')
|
|
112
135
|
.get(releaseSlug)
|
|
113
136
|
.get('codes')
|
|
@@ -151,8 +174,7 @@
|
|
|
151
174
|
const codeHash = await this.hashCode(code);
|
|
152
175
|
|
|
153
176
|
return new Promise((resolve) => {
|
|
154
|
-
const codeRef = this.
|
|
155
|
-
.get(this.namespace)
|
|
177
|
+
const codeRef = this.getCodesRoot()
|
|
156
178
|
.get('releases')
|
|
157
179
|
.get(releaseSlug)
|
|
158
180
|
.get('codes')
|
|
@@ -174,7 +196,8 @@
|
|
|
174
196
|
const maxDownloads = data.maxDownloads || 1;
|
|
175
197
|
const used = downloads >= maxDownloads;
|
|
176
198
|
|
|
177
|
-
// Update the code
|
|
199
|
+
// Update the code (note: this only works if codes are in public space
|
|
200
|
+
// or if artist has write access - for private space, updates won't persist)
|
|
178
201
|
codeRef.put({
|
|
179
202
|
...data,
|
|
180
203
|
downloads,
|
|
@@ -200,8 +223,7 @@
|
|
|
200
223
|
return new Promise((resolve) => {
|
|
201
224
|
const codes = [];
|
|
202
225
|
|
|
203
|
-
this.
|
|
204
|
-
.get(this.namespace)
|
|
226
|
+
this.getCodesRoot()
|
|
205
227
|
.get('releases')
|
|
206
228
|
.get(releaseSlug)
|
|
207
229
|
.get('codes')
|
|
@@ -218,6 +240,14 @@
|
|
|
218
240
|
}, 1000);
|
|
219
241
|
});
|
|
220
242
|
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Check if using private space (artist's user space)
|
|
246
|
+
* @returns {boolean} True if using private space
|
|
247
|
+
*/
|
|
248
|
+
isPrivateSpace() {
|
|
249
|
+
return !!this.publicKey;
|
|
250
|
+
}
|
|
221
251
|
}
|
|
222
252
|
|
|
223
253
|
// Expose globally
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tunecamp Unlock Codes - GunDB Client
|
|
3
|
+
* Decentralized unlock code validation using GunDB public peers
|
|
4
|
+
*
|
|
5
|
+
* Usage for beginners:
|
|
6
|
+
* 1. Include GunDB: <script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
|
|
7
|
+
* 2. Include this script
|
|
8
|
+
* 3. Initialize: const unlockCodes = new TunecampUnlockCodes();
|
|
9
|
+
* 4. Validate: unlockCodes.validateCode(releaseSlug, userCode).then(valid => {...})
|
|
10
|
+
*
|
|
11
|
+
* For private space (with keypair):
|
|
12
|
+
* const unlockCodes = new TunecampUnlockCodes({
|
|
13
|
+
* publicKey: 'artist-public-key-here'
|
|
14
|
+
* });
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
(function() {
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
// Default public GunDB peers
|
|
21
|
+
const DEFAULT_PEERS = [
|
|
22
|
+
'https://gun.defucc.me/gun',
|
|
23
|
+
'https://gun.o8.is/gun',
|
|
24
|
+
'https://shogun-relay.scobrudot.dev/gun',
|
|
25
|
+
'https://relay.peer.ooo/gun',
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* TunecampUnlockCodes class
|
|
30
|
+
* Handles code validation and redemption via GunDB
|
|
31
|
+
*/
|
|
32
|
+
class TunecampUnlockCodes {
|
|
33
|
+
/**
|
|
34
|
+
* Initialize the unlock codes system
|
|
35
|
+
* @param {Object} options - Configuration options
|
|
36
|
+
* @param {Array} options.peers - GunDB peer URLs (default: public peers)
|
|
37
|
+
* @param {string} options.namespace - GunDB namespace (default: 'tunecamp')
|
|
38
|
+
* @param {string} options.publicKey - Artist's public key (for reading from private space)
|
|
39
|
+
*/
|
|
40
|
+
constructor(options = {}) {
|
|
41
|
+
this.peers = options.peers || DEFAULT_PEERS;
|
|
42
|
+
this.namespace = options.namespace || 'tunecamp';
|
|
43
|
+
this.publicKey = options.publicKey || null; // Artist's public key for private space
|
|
44
|
+
this.gun = null;
|
|
45
|
+
this.initialized = false;
|
|
46
|
+
|
|
47
|
+
// Initialize GunDB when script loads
|
|
48
|
+
this.init();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Initialize GunDB connection
|
|
53
|
+
*/
|
|
54
|
+
async init() {
|
|
55
|
+
// Check if Gun is available
|
|
56
|
+
if (typeof Gun === 'undefined') {
|
|
57
|
+
console.warn('GunDB not loaded. Please include gun.js before unlock-codes.js');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Initialize Gun with peers
|
|
62
|
+
this.gun = Gun({
|
|
63
|
+
peers: this.peers,
|
|
64
|
+
localStorage: true, // Use localStorage for offline caching
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
this.initialized = true;
|
|
68
|
+
const spaceType = this.publicKey ? 'private (artist space)' : 'public';
|
|
69
|
+
console.log(`🔐 Tunecamp Unlock Codes initialized (${spaceType})`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get the root node for code storage
|
|
74
|
+
* If publicKey is set, reads from artist's user space
|
|
75
|
+
* Otherwise reads from public space
|
|
76
|
+
*/
|
|
77
|
+
getCodesRoot() {
|
|
78
|
+
if (this.publicKey) {
|
|
79
|
+
// Read from artist's private/user space using their public key
|
|
80
|
+
return this.gun.user(this.publicKey).get(this.namespace);
|
|
81
|
+
}
|
|
82
|
+
// Read from public space
|
|
83
|
+
return this.gun.get(this.namespace);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Wait for Gun to be ready
|
|
88
|
+
*/
|
|
89
|
+
async waitForInit() {
|
|
90
|
+
if (this.initialized) return;
|
|
91
|
+
|
|
92
|
+
return new Promise((resolve) => {
|
|
93
|
+
const check = () => {
|
|
94
|
+
if (this.initialized) {
|
|
95
|
+
resolve();
|
|
96
|
+
} else {
|
|
97
|
+
setTimeout(check, 100);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
check();
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Hash a code for secure storage
|
|
106
|
+
* @param {string} code - The unlock code
|
|
107
|
+
* @returns {string} Hashed code
|
|
108
|
+
*/
|
|
109
|
+
async hashCode(code) {
|
|
110
|
+
const encoder = new TextEncoder();
|
|
111
|
+
const data = encoder.encode(code.toLowerCase().trim());
|
|
112
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
113
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
114
|
+
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Validate an unlock code
|
|
119
|
+
* @param {string} releaseSlug - The release identifier
|
|
120
|
+
* @param {string} code - The unlock code entered by user
|
|
121
|
+
* @returns {Promise<Object>} Validation result
|
|
122
|
+
*/
|
|
123
|
+
async validateCode(releaseSlug, code) {
|
|
124
|
+
await this.waitForInit();
|
|
125
|
+
|
|
126
|
+
if (!this.gun) {
|
|
127
|
+
return { valid: false, error: 'GunDB not initialized' };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const codeHash = await this.hashCode(code);
|
|
131
|
+
|
|
132
|
+
return new Promise((resolve) => {
|
|
133
|
+
this.getCodesRoot()
|
|
134
|
+
.get('releases')
|
|
135
|
+
.get(releaseSlug)
|
|
136
|
+
.get('codes')
|
|
137
|
+
.get(codeHash)
|
|
138
|
+
.once((data) => {
|
|
139
|
+
if (!data) {
|
|
140
|
+
resolve({ valid: false, error: 'Invalid code' });
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (data.used) {
|
|
145
|
+
resolve({ valid: false, error: 'Code already used' });
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
resolve({
|
|
150
|
+
valid: true,
|
|
151
|
+
data: {
|
|
152
|
+
maxDownloads: data.maxDownloads || 1,
|
|
153
|
+
currentDownloads: data.downloads || 0,
|
|
154
|
+
expiresAt: data.expiresAt,
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Redeem a code (mark as used)
|
|
163
|
+
* @param {string} releaseSlug - The release identifier
|
|
164
|
+
* @param {string} code - The unlock code
|
|
165
|
+
* @returns {Promise<Object>} Redemption result
|
|
166
|
+
*/
|
|
167
|
+
async redeemCode(releaseSlug, code) {
|
|
168
|
+
await this.waitForInit();
|
|
169
|
+
|
|
170
|
+
if (!this.gun) {
|
|
171
|
+
return { success: false, error: 'GunDB not initialized' };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const codeHash = await this.hashCode(code);
|
|
175
|
+
|
|
176
|
+
return new Promise((resolve) => {
|
|
177
|
+
const codeRef = this.getCodesRoot()
|
|
178
|
+
.get('releases')
|
|
179
|
+
.get(releaseSlug)
|
|
180
|
+
.get('codes')
|
|
181
|
+
.get(codeHash);
|
|
182
|
+
|
|
183
|
+
codeRef.once((data) => {
|
|
184
|
+
if (!data) {
|
|
185
|
+
resolve({ success: false, error: 'Invalid code' });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (data.used) {
|
|
190
|
+
resolve({ success: false, error: 'Code already used' });
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Check max downloads
|
|
195
|
+
const downloads = (data.downloads || 0) + 1;
|
|
196
|
+
const maxDownloads = data.maxDownloads || 1;
|
|
197
|
+
const used = downloads >= maxDownloads;
|
|
198
|
+
|
|
199
|
+
// Update the code (note: this only works if codes are in public space
|
|
200
|
+
// or if artist has write access - for private space, updates won't persist)
|
|
201
|
+
codeRef.put({
|
|
202
|
+
...data,
|
|
203
|
+
downloads,
|
|
204
|
+
used,
|
|
205
|
+
lastUsedAt: Date.now(),
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
resolve({
|
|
209
|
+
success: true,
|
|
210
|
+
downloadsRemaining: maxDownloads - downloads
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Get release info (for artists to check their codes)
|
|
218
|
+
* @param {string} releaseSlug - The release identifier
|
|
219
|
+
*/
|
|
220
|
+
async getReleaseInfo(releaseSlug) {
|
|
221
|
+
await this.waitForInit();
|
|
222
|
+
|
|
223
|
+
return new Promise((resolve) => {
|
|
224
|
+
const codes = [];
|
|
225
|
+
|
|
226
|
+
this.getCodesRoot()
|
|
227
|
+
.get('releases')
|
|
228
|
+
.get(releaseSlug)
|
|
229
|
+
.get('codes')
|
|
230
|
+
.map()
|
|
231
|
+
.once((data, key) => {
|
|
232
|
+
if (data) {
|
|
233
|
+
codes.push({ hash: key, ...data });
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Give it some time to collect all codes
|
|
238
|
+
setTimeout(() => {
|
|
239
|
+
resolve(codes);
|
|
240
|
+
}, 1000);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Check if using private space (artist's user space)
|
|
246
|
+
* @returns {boolean} True if using private space
|
|
247
|
+
*/
|
|
248
|
+
isPrivateSpace() {
|
|
249
|
+
return !!this.publicKey;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Expose globally
|
|
254
|
+
window.TunecampUnlockCodes = TunecampUnlockCodes;
|
|
255
|
+
})();
|
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
* 2. Include this script
|
|
8
8
|
* 3. Initialize: const unlockCodes = new TunecampUnlockCodes();
|
|
9
9
|
* 4. Validate: unlockCodes.validateCode(releaseSlug, userCode).then(valid => {...})
|
|
10
|
+
*
|
|
11
|
+
* For private space (with keypair):
|
|
12
|
+
* const unlockCodes = new TunecampUnlockCodes({
|
|
13
|
+
* publicKey: 'artist-public-key-here'
|
|
14
|
+
* });
|
|
10
15
|
*/
|
|
11
16
|
|
|
12
17
|
(function() {
|
|
@@ -14,8 +19,10 @@
|
|
|
14
19
|
|
|
15
20
|
// Default public GunDB peers
|
|
16
21
|
const DEFAULT_PEERS = [
|
|
17
|
-
'https://gun
|
|
18
|
-
'https://gun
|
|
22
|
+
'https://gun.defucc.me/gun',
|
|
23
|
+
'https://gun.o8.is/gun',
|
|
24
|
+
'https://shogun-relay.scobrudot.dev/gun',
|
|
25
|
+
'https://relay.peer.ooo/gun',
|
|
19
26
|
];
|
|
20
27
|
|
|
21
28
|
/**
|
|
@@ -28,10 +35,12 @@
|
|
|
28
35
|
* @param {Object} options - Configuration options
|
|
29
36
|
* @param {Array} options.peers - GunDB peer URLs (default: public peers)
|
|
30
37
|
* @param {string} options.namespace - GunDB namespace (default: 'tunecamp')
|
|
38
|
+
* @param {string} options.publicKey - Artist's public key (for reading from private space)
|
|
31
39
|
*/
|
|
32
40
|
constructor(options = {}) {
|
|
33
41
|
this.peers = options.peers || DEFAULT_PEERS;
|
|
34
42
|
this.namespace = options.namespace || 'tunecamp';
|
|
43
|
+
this.publicKey = options.publicKey || null; // Artist's public key for private space
|
|
35
44
|
this.gun = null;
|
|
36
45
|
this.initialized = false;
|
|
37
46
|
|
|
@@ -56,7 +65,22 @@
|
|
|
56
65
|
});
|
|
57
66
|
|
|
58
67
|
this.initialized = true;
|
|
59
|
-
|
|
68
|
+
const spaceType = this.publicKey ? 'private (artist space)' : 'public';
|
|
69
|
+
console.log(`🔐 Tunecamp Unlock Codes initialized (${spaceType})`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get the root node for code storage
|
|
74
|
+
* If publicKey is set, reads from artist's user space
|
|
75
|
+
* Otherwise reads from public space
|
|
76
|
+
*/
|
|
77
|
+
getCodesRoot() {
|
|
78
|
+
if (this.publicKey) {
|
|
79
|
+
// Read from artist's private/user space using their public key
|
|
80
|
+
return this.gun.user(this.publicKey).get(this.namespace);
|
|
81
|
+
}
|
|
82
|
+
// Read from public space
|
|
83
|
+
return this.gun.get(this.namespace);
|
|
60
84
|
}
|
|
61
85
|
|
|
62
86
|
/**
|
|
@@ -106,8 +130,7 @@
|
|
|
106
130
|
const codeHash = await this.hashCode(code);
|
|
107
131
|
|
|
108
132
|
return new Promise((resolve) => {
|
|
109
|
-
this.
|
|
110
|
-
.get(this.namespace)
|
|
133
|
+
this.getCodesRoot()
|
|
111
134
|
.get('releases')
|
|
112
135
|
.get(releaseSlug)
|
|
113
136
|
.get('codes')
|
|
@@ -151,8 +174,7 @@
|
|
|
151
174
|
const codeHash = await this.hashCode(code);
|
|
152
175
|
|
|
153
176
|
return new Promise((resolve) => {
|
|
154
|
-
const codeRef = this.
|
|
155
|
-
.get(this.namespace)
|
|
177
|
+
const codeRef = this.getCodesRoot()
|
|
156
178
|
.get('releases')
|
|
157
179
|
.get(releaseSlug)
|
|
158
180
|
.get('codes')
|
|
@@ -174,7 +196,8 @@
|
|
|
174
196
|
const maxDownloads = data.maxDownloads || 1;
|
|
175
197
|
const used = downloads >= maxDownloads;
|
|
176
198
|
|
|
177
|
-
// Update the code
|
|
199
|
+
// Update the code (note: this only works if codes are in public space
|
|
200
|
+
// or if artist has write access - for private space, updates won't persist)
|
|
178
201
|
codeRef.put({
|
|
179
202
|
...data,
|
|
180
203
|
downloads,
|
|
@@ -200,8 +223,7 @@
|
|
|
200
223
|
return new Promise((resolve) => {
|
|
201
224
|
const codes = [];
|
|
202
225
|
|
|
203
|
-
this.
|
|
204
|
-
.get(this.namespace)
|
|
226
|
+
this.getCodesRoot()
|
|
205
227
|
.get('releases')
|
|
206
228
|
.get(releaseSlug)
|
|
207
229
|
.get('codes')
|
|
@@ -218,6 +240,14 @@
|
|
|
218
240
|
}, 1000);
|
|
219
241
|
});
|
|
220
242
|
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Check if using private space (artist's user space)
|
|
246
|
+
* @returns {boolean} True if using private space
|
|
247
|
+
*/
|
|
248
|
+
isPrivateSpace() {
|
|
249
|
+
return !!this.publicKey;
|
|
250
|
+
}
|
|
221
251
|
}
|
|
222
252
|
|
|
223
253
|
// Expose globally
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<meta name="description" content="{{catalog.description}}">
|
|
10
10
|
{{/if}}
|
|
11
11
|
<!-- Tunecamp Metadata (for community registry) -->
|
|
12
|
-
<meta name="generator" content="Tunecamp
|
|
12
|
+
<meta name="generator" content="Tunecamp 1.0.0">
|
|
13
13
|
<meta name="tunecamp-title" content="{{catalog.title}}">
|
|
14
14
|
{{#if artist}}
|
|
15
15
|
<meta name="tunecamp-artist" content="{{artist.name}}">
|
|
@@ -208,6 +208,7 @@
|
|
|
208
208
|
(function () {
|
|
209
209
|
const releaseSlug = '{{release.slug}}';
|
|
210
210
|
const namespace = '{{#if release.config.unlockCodes.namespace}}{{release.config.unlockCodes.namespace}}{{else}}tunecamp{{/if}}';
|
|
211
|
+
const publicKey = '{{#if release.config.unlockCodes.publicKey}}{{release.config.unlockCodes.publicKey}}{{/if}}';
|
|
211
212
|
|
|
212
213
|
// Initialize unlock codes
|
|
213
214
|
let unlockCodes;
|
|
@@ -221,7 +222,13 @@
|
|
|
221
222
|
}
|
|
222
223
|
|
|
223
224
|
// Initialize GunDB unlock codes
|
|
224
|
-
|
|
225
|
+
// If publicKey is set, codes are read from artist's private space
|
|
226
|
+
const options = { namespace };
|
|
227
|
+
if (publicKey) {
|
|
228
|
+
options.publicKey = publicKey;
|
|
229
|
+
console.log('🔐 Using artist private space for unlock codes');
|
|
230
|
+
}
|
|
231
|
+
unlockCodes = new TunecampUnlockCodes(options);
|
|
225
232
|
|
|
226
233
|
// Bind form events
|
|
227
234
|
const input = document.getElementById('unlockCodeInput');
|