tunecamp 1.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.
Files changed (132) hide show
  1. package/.env.local +2 -0
  2. package/.vercel/README.txt +11 -0
  3. package/.vercel/project.json +1 -0
  4. package/LICENSE +22 -0
  5. package/README.md +554 -0
  6. package/dist/cli.d.ts +6 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +172 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/generator/embedGenerator.d.ts +38 -0
  11. package/dist/generator/embedGenerator.d.ts.map +1 -0
  12. package/dist/generator/embedGenerator.js +92 -0
  13. package/dist/generator/embedGenerator.js.map +1 -0
  14. package/dist/generator/feedGenerator.d.ts +50 -0
  15. package/dist/generator/feedGenerator.d.ts.map +1 -0
  16. package/dist/generator/feedGenerator.js +167 -0
  17. package/dist/generator/feedGenerator.js.map +1 -0
  18. package/dist/generator/podcastFeedGenerator.d.ts +54 -0
  19. package/dist/generator/podcastFeedGenerator.d.ts.map +1 -0
  20. package/dist/generator/podcastFeedGenerator.js +173 -0
  21. package/dist/generator/podcastFeedGenerator.js.map +1 -0
  22. package/dist/generator/proceduralCoverGenerator.d.ts +51 -0
  23. package/dist/generator/proceduralCoverGenerator.d.ts.map +1 -0
  24. package/dist/generator/proceduralCoverGenerator.js +228 -0
  25. package/dist/generator/proceduralCoverGenerator.js.map +1 -0
  26. package/dist/generator/siteGenerator.d.ts +55 -0
  27. package/dist/generator/siteGenerator.d.ts.map +1 -0
  28. package/dist/generator/siteGenerator.js +539 -0
  29. package/dist/generator/siteGenerator.js.map +1 -0
  30. package/dist/generator/templateEngine.d.ts +13 -0
  31. package/dist/generator/templateEngine.d.ts.map +1 -0
  32. package/dist/generator/templateEngine.js +146 -0
  33. package/dist/generator/templateEngine.js.map +1 -0
  34. package/dist/index.d.ts +12 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +32 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/parser/catalogParser.d.ts +13 -0
  39. package/dist/parser/catalogParser.d.ts.map +1 -0
  40. package/dist/parser/catalogParser.js +120 -0
  41. package/dist/parser/catalogParser.js.map +1 -0
  42. package/dist/tools/generate-codes.d.ts +14 -0
  43. package/dist/tools/generate-codes.d.ts.map +1 -0
  44. package/dist/tools/generate-codes.js +274 -0
  45. package/dist/tools/generate-codes.js.map +1 -0
  46. package/dist/tools/generate-sea-pair.d.ts +14 -0
  47. package/dist/tools/generate-sea-pair.d.ts.map +1 -0
  48. package/dist/tools/generate-sea-pair.js +111 -0
  49. package/dist/tools/generate-sea-pair.js.map +1 -0
  50. package/dist/types/index.d.ts +117 -0
  51. package/dist/types/index.d.ts.map +1 -0
  52. package/dist/types/index.js +5 -0
  53. package/dist/types/index.js.map +1 -0
  54. package/dist/utils/audioUtils.d.ts +9 -0
  55. package/dist/utils/audioUtils.d.ts.map +1 -0
  56. package/dist/utils/audioUtils.js +67 -0
  57. package/dist/utils/audioUtils.js.map +1 -0
  58. package/dist/utils/configUtils.d.ts +11 -0
  59. package/dist/utils/configUtils.d.ts.map +1 -0
  60. package/dist/utils/configUtils.js +50 -0
  61. package/dist/utils/configUtils.js.map +1 -0
  62. package/dist/utils/fileUtils.d.ts +14 -0
  63. package/dist/utils/fileUtils.d.ts.map +1 -0
  64. package/dist/utils/fileUtils.js +73 -0
  65. package/dist/utils/fileUtils.js.map +1 -0
  66. package/examples/artist-free/README.md +36 -0
  67. package/examples/artist-paycurtain/README.md +49 -0
  68. package/examples/label/README.md +33 -0
  69. package/gundb-keypair.json +8 -0
  70. package/logo.svg +30 -0
  71. package/package-lock.json +1176 -0
  72. package/package.json +42 -0
  73. package/public/assets/community-registry.js +291 -0
  74. package/public/assets/download-stats.js +263 -0
  75. package/public/assets/player.js +219 -0
  76. package/public/assets/style.css +1170 -0
  77. package/public/assets/theme-widget.js +353 -0
  78. package/public/assets/unlock-codes.js +225 -0
  79. package/public/atom.xml +22 -0
  80. package/public/catalog.m3u +3 -0
  81. package/public/feed.xml +22 -0
  82. package/public/image.png +0 -0
  83. package/public/index.html +249 -0
  84. package/public/logo.svg +30 -0
  85. package/public/releases/chirichetto/Homologo - Chirichetto.wav +0 -0
  86. package/public/releases/chirichetto/cover.png +0 -0
  87. package/public/releases/chirichetto/embed-code.txt +16 -0
  88. package/public/releases/chirichetto/embed-compact.txt +8 -0
  89. package/public/releases/chirichetto/embed.html +39 -0
  90. package/public/releases/chirichetto/index.html +389 -0
  91. package/public/releases/chirichetto/playlist.m3u +3 -0
  92. package/templates/dark/assets/community-registry.js +291 -0
  93. package/templates/dark/assets/download-stats.js +263 -0
  94. package/templates/dark/assets/player.js +219 -0
  95. package/templates/dark/assets/style.css +740 -0
  96. package/templates/dark/index.hbs +73 -0
  97. package/templates/dark/layout.hbs +84 -0
  98. package/templates/dark/release.hbs +212 -0
  99. package/templates/default/assets/community-registry.js +291 -0
  100. package/templates/default/assets/download-stats.js +263 -0
  101. package/templates/default/assets/player.js +219 -0
  102. package/templates/default/assets/style.css +1170 -0
  103. package/templates/default/assets/theme-widget.js +353 -0
  104. package/templates/default/assets/unlock-codes.js +225 -0
  105. package/templates/default/index.hbs +188 -0
  106. package/templates/default/layout.hbs +117 -0
  107. package/templates/default/release.hbs +553 -0
  108. package/templates/minimal/assets/community-registry.js +291 -0
  109. package/templates/minimal/assets/download-stats.js +263 -0
  110. package/templates/minimal/assets/player.js +219 -0
  111. package/templates/minimal/assets/style.css +796 -0
  112. package/templates/minimal/index.hbs +73 -0
  113. package/templates/minimal/layout.hbs +84 -0
  114. package/templates/minimal/release.hbs +212 -0
  115. package/templates/retro/assets/community-registry.js +291 -0
  116. package/templates/retro/assets/download-stats.js +263 -0
  117. package/templates/retro/assets/player.js +219 -0
  118. package/templates/retro/assets/style.css +872 -0
  119. package/templates/retro/index.hbs +73 -0
  120. package/templates/retro/layout.hbs +84 -0
  121. package/templates/retro/release.hbs +212 -0
  122. package/templates/translucent/assets/community-registry.js +291 -0
  123. package/templates/translucent/assets/download-stats.js +263 -0
  124. package/templates/translucent/assets/player.js +219 -0
  125. package/templates/translucent/assets/style.css +1352 -0
  126. package/templates/translucent/index.hbs +73 -0
  127. package/templates/translucent/layout.hbs +84 -0
  128. package/templates/translucent/release.hbs +212 -0
  129. package/website/community.html +492 -0
  130. package/website/index.html +195 -0
  131. package/website/styles.css +396 -0
  132. package/website/tunecamp.svg +30 -0
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Tunecamp SEA Pair Generator
4
+ * Generates a GunDB SEA (Secure Encryption Algorithm) key pair for authentication
5
+ *
6
+ * Usage:
7
+ * npx ts-node src/tools/generate-sea-pair.ts [options]
8
+ *
9
+ * Examples:
10
+ * npx ts-node src/tools/generate-sea-pair.ts
11
+ * npx ts-node src/tools/generate-sea-pair.ts --output ./gundb-keypair.json
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=generate-sea-pair.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-sea-pair.d.ts","sourceRoot":"","sources":["../../src/tools/generate-sea-pair.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG"}
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Tunecamp SEA Pair Generator
4
+ * Generates a GunDB SEA (Secure Encryption Algorithm) key pair for authentication
5
+ *
6
+ * Usage:
7
+ * npx ts-node src/tools/generate-sea-pair.ts [options]
8
+ *
9
+ * Examples:
10
+ * npx ts-node src/tools/generate-sea-pair.ts
11
+ * npx ts-node src/tools/generate-sea-pair.ts --output ./gundb-keypair.json
12
+ */
13
+ import Gun from 'gun';
14
+ import SEA from 'gun/sea.js';
15
+ import fs from 'fs';
16
+ import path from 'path';
17
+ const DEFAULT_OUTPUT_FILE = './gundb-keypair.json';
18
+ /**
19
+ * Generate SEA key pair
20
+ */
21
+ async function generateSEAPair() {
22
+ // Initialize Gun to get SEA
23
+ const gun = Gun();
24
+ // Wait for SEA to be ready
25
+ await new Promise(resolve => setTimeout(resolve, 500));
26
+ // Generate pair
27
+ return new Promise((resolve, reject) => {
28
+ SEA.pair((data) => {
29
+ if (!data || !data.pub || !data.priv || !data.epub || !data.epriv) {
30
+ reject(new Error('Failed to generate SEA pair'));
31
+ return;
32
+ }
33
+ resolve(data);
34
+ });
35
+ });
36
+ }
37
+ /**
38
+ * Main CLI
39
+ */
40
+ async function main() {
41
+ const args = process.argv.slice(2);
42
+ if (args.includes('--help') || args.includes('-h')) {
43
+ console.log(`
44
+ Tunecamp SEA Pair Generator
45
+
46
+ Generates a GunDB SEA (Secure Encryption Algorithm) key pair for secure authentication.
47
+ This pair allows you to write to your private GunDB space instead of public space.
48
+
49
+ Usage:
50
+ npx ts-node src/tools/generate-sea-pair.ts [options]
51
+
52
+ Options:
53
+ --output <file> Output file path (default: ./gundb-keypair.json)
54
+ --help, -h Show this help message
55
+
56
+ Examples:
57
+ npx ts-node src/tools/generate-sea-pair.ts
58
+ npx ts-node src/tools/generate-sea-pair.ts --output ./my-keypair.json
59
+
60
+ Security Notes:
61
+ - Keep this file secure and never commit it to version control
62
+ - Add gundb-keypair.json to your .gitignore
63
+ - This pair gives full access to your private GunDB space
64
+ - If compromised, generate a new pair and update your configuration
65
+ `);
66
+ process.exit(0);
67
+ }
68
+ const outputIndex = args.indexOf('--output');
69
+ const outputFile = outputIndex >= 0 && args[outputIndex + 1]
70
+ ? args[outputIndex + 1]
71
+ : DEFAULT_OUTPUT_FILE;
72
+ try {
73
+ console.log('\n🔑 Tunecamp SEA Pair Generator');
74
+ console.log('================================\n');
75
+ console.log('Generating SEA key pair...');
76
+ const pair = await generateSEAPair();
77
+ // Create output object with metadata
78
+ const output = {
79
+ generated: new Date().toISOString(),
80
+ pub: pair.pub,
81
+ priv: pair.priv,
82
+ epub: pair.epub,
83
+ epriv: pair.epriv,
84
+ note: 'Keep this file secure! Never commit it to version control.',
85
+ };
86
+ // Ensure directory exists
87
+ const outputDir = path.dirname(outputFile);
88
+ if (outputDir !== '.' && !fs.existsSync(outputDir)) {
89
+ fs.mkdirSync(outputDir, { recursive: true });
90
+ }
91
+ // Write to file
92
+ fs.writeFileSync(outputFile, JSON.stringify(output, null, 2));
93
+ console.log(`\n✅ SEA pair generated successfully!`);
94
+ console.log(`\n📁 Saved to: ${path.resolve(outputFile)}`);
95
+ console.log(`\n📋 Public Key (pub): ${pair.pub.substring(0, 20)}...`);
96
+ console.log(`\n⚠️ Security Reminders:`);
97
+ console.log(` - Add ${path.basename(outputFile)} to your .gitignore`);
98
+ console.log(` - Keep this file secure and private`);
99
+ console.log(` - Use this pair with generate-codes.ts for private code storage`);
100
+ console.log(`\n💡 Next steps:`);
101
+ console.log(` Use this pair with generate-codes.ts:`);
102
+ console.log(` npx ts-node src/tools/generate-codes.ts <release-slug> --keypair ${outputFile}`);
103
+ process.exit(0);
104
+ }
105
+ catch (error) {
106
+ console.error('\n❌ Error generating SEA pair:', error.message);
107
+ process.exit(1);
108
+ }
109
+ }
110
+ main().catch(console.error);
111
+ //# sourceMappingURL=generate-sea-pair.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-sea-pair.js","sourceRoot":"","sources":["../../src/tools/generate-sea-pair.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Type definitions for Tunecamp
3
+ */
4
+ export interface CatalogConfig {
5
+ title: string;
6
+ description?: string;
7
+ url?: string;
8
+ basePath?: string;
9
+ theme?: string;
10
+ language?: string;
11
+ headerImage?: string;
12
+ customFont?: string;
13
+ customCSS?: string;
14
+ labelMode?: boolean;
15
+ podcast?: PodcastConfig;
16
+ metadata?: Record<string, any>;
17
+ }
18
+ export interface PodcastConfig {
19
+ enabled?: boolean;
20
+ title?: string;
21
+ description?: string;
22
+ author?: string;
23
+ email?: string;
24
+ category?: string;
25
+ image?: string;
26
+ explicit?: boolean;
27
+ }
28
+ export interface ArtistConfig {
29
+ name: string;
30
+ bio?: string;
31
+ photo?: string;
32
+ links?: ArtistLink[];
33
+ donationLinks?: DonationLink[];
34
+ slug?: string;
35
+ metadata?: Record<string, any>;
36
+ }
37
+ export interface DonationLink {
38
+ platform: string;
39
+ url: string;
40
+ description?: string;
41
+ }
42
+ export interface ArtistLink {
43
+ [platform: string]: string;
44
+ }
45
+ export type DownloadMode = 'free' | 'paycurtain' | 'codes' | 'none';
46
+ export type LicenseType = 'copyright' | 'cc-by' | 'cc-by-sa' | 'cc-by-nc' | 'cc-by-nc-sa' | 'cc-by-nc-nd' | 'cc-by-nd' | 'public-domain';
47
+ export interface UnlockCodesConfig {
48
+ enabled: boolean;
49
+ namespace?: string;
50
+ peers?: string[];
51
+ }
52
+ export interface ReleaseConfig {
53
+ title: string;
54
+ date: string;
55
+ description?: string;
56
+ cover?: string;
57
+ download?: DownloadMode;
58
+ unlockCodes?: UnlockCodesConfig;
59
+ price?: number;
60
+ paypalLink?: string;
61
+ stripeLink?: string;
62
+ license?: LicenseType;
63
+ genres?: string[];
64
+ credits?: Credit[];
65
+ unlisted?: boolean;
66
+ artistSlug?: string;
67
+ metadata?: Record<string, any>;
68
+ }
69
+ export interface Credit {
70
+ role: string;
71
+ name: string;
72
+ }
73
+ export interface TrackConfig {
74
+ file: string;
75
+ title?: string;
76
+ description?: string;
77
+ metadata?: Record<string, any>;
78
+ }
79
+ export interface TrackMetadata {
80
+ file: string;
81
+ filename: string;
82
+ title: string;
83
+ artist?: string;
84
+ album?: string;
85
+ year?: number;
86
+ track?: number;
87
+ duration?: number;
88
+ format?: string;
89
+ bitrate?: number;
90
+ sampleRate?: number;
91
+ description?: string;
92
+ genre?: string[];
93
+ }
94
+ export interface Release {
95
+ config: ReleaseConfig;
96
+ tracks: TrackMetadata[];
97
+ coverPath?: string;
98
+ path: string;
99
+ slug: string;
100
+ }
101
+ export interface Catalog {
102
+ config: CatalogConfig;
103
+ artist?: ArtistConfig;
104
+ artists?: ArtistConfig[];
105
+ releases: Release[];
106
+ }
107
+ export interface BuildOptions {
108
+ inputDir: string;
109
+ outputDir: string;
110
+ theme?: string;
111
+ basePath?: string;
112
+ verbose?: boolean;
113
+ }
114
+ export interface GeneratorOptions extends BuildOptions {
115
+ watch?: boolean;
116
+ }
117
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Type definitions for Tunecamp
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,9 @@
1
+ import { TrackMetadata } from '../types/index.js';
2
+ /**
3
+ * Audio file utilities
4
+ */
5
+ export declare function readAudioMetadata(filePath: string): Promise<TrackMetadata>;
6
+ export declare function formatDuration(seconds?: number): string;
7
+ export declare function formatFileSize(bytes?: number): string;
8
+ export declare function getAudioFormat(filename: string): string;
9
+ //# sourceMappingURL=audioUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioUtils.d.ts","sourceRoot":"","sources":["../../src/utils/audioUtils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD;;GAEG;AAEH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA4BhF;AAED,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAarD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAavD"}
@@ -0,0 +1,67 @@
1
+ import { parseFile } from 'music-metadata';
2
+ import path from 'path';
3
+ /**
4
+ * Audio file utilities
5
+ */
6
+ export async function readAudioMetadata(filePath) {
7
+ try {
8
+ const metadata = await parseFile(filePath);
9
+ const filename = path.basename(filePath);
10
+ return {
11
+ file: filePath,
12
+ filename,
13
+ title: metadata.common.title || filename.replace(/\.[^.]+$/, ''),
14
+ artist: metadata.common.artist,
15
+ album: metadata.common.album,
16
+ year: metadata.common.year,
17
+ track: metadata.common.track.no ?? undefined,
18
+ duration: metadata.format.duration,
19
+ format: metadata.format.container,
20
+ bitrate: metadata.format.bitrate,
21
+ sampleRate: metadata.format.sampleRate,
22
+ genre: metadata.common.genre,
23
+ };
24
+ }
25
+ catch (error) {
26
+ // Fallback if metadata reading fails
27
+ const filename = path.basename(filePath);
28
+ return {
29
+ file: filePath,
30
+ filename,
31
+ title: filename.replace(/\.[^.]+$/, ''),
32
+ };
33
+ }
34
+ }
35
+ export function formatDuration(seconds) {
36
+ if (!seconds)
37
+ return '0:00';
38
+ const mins = Math.floor(seconds / 60);
39
+ const secs = Math.floor(seconds % 60);
40
+ return `${mins}:${secs.toString().padStart(2, '0')}`;
41
+ }
42
+ export function formatFileSize(bytes) {
43
+ if (!bytes)
44
+ return '0 B';
45
+ const units = ['B', 'KB', 'MB', 'GB'];
46
+ let size = bytes;
47
+ let unitIndex = 0;
48
+ while (size >= 1024 && unitIndex < units.length - 1) {
49
+ size /= 1024;
50
+ unitIndex++;
51
+ }
52
+ return `${size.toFixed(1)} ${units[unitIndex]}`;
53
+ }
54
+ export function getAudioFormat(filename) {
55
+ const ext = path.extname(filename).toLowerCase().slice(1);
56
+ const formats = {
57
+ 'mp3': 'MP3',
58
+ 'flac': 'FLAC',
59
+ 'ogg': 'OGG Vorbis',
60
+ 'wav': 'WAV',
61
+ 'm4a': 'M4A/AAC',
62
+ 'aac': 'AAC',
63
+ 'opus': 'OPUS',
64
+ };
65
+ return formats[ext] || ext.toUpperCase();
66
+ }
67
+ //# sourceMappingURL=audioUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioUtils.js","sourceRoot":"","sources":["../../src/utils/audioUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB;;GAEG;AAEH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,QAAgB;IACtD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAEzC,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,QAAQ;YACR,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,IAAI,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;YAChE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM;YAC9B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK;YAC5B,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI;YAC1B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,SAAS;YAC5C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;YAClC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS;YACjC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO;YAChC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU;YACtC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK;SAC7B,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,qCAAqC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,QAAQ;YACR,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACxC,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,IAAI,CAAC,OAAO;QAAE,OAAO,MAAM,CAAC;IAE5B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IACtC,OAAO,GAAG,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACtC,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,OAAO,IAAI,IAAI,IAAI,IAAI,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,IAAI,IAAI,IAAI,CAAC;QACb,SAAS,EAAE,CAAC;IACd,CAAC;IAED,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,OAAO,GAA2B;QACtC,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,YAAY;QACnB,KAAK,EAAE,KAAK;QACZ,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,MAAM;KACf,CAAC;IAEF,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { CatalogConfig, ArtistConfig, ReleaseConfig } from '../types/index.js';
2
+ /**
3
+ * Configuration file utilities
4
+ */
5
+ export declare function readYamlFile<T>(filePath: string): Promise<T | null>;
6
+ export declare function readCatalogConfig(directory: string): Promise<CatalogConfig>;
7
+ export declare function readArtistConfig(directory: string): Promise<ArtistConfig | null>;
8
+ export declare function readReleaseConfig(directory: string): Promise<ReleaseConfig | null>;
9
+ export declare function validateCatalogConfig(config: CatalogConfig): void;
10
+ export declare function validateReleaseConfig(config: ReleaseConfig): void;
11
+ //# sourceMappingURL=configUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configUtils.d.ts","sourceRoot":"","sources":["../../src/utils/configUtils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAG/E;;GAEG;AAEH,wBAAsB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAOzE;AAED,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CASjF;AAED,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAGtF;AAED,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CASxF;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAIjE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAYjE"}
@@ -0,0 +1,50 @@
1
+ import { parse as parseYaml } from 'yaml';
2
+ import { readFile, fileExists } from './fileUtils.js';
3
+ import path from 'path';
4
+ /**
5
+ * Configuration file utilities
6
+ */
7
+ export async function readYamlFile(filePath) {
8
+ if (!(await fileExists(filePath))) {
9
+ return null;
10
+ }
11
+ const content = await readFile(filePath);
12
+ return parseYaml(content);
13
+ }
14
+ export async function readCatalogConfig(directory) {
15
+ const configPath = path.join(directory, 'catalog.yaml');
16
+ const config = await readYamlFile(configPath);
17
+ if (!config || !config.title) {
18
+ throw new Error(`Invalid or missing catalog.yaml in ${directory}`);
19
+ }
20
+ return config;
21
+ }
22
+ export async function readArtistConfig(directory) {
23
+ const configPath = path.join(directory, 'artist.yaml');
24
+ return await readYamlFile(configPath);
25
+ }
26
+ export async function readReleaseConfig(directory) {
27
+ const configPath = path.join(directory, 'release.yaml');
28
+ const config = await readYamlFile(configPath);
29
+ if (config && !config.title) {
30
+ throw new Error(`Release config missing title in ${directory}`);
31
+ }
32
+ return config;
33
+ }
34
+ export function validateCatalogConfig(config) {
35
+ if (!config.title) {
36
+ throw new Error('Catalog config must have a title');
37
+ }
38
+ }
39
+ export function validateReleaseConfig(config) {
40
+ if (!config.title) {
41
+ throw new Error('Release config must have a title');
42
+ }
43
+ if (!config.date) {
44
+ throw new Error('Release config must have a date');
45
+ }
46
+ if (config.download === 'paycurtain' && !config.price) {
47
+ throw new Error('Release with paycurtain download mode must have a price');
48
+ }
49
+ }
50
+ //# sourceMappingURL=configUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configUtils.js","sourceRoot":"","sources":["../../src/utils/configUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;GAEG;AAEH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAI,QAAgB;IACpD,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,OAAO,SAAS,CAAC,OAAO,CAAM,CAAC;AACjC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,SAAiB;IACvD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAgB,UAAU,CAAC,CAAC;IAE7D,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,sCAAsC,SAAS,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,SAAiB;IACtD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACvD,OAAO,MAAM,YAAY,CAAe,UAAU,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,SAAiB;IACvD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAgB,UAAU,CAAC,CAAC;IAE7D,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,mCAAmC,SAAS,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAAqB;IACzD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAAqB;IACzD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,KAAK,YAAY,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * File utility functions
3
+ */
4
+ export declare function findAudioFiles(directory: string): Promise<string[]>;
5
+ export declare function findImageFiles(directory: string, name?: string): Promise<string[]>;
6
+ export declare function findCover(directory: string): Promise<string | undefined>;
7
+ export declare function ensureDir(dir: string): Promise<void>;
8
+ export declare function copyFile(src: string, dest: string): Promise<void>;
9
+ export declare function readFile(filePath: string): Promise<string>;
10
+ export declare function writeFile(filePath: string, content: string): Promise<void>;
11
+ export declare function fileExists(filePath: string): Promise<boolean>;
12
+ export declare function createSlug(text: string): string;
13
+ export declare function getRelativePath(from: string, to: string): string;
14
+ //# sourceMappingURL=fileUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileUtils.d.ts","sourceRoot":"","sources":["../../src/utils/fileUtils.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAWzE;AAED,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAaxF;AAED,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAa9E;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1D;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvE;AAED,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEhE;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhF;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAEhE"}
@@ -0,0 +1,73 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { glob } from 'glob';
4
+ /**
5
+ * File utility functions
6
+ */
7
+ export async function findAudioFiles(directory) {
8
+ const audioExtensions = ['mp3', 'flac', 'ogg', 'wav', 'm4a', 'aac', 'opus'];
9
+ const pattern = `**/*.{${audioExtensions.join(',')}}`;
10
+ const files = await glob(pattern, {
11
+ cwd: directory,
12
+ absolute: false,
13
+ nodir: true,
14
+ });
15
+ return files.sort();
16
+ }
17
+ export async function findImageFiles(directory, name) {
18
+ const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
19
+ const pattern = name
20
+ ? `**/${name}.{${imageExtensions.join(',')}}`
21
+ : `**/*.{${imageExtensions.join(',')}}`;
22
+ const files = await glob(pattern, {
23
+ cwd: directory,
24
+ absolute: false,
25
+ nodir: true,
26
+ });
27
+ return files;
28
+ }
29
+ export async function findCover(directory) {
30
+ const coverNames = ['cover', 'artwork', 'folder', 'album'];
31
+ for (const name of coverNames) {
32
+ const covers = await findImageFiles(directory, name);
33
+ if (covers.length > 0) {
34
+ return covers[0];
35
+ }
36
+ }
37
+ // Fallback to any image in the directory
38
+ const images = await findImageFiles(directory);
39
+ return images[0];
40
+ }
41
+ export async function ensureDir(dir) {
42
+ await fs.ensureDir(dir);
43
+ }
44
+ export async function copyFile(src, dest) {
45
+ await fs.ensureDir(path.dirname(dest));
46
+ await fs.copy(src, dest);
47
+ }
48
+ export async function readFile(filePath) {
49
+ return await fs.readFile(filePath, 'utf-8');
50
+ }
51
+ export async function writeFile(filePath, content) {
52
+ await fs.ensureDir(path.dirname(filePath));
53
+ await fs.writeFile(filePath, content, 'utf-8');
54
+ }
55
+ export async function fileExists(filePath) {
56
+ try {
57
+ await fs.access(filePath);
58
+ return true;
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ }
64
+ export function createSlug(text) {
65
+ return text
66
+ .toLowerCase()
67
+ .replace(/[^a-z0-9]+/g, '-')
68
+ .replace(/^-|-$/g, '');
69
+ }
70
+ export function getRelativePath(from, to) {
71
+ return path.relative(from, to).replace(/\\/g, '/');
72
+ }
73
+ //# sourceMappingURL=fileUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileUtils.js","sourceRoot":"","sources":["../../src/utils/fileUtils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ # Example: Artist with Free Downloads
2
+
3
+ This example shows a simple artist catalog with free downloads.
4
+
5
+ ## Structure
6
+
7
+ ```
8
+ artist-free/
9
+ ├── catalog.yaml # Main catalog config
10
+ ├── artist.yaml # Artist information
11
+ └── releases/
12
+ └── debut-album/
13
+ ├── release.yaml # Release config
14
+ ├── cover.jpg # Album artwork (add your own)
15
+ └── tracks/
16
+ ├── 01-track-one.mp3
17
+ ├── 02-track-two.mp3
18
+ └── 03-track-three.mp3
19
+ ```
20
+
21
+ ## Features
22
+
23
+ - Free downloads for all tracks
24
+ - Artist bio and social links
25
+ - Album metadata and credits
26
+ - Genre tags
27
+
28
+ ## Building
29
+
30
+ ```bash
31
+ tunecamp build ./examples/artist-free -o ./output
32
+ ```
33
+
34
+ ## Notes
35
+
36
+ This example doesn't include actual audio files. Add your own MP3/FLAC files to the `tracks/` directory and cover art as `cover.jpg` and header image.
@@ -0,0 +1,49 @@
1
+ # Artist Paycurtain Example
2
+
3
+ This example demonstrates how to use TuneCamp with the honor system payment model.
4
+
5
+ ## Features Demonstrated
6
+
7
+ - **Paycurtain Mode**: Honor system where users can download for free but are encouraged to support the artist
8
+ - **Payment Links**: PayPal and Stripe integration
9
+ - **License System**: Creative Commons licensing
10
+ - **Donation Links**: Multiple donation platforms for artist support
11
+
12
+ ## Configuration
13
+
14
+ ### Catalog Configuration
15
+ - Basic catalog setup with theme selection
16
+
17
+ ### Artist Configuration
18
+ - Artist bio and social links
19
+ - Multiple donation platforms (PayPal, Ko-fi, Patreon)
20
+
21
+ ### Release Configuration
22
+ - Paycurtain mode with suggested price
23
+ - Payment links for PayPal and Stripe
24
+ - Creative Commons license (CC BY-NC)
25
+ - Genre and credit information
26
+
27
+ ## How It Works
28
+
29
+ 1. **Honor System**: Users can download tracks for free, but the interface encourages support
30
+ 2. **Payment Links**: Direct links to PayPal and Stripe for easy payment
31
+ 3. **License Display**: Clear licensing information for each release
32
+ 4. **Donation Section**: Additional ways to support the artist
33
+
34
+ ## Building the Example
35
+
36
+ ```bash
37
+ # Build the example
38
+ tunecamp build ./examples/artist-paycurtain --output ./output
39
+
40
+ # Serve locally
41
+ tunecamp serve ./output --port 3000
42
+ ```
43
+
44
+ ## Key Points
45
+
46
+ - All files are technically downloadable (static site limitation)
47
+ - The paycurtain is more about encouraging support than restricting access
48
+ - Multiple payment options give users flexibility
49
+ - Clear licensing helps with legal compliance
@@ -0,0 +1,33 @@
1
+ # Example: Music Label
2
+
3
+ This example shows a label catalog with multiple artists.
4
+
5
+ ## Structure
6
+
7
+ ```
8
+ label/
9
+ ├── catalog.yaml # Label info
10
+ └── releases/
11
+ ├── artist-one-album/
12
+ │ └── release.yaml
13
+ └── artist-two-ep/
14
+ └── release.yaml
15
+ ```
16
+
17
+ ## Features
18
+
19
+ - Label-level configuration
20
+ - Multiple artists
21
+ - Mixed download modes
22
+ - Various genres
23
+
24
+ ## Building
25
+
26
+ ```bash
27
+ tunecamp build ./examples/label -o ./output
28
+ ```
29
+
30
+ ## Notes
31
+
32
+ For a label catalog, you don't need an `artist.yaml` at the root. Instead, each release can specify its own artist in the track metadata or release config.
33
+