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.
- package/.env.local +2 -0
- package/.vercel/README.txt +11 -0
- package/.vercel/project.json +1 -0
- package/LICENSE +22 -0
- package/README.md +554 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +172 -0
- package/dist/cli.js.map +1 -0
- package/dist/generator/embedGenerator.d.ts +38 -0
- package/dist/generator/embedGenerator.d.ts.map +1 -0
- package/dist/generator/embedGenerator.js +92 -0
- package/dist/generator/embedGenerator.js.map +1 -0
- package/dist/generator/feedGenerator.d.ts +50 -0
- package/dist/generator/feedGenerator.d.ts.map +1 -0
- package/dist/generator/feedGenerator.js +167 -0
- package/dist/generator/feedGenerator.js.map +1 -0
- package/dist/generator/podcastFeedGenerator.d.ts +54 -0
- package/dist/generator/podcastFeedGenerator.d.ts.map +1 -0
- package/dist/generator/podcastFeedGenerator.js +173 -0
- package/dist/generator/podcastFeedGenerator.js.map +1 -0
- package/dist/generator/proceduralCoverGenerator.d.ts +51 -0
- package/dist/generator/proceduralCoverGenerator.d.ts.map +1 -0
- package/dist/generator/proceduralCoverGenerator.js +228 -0
- package/dist/generator/proceduralCoverGenerator.js.map +1 -0
- package/dist/generator/siteGenerator.d.ts +55 -0
- package/dist/generator/siteGenerator.d.ts.map +1 -0
- package/dist/generator/siteGenerator.js +539 -0
- package/dist/generator/siteGenerator.js.map +1 -0
- package/dist/generator/templateEngine.d.ts +13 -0
- package/dist/generator/templateEngine.d.ts.map +1 -0
- package/dist/generator/templateEngine.js +146 -0
- package/dist/generator/templateEngine.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/catalogParser.d.ts +13 -0
- package/dist/parser/catalogParser.d.ts.map +1 -0
- package/dist/parser/catalogParser.js +120 -0
- package/dist/parser/catalogParser.js.map +1 -0
- package/dist/tools/generate-codes.d.ts +14 -0
- package/dist/tools/generate-codes.d.ts.map +1 -0
- package/dist/tools/generate-codes.js +274 -0
- package/dist/tools/generate-codes.js.map +1 -0
- package/dist/tools/generate-sea-pair.d.ts +14 -0
- package/dist/tools/generate-sea-pair.d.ts.map +1 -0
- package/dist/tools/generate-sea-pair.js +111 -0
- package/dist/tools/generate-sea-pair.js.map +1 -0
- package/dist/types/index.d.ts +117 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/audioUtils.d.ts +9 -0
- package/dist/utils/audioUtils.d.ts.map +1 -0
- package/dist/utils/audioUtils.js +67 -0
- package/dist/utils/audioUtils.js.map +1 -0
- package/dist/utils/configUtils.d.ts +11 -0
- package/dist/utils/configUtils.d.ts.map +1 -0
- package/dist/utils/configUtils.js +50 -0
- package/dist/utils/configUtils.js.map +1 -0
- package/dist/utils/fileUtils.d.ts +14 -0
- package/dist/utils/fileUtils.d.ts.map +1 -0
- package/dist/utils/fileUtils.js +73 -0
- package/dist/utils/fileUtils.js.map +1 -0
- package/examples/artist-free/README.md +36 -0
- package/examples/artist-paycurtain/README.md +49 -0
- package/examples/label/README.md +33 -0
- package/gundb-keypair.json +8 -0
- package/logo.svg +30 -0
- package/package-lock.json +1176 -0
- package/package.json +42 -0
- package/public/assets/community-registry.js +291 -0
- package/public/assets/download-stats.js +263 -0
- package/public/assets/player.js +219 -0
- package/public/assets/style.css +1170 -0
- package/public/assets/theme-widget.js +353 -0
- package/public/assets/unlock-codes.js +225 -0
- package/public/atom.xml +22 -0
- package/public/catalog.m3u +3 -0
- package/public/feed.xml +22 -0
- package/public/image.png +0 -0
- package/public/index.html +249 -0
- package/public/logo.svg +30 -0
- package/public/releases/chirichetto/Homologo - Chirichetto.wav +0 -0
- package/public/releases/chirichetto/cover.png +0 -0
- package/public/releases/chirichetto/embed-code.txt +16 -0
- package/public/releases/chirichetto/embed-compact.txt +8 -0
- package/public/releases/chirichetto/embed.html +39 -0
- package/public/releases/chirichetto/index.html +389 -0
- package/public/releases/chirichetto/playlist.m3u +3 -0
- package/templates/dark/assets/community-registry.js +291 -0
- package/templates/dark/assets/download-stats.js +263 -0
- package/templates/dark/assets/player.js +219 -0
- package/templates/dark/assets/style.css +740 -0
- package/templates/dark/index.hbs +73 -0
- package/templates/dark/layout.hbs +84 -0
- package/templates/dark/release.hbs +212 -0
- package/templates/default/assets/community-registry.js +291 -0
- package/templates/default/assets/download-stats.js +263 -0
- package/templates/default/assets/player.js +219 -0
- package/templates/default/assets/style.css +1170 -0
- package/templates/default/assets/theme-widget.js +353 -0
- package/templates/default/assets/unlock-codes.js +225 -0
- package/templates/default/index.hbs +188 -0
- package/templates/default/layout.hbs +117 -0
- package/templates/default/release.hbs +553 -0
- package/templates/minimal/assets/community-registry.js +291 -0
- package/templates/minimal/assets/download-stats.js +263 -0
- package/templates/minimal/assets/player.js +219 -0
- package/templates/minimal/assets/style.css +796 -0
- package/templates/minimal/index.hbs +73 -0
- package/templates/minimal/layout.hbs +84 -0
- package/templates/minimal/release.hbs +212 -0
- package/templates/retro/assets/community-registry.js +291 -0
- package/templates/retro/assets/download-stats.js +263 -0
- package/templates/retro/assets/player.js +219 -0
- package/templates/retro/assets/style.css +872 -0
- package/templates/retro/index.hbs +73 -0
- package/templates/retro/layout.hbs +84 -0
- package/templates/retro/release.hbs +212 -0
- package/templates/translucent/assets/community-registry.js +291 -0
- package/templates/translucent/assets/download-stats.js +263 -0
- package/templates/translucent/assets/player.js +219 -0
- package/templates/translucent/assets/style.css +1352 -0
- package/templates/translucent/index.hbs +73 -0
- package/templates/translucent/layout.hbs +84 -0
- package/templates/translucent/release.hbs +212 -0
- package/website/community.html +492 -0
- package/website/index.html +195 -0
- package/website/styles.css +396 -0
- package/website/tunecamp.svg +30 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Podcast RSS Feed Generator for Tunecamp
|
|
3
|
+
* Creates podcast-specific RSS feeds for episodic content
|
|
4
|
+
*/
|
|
5
|
+
import path from "path";
|
|
6
|
+
/**
|
|
7
|
+
* Generates podcast-specific RSS 2.0 feeds
|
|
8
|
+
*/
|
|
9
|
+
export class PodcastFeedGenerator {
|
|
10
|
+
catalog;
|
|
11
|
+
options;
|
|
12
|
+
constructor(catalog, options) {
|
|
13
|
+
this.catalog = catalog;
|
|
14
|
+
this.options = options;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get the full URL for a path
|
|
18
|
+
*/
|
|
19
|
+
getUrl(relativePath) {
|
|
20
|
+
const base = this.options.siteUrl.replace(/\/$/, "");
|
|
21
|
+
const basePath = this.options.basePath || "";
|
|
22
|
+
return `${base}${basePath}/${relativePath}`.replace(/([^:]\/)\/+/g, "$1");
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Format date for RSS (RFC 822)
|
|
26
|
+
*/
|
|
27
|
+
formatRssDate(dateStr) {
|
|
28
|
+
const date = new Date(dateStr);
|
|
29
|
+
return date.toUTCString();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Escape XML special characters
|
|
33
|
+
*/
|
|
34
|
+
escapeXml(str) {
|
|
35
|
+
return str
|
|
36
|
+
.replace(/&/g, "&")
|
|
37
|
+
.replace(/</g, "<")
|
|
38
|
+
.replace(/>/g, ">")
|
|
39
|
+
.replace(/"/g, """)
|
|
40
|
+
.replace(/'/g, "'");
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Format duration in HH:MM:SS format for iTunes
|
|
44
|
+
*/
|
|
45
|
+
formatItunesDuration(seconds) {
|
|
46
|
+
if (!seconds)
|
|
47
|
+
return "00:00:00";
|
|
48
|
+
const h = Math.floor(seconds / 3600);
|
|
49
|
+
const m = Math.floor((seconds % 3600) / 60);
|
|
50
|
+
const s = Math.floor(seconds % 60);
|
|
51
|
+
return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get MIME type for audio file
|
|
55
|
+
*/
|
|
56
|
+
getAudioMimeType(filename) {
|
|
57
|
+
const ext = path.extname(filename).toLowerCase();
|
|
58
|
+
const mimeTypes = {
|
|
59
|
+
'.mp3': 'audio/mpeg',
|
|
60
|
+
'.m4a': 'audio/mp4',
|
|
61
|
+
'.aac': 'audio/aac',
|
|
62
|
+
'.ogg': 'audio/ogg',
|
|
63
|
+
'.opus': 'audio/opus',
|
|
64
|
+
'.flac': 'audio/flac',
|
|
65
|
+
'.wav': 'audio/wav',
|
|
66
|
+
};
|
|
67
|
+
return mimeTypes[ext] || 'audio/mpeg';
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Generate Podcast RSS feed
|
|
71
|
+
* Each track becomes an episode
|
|
72
|
+
*/
|
|
73
|
+
generatePodcastFeed() {
|
|
74
|
+
const title = this.escapeXml(this.options.podcastTitle || this.catalog.config.title);
|
|
75
|
+
const description = this.escapeXml(this.options.podcastDescription || this.catalog.config.description || "Music podcast");
|
|
76
|
+
const link = this.getUrl("");
|
|
77
|
+
const feedUrl = this.getUrl("podcast.xml");
|
|
78
|
+
const author = this.escapeXml(this.options.podcastAuthor || this.catalog.artist?.name || "Unknown");
|
|
79
|
+
const email = this.options.podcastEmail || "";
|
|
80
|
+
const category = this.options.podcastCategory || "Music";
|
|
81
|
+
const explicit = this.options.explicit ? "true" : "false";
|
|
82
|
+
const now = new Date().toUTCString();
|
|
83
|
+
// Get image URL
|
|
84
|
+
let imageUrl = this.getUrl("logo.svg");
|
|
85
|
+
if (this.options.podcastImage) {
|
|
86
|
+
imageUrl = this.getUrl(this.options.podcastImage);
|
|
87
|
+
}
|
|
88
|
+
else if (this.catalog.artist?.photo) {
|
|
89
|
+
imageUrl = this.getUrl(this.catalog.artist.photo);
|
|
90
|
+
}
|
|
91
|
+
// Collect all episodes (tracks from all releases)
|
|
92
|
+
const episodes = [];
|
|
93
|
+
for (const release of this.catalog.releases) {
|
|
94
|
+
if (release.config.unlisted)
|
|
95
|
+
continue;
|
|
96
|
+
for (const track of release.tracks) {
|
|
97
|
+
episodes.push({
|
|
98
|
+
track,
|
|
99
|
+
release,
|
|
100
|
+
pubDate: release.config.date,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Sort episodes by date (newest first)
|
|
105
|
+
episodes.sort((a, b) => new Date(b.pubDate).getTime() - new Date(a.pubDate).getTime());
|
|
106
|
+
const items = episodes.map((ep, index) => this.generateEpisodeItem(ep.track, ep.release, episodes.length - index)).join("\n");
|
|
107
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
108
|
+
<rss version="2.0"
|
|
109
|
+
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
|
|
110
|
+
xmlns:podcast="https://podcastindex.org/namespace/1.0"
|
|
111
|
+
xmlns:atom="http://www.w3.org/2005/Atom"
|
|
112
|
+
xmlns:content="http://purl.org/rss/1.0/modules/content/">
|
|
113
|
+
<channel>
|
|
114
|
+
<title>${title}</title>
|
|
115
|
+
<link>${link}</link>
|
|
116
|
+
<description>${description}</description>
|
|
117
|
+
<language>${this.catalog.config.language || "en"}</language>
|
|
118
|
+
<lastBuildDate>${now}</lastBuildDate>
|
|
119
|
+
<generator>Tunecamp Podcast Generator</generator>
|
|
120
|
+
<atom:link href="${feedUrl}" rel="self" type="application/rss+xml"/>
|
|
121
|
+
|
|
122
|
+
<!-- iTunes Podcast Tags -->
|
|
123
|
+
<itunes:author>${author}</itunes:author>
|
|
124
|
+
<itunes:summary>${description}</itunes:summary>
|
|
125
|
+
<itunes:type>episodic</itunes:type>
|
|
126
|
+
<itunes:explicit>${explicit}</itunes:explicit>
|
|
127
|
+
<itunes:category text="${this.escapeXml(category)}"/>
|
|
128
|
+
<itunes:image href="${imageUrl}"/>
|
|
129
|
+
${email ? `<itunes:owner><itunes:name>${author}</itunes:name><itunes:email>${email}</itunes:email></itunes:owner>` : ''}
|
|
130
|
+
|
|
131
|
+
<!-- Podcast 2.0 Tags -->
|
|
132
|
+
<podcast:locked>no</podcast:locked>
|
|
133
|
+
|
|
134
|
+
${items}
|
|
135
|
+
</channel>
|
|
136
|
+
</rss>`;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Generate a single episode item
|
|
140
|
+
*/
|
|
141
|
+
generateEpisodeItem(track, release, episodeNumber) {
|
|
142
|
+
const title = this.escapeXml(`${track.title} (from ${release.config.title})`);
|
|
143
|
+
const description = this.escapeXml(track.description || release.config.description || `Episode ${episodeNumber}`);
|
|
144
|
+
const audioUrl = this.getUrl(`releases/${release.slug}/${path.basename(track.file)}`);
|
|
145
|
+
const pageUrl = this.getUrl(`releases/${release.slug}/index.html`);
|
|
146
|
+
const pubDate = this.formatRssDate(release.config.date);
|
|
147
|
+
const duration = this.formatItunesDuration(track.duration);
|
|
148
|
+
const mimeType = this.getAudioMimeType(track.file);
|
|
149
|
+
const guid = `${release.slug}-${path.basename(track.file, path.extname(track.file))}`;
|
|
150
|
+
const artist = this.catalog.artist?.name || "Unknown Artist";
|
|
151
|
+
// Get cover image
|
|
152
|
+
let imageUrl = "";
|
|
153
|
+
if (release.coverPath) {
|
|
154
|
+
imageUrl = this.getUrl(`releases/${release.slug}/${path.basename(release.coverPath)}`);
|
|
155
|
+
}
|
|
156
|
+
return ` <item>
|
|
157
|
+
<title>${title}</title>
|
|
158
|
+
<link>${pageUrl}</link>
|
|
159
|
+
<description><![CDATA[${description}]]></description>
|
|
160
|
+
<pubDate>${pubDate}</pubDate>
|
|
161
|
+
<guid isPermaLink="false">${guid}</guid>
|
|
162
|
+
<enclosure url="${audioUrl}" type="${mimeType}" length="0"/>
|
|
163
|
+
|
|
164
|
+
<itunes:title>${this.escapeXml(track.title)}</itunes:title>
|
|
165
|
+
<itunes:author>${this.escapeXml(artist)}</itunes:author>
|
|
166
|
+
<itunes:duration>${duration}</itunes:duration>
|
|
167
|
+
<itunes:episodeType>full</itunes:episodeType>
|
|
168
|
+
<itunes:episode>${episodeNumber}</itunes:episode>
|
|
169
|
+
${imageUrl ? `<itunes:image href="${imageUrl}"/>` : ''}
|
|
170
|
+
</item>`;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=podcastFeedGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"podcastFeedGenerator.js","sourceRoot":"","sources":["../../src/generator/podcastFeedGenerator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Procedural Cover Generator for Tunecamp
|
|
3
|
+
* Creates AI-free, algorithmically generated cover art
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Generate SVG cover art based on release metadata
|
|
7
|
+
* Uses hash-based deterministic generation for consistency
|
|
8
|
+
*/
|
|
9
|
+
export declare class ProceduralCoverGenerator {
|
|
10
|
+
/**
|
|
11
|
+
* Simple hash function for strings
|
|
12
|
+
*/
|
|
13
|
+
private hash;
|
|
14
|
+
/**
|
|
15
|
+
* Generate HSL color from hash
|
|
16
|
+
*/
|
|
17
|
+
private hashToHsl;
|
|
18
|
+
/**
|
|
19
|
+
* Generate procedural cover SVG
|
|
20
|
+
*/
|
|
21
|
+
generateCover(title: string, artistName: string, releaseDate?: string, genres?: string[]): string;
|
|
22
|
+
/**
|
|
23
|
+
* Wave pattern
|
|
24
|
+
*/
|
|
25
|
+
private generateWavePattern;
|
|
26
|
+
/**
|
|
27
|
+
* Circle pattern
|
|
28
|
+
*/
|
|
29
|
+
private generateCirclePattern;
|
|
30
|
+
/**
|
|
31
|
+
* Grid pattern
|
|
32
|
+
*/
|
|
33
|
+
private generateGridPattern;
|
|
34
|
+
/**
|
|
35
|
+
* Gradient pattern with shapes
|
|
36
|
+
*/
|
|
37
|
+
private generateGradientPattern;
|
|
38
|
+
/**
|
|
39
|
+
* Geometric pattern
|
|
40
|
+
*/
|
|
41
|
+
private generateGeometricPattern;
|
|
42
|
+
/**
|
|
43
|
+
* Get contrasting text color
|
|
44
|
+
*/
|
|
45
|
+
private getContrastColor;
|
|
46
|
+
/**
|
|
47
|
+
* Escape XML special characters
|
|
48
|
+
*/
|
|
49
|
+
private escapeXml;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=proceduralCoverGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proceduralCoverGenerator.d.ts","sourceRoot":"","sources":["../../src/generator/proceduralCoverGenerator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,qBAAa,wBAAwB;IACjC;;OAEG;IACH,OAAO,CAAC,IAAI;IAUZ;;OAEG;IACH,OAAO,CAAC,SAAS;IAOjB;;OAEG;IACH,aAAa,CACT,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM,EAAE,GAClB,MAAM;IA0ET;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAyB3B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAiB7B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAmB3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAiB/B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA8BhC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAKxB;;OAEG;IACH,OAAO,CAAC,SAAS;CAQpB"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Procedural Cover Generator for Tunecamp
|
|
3
|
+
* Creates AI-free, algorithmically generated cover art
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Generate SVG cover art based on release metadata
|
|
7
|
+
* Uses hash-based deterministic generation for consistency
|
|
8
|
+
*/
|
|
9
|
+
export class ProceduralCoverGenerator {
|
|
10
|
+
/**
|
|
11
|
+
* Simple hash function for strings
|
|
12
|
+
*/
|
|
13
|
+
hash(str) {
|
|
14
|
+
let hash = 0;
|
|
15
|
+
for (let i = 0; i < str.length; i++) {
|
|
16
|
+
const char = str.charCodeAt(i);
|
|
17
|
+
hash = ((hash << 5) - hash) + char;
|
|
18
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
19
|
+
}
|
|
20
|
+
return Math.abs(hash);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Generate HSL color from hash
|
|
24
|
+
*/
|
|
25
|
+
hashToHsl(hash, offset = 0) {
|
|
26
|
+
const h = ((hash + offset * 137) % 360);
|
|
27
|
+
const s = 60 + (hash % 30); // 60-90%
|
|
28
|
+
const l = 40 + ((hash >> 4) % 25); // 40-65%
|
|
29
|
+
return `hsl(${h}, ${s}%, ${l}%)`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Generate procedural cover SVG
|
|
33
|
+
*/
|
|
34
|
+
generateCover(title, artistName, releaseDate, genres) {
|
|
35
|
+
const seed = this.hash(title + artistName + (releaseDate || ""));
|
|
36
|
+
const width = 500;
|
|
37
|
+
const height = 500;
|
|
38
|
+
// Choose a pattern based on hash
|
|
39
|
+
const patternType = seed % 5;
|
|
40
|
+
let pattern;
|
|
41
|
+
switch (patternType) {
|
|
42
|
+
case 0:
|
|
43
|
+
pattern = this.generateWavePattern(seed, width, height);
|
|
44
|
+
break;
|
|
45
|
+
case 1:
|
|
46
|
+
pattern = this.generateCirclePattern(seed, width, height);
|
|
47
|
+
break;
|
|
48
|
+
case 2:
|
|
49
|
+
pattern = this.generateGridPattern(seed, width, height);
|
|
50
|
+
break;
|
|
51
|
+
case 3:
|
|
52
|
+
pattern = this.generateGradientPattern(seed, width, height);
|
|
53
|
+
break;
|
|
54
|
+
default:
|
|
55
|
+
pattern = this.generateGeometricPattern(seed, width, height);
|
|
56
|
+
}
|
|
57
|
+
// Background gradient
|
|
58
|
+
const bgColor1 = this.hashToHsl(seed, 0);
|
|
59
|
+
const bgColor2 = this.hashToHsl(seed, 100);
|
|
60
|
+
// Text styling
|
|
61
|
+
const textColor = this.getContrastColor(seed);
|
|
62
|
+
const titleSize = Math.min(36, Math.max(24, 500 / (title.length * 0.7)));
|
|
63
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
64
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}">
|
|
65
|
+
<defs>
|
|
66
|
+
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
67
|
+
<stop offset="0%" style="stop-color:${bgColor1}"/>
|
|
68
|
+
<stop offset="100%" style="stop-color:${bgColor2}"/>
|
|
69
|
+
</linearGradient>
|
|
70
|
+
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
71
|
+
<feDropShadow dx="0" dy="2" stdDeviation="3" flood-opacity="0.3"/>
|
|
72
|
+
</filter>
|
|
73
|
+
</defs>
|
|
74
|
+
|
|
75
|
+
<!-- Background -->
|
|
76
|
+
<rect width="100%" height="100%" fill="url(#bg)"/>
|
|
77
|
+
|
|
78
|
+
<!-- Pattern -->
|
|
79
|
+
${pattern}
|
|
80
|
+
|
|
81
|
+
<!-- Text overlay with shadow -->
|
|
82
|
+
<g filter="url(#shadow)">
|
|
83
|
+
<text x="${width / 2}" y="${height - 100}"
|
|
84
|
+
font-family="system-ui, -apple-system, sans-serif"
|
|
85
|
+
font-size="${titleSize}"
|
|
86
|
+
font-weight="700"
|
|
87
|
+
fill="${textColor}"
|
|
88
|
+
text-anchor="middle">
|
|
89
|
+
${this.escapeXml(title)}
|
|
90
|
+
</text>
|
|
91
|
+
<text x="${width / 2}" y="${height - 60}"
|
|
92
|
+
font-family="system-ui, -apple-system, sans-serif"
|
|
93
|
+
font-size="18"
|
|
94
|
+
fill="${textColor}"
|
|
95
|
+
text-anchor="middle"
|
|
96
|
+
opacity="0.8">
|
|
97
|
+
${this.escapeXml(artistName)}
|
|
98
|
+
</text>
|
|
99
|
+
</g>
|
|
100
|
+
</svg>`;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Wave pattern
|
|
104
|
+
*/
|
|
105
|
+
generateWavePattern(seed, w, h) {
|
|
106
|
+
const color1 = this.hashToHsl(seed, 50);
|
|
107
|
+
const color2 = this.hashToHsl(seed, 150);
|
|
108
|
+
const waves = [];
|
|
109
|
+
const numWaves = 4 + (seed % 4);
|
|
110
|
+
for (let i = 0; i < numWaves; i++) {
|
|
111
|
+
const amplitude = 30 + (seed >> (i * 2)) % 40;
|
|
112
|
+
const freq = 0.02 + ((seed >> (i * 3)) % 20) / 1000;
|
|
113
|
+
const yOffset = (h / (numWaves + 1)) * (i + 1);
|
|
114
|
+
const opacity = 0.3 + (i * 0.1);
|
|
115
|
+
let d = `M 0 ${yOffset}`;
|
|
116
|
+
for (let x = 0; x <= w; x += 10) {
|
|
117
|
+
const y = yOffset + Math.sin(x * freq + i) * amplitude;
|
|
118
|
+
d += ` L ${x} ${y}`;
|
|
119
|
+
}
|
|
120
|
+
d += ` L ${w} ${h} L 0 ${h} Z`;
|
|
121
|
+
waves.push(`<path d="${d}" fill="${i % 2 === 0 ? color1 : color2}" opacity="${opacity}"/>`);
|
|
122
|
+
}
|
|
123
|
+
return waves.join("\n ");
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Circle pattern
|
|
127
|
+
*/
|
|
128
|
+
generateCirclePattern(seed, w, h) {
|
|
129
|
+
const circles = [];
|
|
130
|
+
const numCircles = 5 + (seed % 8);
|
|
131
|
+
for (let i = 0; i < numCircles; i++) {
|
|
132
|
+
const cx = ((seed >> (i * 5)) % w);
|
|
133
|
+
const cy = ((seed >> (i * 3 + 1)) % h);
|
|
134
|
+
const r = 30 + ((seed >> (i * 2)) % 80);
|
|
135
|
+
const color = this.hashToHsl(seed + i * 47, i * 30);
|
|
136
|
+
const opacity = 0.2 + (i % 4) * 0.1;
|
|
137
|
+
circles.push(`<circle cx="${cx}" cy="${cy}" r="${r}" fill="${color}" opacity="${opacity}"/>`);
|
|
138
|
+
}
|
|
139
|
+
return circles.join("\n ");
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Grid pattern
|
|
143
|
+
*/
|
|
144
|
+
generateGridPattern(seed, w, h) {
|
|
145
|
+
const rects = [];
|
|
146
|
+
const cellSize = 50 + (seed % 50);
|
|
147
|
+
const cols = Math.ceil(w / cellSize);
|
|
148
|
+
const rows = Math.ceil(h / cellSize);
|
|
149
|
+
for (let row = 0; row < rows; row++) {
|
|
150
|
+
for (let col = 0; col < cols; col++) {
|
|
151
|
+
if ((seed + row * cols + col) % 3 === 0) {
|
|
152
|
+
const color = this.hashToHsl(seed + row * cols + col, 0);
|
|
153
|
+
const opacity = 0.1 + ((seed >> ((row + col) % 16)) % 3) * 0.1;
|
|
154
|
+
rects.push(`<rect x="${col * cellSize}" y="${row * cellSize}" width="${cellSize}" height="${cellSize}" fill="${color}" opacity="${opacity}"/>`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return rects.join("\n ");
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Gradient pattern with shapes
|
|
162
|
+
*/
|
|
163
|
+
generateGradientPattern(seed, w, h) {
|
|
164
|
+
const color1 = this.hashToHsl(seed, 200);
|
|
165
|
+
const color2 = this.hashToHsl(seed, 300);
|
|
166
|
+
const rotation = seed % 360;
|
|
167
|
+
return `
|
|
168
|
+
<defs>
|
|
169
|
+
<radialGradient id="overlay">
|
|
170
|
+
<stop offset="0%" style="stop-color:${color1};stop-opacity:0.4"/>
|
|
171
|
+
<stop offset="100%" style="stop-color:${color2};stop-opacity:0.1"/>
|
|
172
|
+
</radialGradient>
|
|
173
|
+
</defs>
|
|
174
|
+
<circle cx="${w * 0.3}" cy="${h * 0.4}" r="${w * 0.6}" fill="url(#overlay)"/>
|
|
175
|
+
<circle cx="${w * 0.7}" cy="${h * 0.6}" r="${w * 0.4}" fill="url(#overlay)"/>
|
|
176
|
+
`;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Geometric pattern
|
|
180
|
+
*/
|
|
181
|
+
generateGeometricPattern(seed, w, h) {
|
|
182
|
+
const shapes = [];
|
|
183
|
+
const numShapes = 6 + (seed % 6);
|
|
184
|
+
for (let i = 0; i < numShapes; i++) {
|
|
185
|
+
const x = ((seed >> (i * 4)) % w);
|
|
186
|
+
const y = ((seed >> (i * 3 + 2)) % h);
|
|
187
|
+
const size = 40 + ((seed >> (i * 2)) % 60);
|
|
188
|
+
const color = this.hashToHsl(seed + i * 71, i * 45);
|
|
189
|
+
const opacity = 0.15 + (i % 3) * 0.1;
|
|
190
|
+
const rotation = (seed + i * 30) % 360;
|
|
191
|
+
// Alternate between triangles, hexagons, and diamonds
|
|
192
|
+
if (i % 3 === 0) {
|
|
193
|
+
// Triangle
|
|
194
|
+
const points = `${x},${y - size / 2} ${x - size / 2},${y + size / 2} ${x + size / 2},${y + size / 2}`;
|
|
195
|
+
shapes.push(`<polygon points="${points}" fill="${color}" opacity="${opacity}" transform="rotate(${rotation} ${x} ${y})"/>`);
|
|
196
|
+
}
|
|
197
|
+
else if (i % 3 === 1) {
|
|
198
|
+
// Diamond
|
|
199
|
+
const points = `${x},${y - size / 2} ${x + size / 2},${y} ${x},${y + size / 2} ${x - size / 2},${y}`;
|
|
200
|
+
shapes.push(`<polygon points="${points}" fill="${color}" opacity="${opacity}"/>`);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
// Hexagon approximation
|
|
204
|
+
shapes.push(`<circle cx="${x}" cy="${y}" r="${size / 2}" fill="${color}" opacity="${opacity}"/>`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return shapes.join("\n ");
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Get contrasting text color
|
|
211
|
+
*/
|
|
212
|
+
getContrastColor(seed) {
|
|
213
|
+
const lightness = 40 + ((seed >> 4) % 25);
|
|
214
|
+
return lightness > 50 ? "#1e293b" : "#f8fafc";
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Escape XML special characters
|
|
218
|
+
*/
|
|
219
|
+
escapeXml(str) {
|
|
220
|
+
return str
|
|
221
|
+
.replace(/&/g, "&")
|
|
222
|
+
.replace(/</g, "<")
|
|
223
|
+
.replace(/>/g, ">")
|
|
224
|
+
.replace(/"/g, """)
|
|
225
|
+
.replace(/'/g, "'");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=proceduralCoverGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proceduralCoverGenerator.js","sourceRoot":"","sources":["../../src/generator/proceduralCoverGenerator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Catalog, BuildOptions } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generates static HTML site from catalog
|
|
4
|
+
*/
|
|
5
|
+
export declare class SiteGenerator {
|
|
6
|
+
private catalog;
|
|
7
|
+
private options;
|
|
8
|
+
private templateEngine;
|
|
9
|
+
private templateDir;
|
|
10
|
+
constructor(catalog: Catalog, options: BuildOptions);
|
|
11
|
+
generate(): Promise<void>;
|
|
12
|
+
private loadTemplates;
|
|
13
|
+
private copyAssets;
|
|
14
|
+
private generateIndexPage;
|
|
15
|
+
private generateReleasesPages;
|
|
16
|
+
private generateReleasePage;
|
|
17
|
+
private copyMediaFiles;
|
|
18
|
+
/**
|
|
19
|
+
* Generate RSS and Atom feeds
|
|
20
|
+
*/
|
|
21
|
+
private generateFeeds;
|
|
22
|
+
/**
|
|
23
|
+
* Generate M3U playlists for releases and catalog
|
|
24
|
+
*/
|
|
25
|
+
private generateM3uPlaylists;
|
|
26
|
+
/**
|
|
27
|
+
* Generate M3U playlist for a single release
|
|
28
|
+
*/
|
|
29
|
+
private generateReleaseM3u;
|
|
30
|
+
/**
|
|
31
|
+
* Generate M3U playlist for entire catalog
|
|
32
|
+
*/
|
|
33
|
+
private generateCatalogM3u;
|
|
34
|
+
/**
|
|
35
|
+
* Generate artist pages for label mode
|
|
36
|
+
*/
|
|
37
|
+
private generateArtistPages;
|
|
38
|
+
/**
|
|
39
|
+
* Generate embed pages for each release
|
|
40
|
+
*/
|
|
41
|
+
private generateEmbedPages;
|
|
42
|
+
/**
|
|
43
|
+
* Generate standalone embed HTML page
|
|
44
|
+
*/
|
|
45
|
+
private generateEmbedHtmlPage;
|
|
46
|
+
/**
|
|
47
|
+
* Generate podcast RSS feed
|
|
48
|
+
*/
|
|
49
|
+
private generatePodcastFeed;
|
|
50
|
+
/**
|
|
51
|
+
* Generate procedural SVG covers for releases without cover art
|
|
52
|
+
*/
|
|
53
|
+
private generateProceduralCovers;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=siteGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"siteGenerator.d.ts","sourceRoot":"","sources":["../../src/generator/siteGenerator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAyB,MAAM,mBAAmB,CAAC;AAajF;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY;IAY7C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YA6CjB,aAAa;YAgBb,UAAU;YAUV,iBAAiB;YA+DjB,qBAAqB;YAMrB,mBAAmB;YA8EnB,cAAc;IA+F5B;;OAEG;YACW,aAAa;IAoB3B;;OAEG;YACW,oBAAoB;IAkBlC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAiB1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA2B1B;;OAEG;YACW,mBAAmB;IAkEjC;;OAEG;YACW,kBAAkB;IAwBhC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAgD7B;;OAEG;YACW,mBAAmB;IAsBjC;;OAEG;YACW,wBAAwB;CA6BvC"}
|