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
package/dist/cli.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Command-line interface for Tunecamp
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { Tunecamp } from './index.js';
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = path.dirname(__filename);
|
|
13
|
+
const program = new Command();
|
|
14
|
+
program
|
|
15
|
+
.name('tunecamp')
|
|
16
|
+
.description('Static site generator for musicians and labels')
|
|
17
|
+
.version('0.1.0');
|
|
18
|
+
program
|
|
19
|
+
.command('build')
|
|
20
|
+
.description('Build a static site from catalog')
|
|
21
|
+
.argument('<input>', 'Input directory containing catalog')
|
|
22
|
+
.option('-o, --output <dir>', 'Output directory', './public')
|
|
23
|
+
.option('-t, --theme <name>', 'Theme name (overrides catalog.yaml)')
|
|
24
|
+
.option('-b, --basePath <path>', 'Base path for deployment (overrides catalog.yaml)')
|
|
25
|
+
.option('-v, --verbose', 'Verbose output', false)
|
|
26
|
+
.action(async (input, options) => {
|
|
27
|
+
try {
|
|
28
|
+
const generator = new Tunecamp({
|
|
29
|
+
inputDir: path.resolve(input),
|
|
30
|
+
outputDir: path.resolve(options.output),
|
|
31
|
+
theme: options.theme,
|
|
32
|
+
basePath: options.basePath,
|
|
33
|
+
verbose: options.verbose,
|
|
34
|
+
});
|
|
35
|
+
await generator.build();
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error(chalk.red('Error:'), error);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
program
|
|
43
|
+
.command('init')
|
|
44
|
+
.description('Initialize a new catalog')
|
|
45
|
+
.argument('<directory>', 'Directory to initialize')
|
|
46
|
+
.action(async (directory) => {
|
|
47
|
+
try {
|
|
48
|
+
const targetDir = path.resolve(directory);
|
|
49
|
+
if (await fs.pathExists(targetDir)) {
|
|
50
|
+
const files = await fs.readdir(targetDir);
|
|
51
|
+
if (files.length > 0) {
|
|
52
|
+
console.error(chalk.red('Error: Directory is not empty'));
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
await initializeCatalog(targetDir);
|
|
57
|
+
console.log(chalk.green('✅ Catalog initialized successfully!'));
|
|
58
|
+
console.log(chalk.blue(`\nNext steps:`));
|
|
59
|
+
console.log(` cd ${directory}`);
|
|
60
|
+
console.log(` # Add your music files to releases/`);
|
|
61
|
+
console.log(` tunecamp build . -o public`);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
console.error(chalk.red('Error:'), error);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
program
|
|
69
|
+
.command('serve')
|
|
70
|
+
.description('Serve the generated site locally')
|
|
71
|
+
.argument('[directory]', 'Directory to serve', './public')
|
|
72
|
+
.option('-p, --port <port>', 'Port number', '3000')
|
|
73
|
+
.action(async (directory, options) => {
|
|
74
|
+
const http = await import('http');
|
|
75
|
+
const fs = await import('fs');
|
|
76
|
+
const path = await import('path');
|
|
77
|
+
const port = parseInt(options.port);
|
|
78
|
+
const dir = path.resolve(directory);
|
|
79
|
+
const server = http.createServer((req, res) => {
|
|
80
|
+
let filePath = path.join(dir, req.url === '/' ? 'index.html' : req.url);
|
|
81
|
+
fs.readFile(filePath, (err, data) => {
|
|
82
|
+
if (err) {
|
|
83
|
+
res.writeHead(404);
|
|
84
|
+
res.end('Not found');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const ext = path.extname(filePath);
|
|
88
|
+
const contentTypes = {
|
|
89
|
+
'.html': 'text/html',
|
|
90
|
+
'.css': 'text/css',
|
|
91
|
+
'.js': 'text/javascript',
|
|
92
|
+
'.json': 'application/json',
|
|
93
|
+
'.png': 'image/png',
|
|
94
|
+
'.jpg': 'image/jpeg',
|
|
95
|
+
'.jpeg': 'image/jpeg',
|
|
96
|
+
'.gif': 'image/gif',
|
|
97
|
+
'.svg': 'image/svg+xml',
|
|
98
|
+
'.mp3': 'audio/mpeg',
|
|
99
|
+
'.flac': 'audio/flac',
|
|
100
|
+
'.ogg': 'audio/ogg',
|
|
101
|
+
'.wav': 'audio/wav',
|
|
102
|
+
};
|
|
103
|
+
res.writeHead(200, { 'Content-Type': contentTypes[ext] || 'text/plain' });
|
|
104
|
+
res.end(data);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
server.listen(port, () => {
|
|
108
|
+
console.log(chalk.green(`🎵 Server running at http://localhost:${port}`));
|
|
109
|
+
console.log(chalk.blue(`Serving: ${dir}`));
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
async function initializeCatalog(targetDir) {
|
|
113
|
+
await fs.ensureDir(targetDir);
|
|
114
|
+
// Create catalog.yaml
|
|
115
|
+
const catalogYaml = `title: "My Music Catalog"
|
|
116
|
+
description: "Independent music releases"
|
|
117
|
+
url: "https://example.com"
|
|
118
|
+
basePath: "" # Leave empty for root deployment, use "/repo-name" for subdirectories
|
|
119
|
+
theme: "default"
|
|
120
|
+
language: "en"
|
|
121
|
+
`;
|
|
122
|
+
await fs.writeFile(path.join(targetDir, 'catalog.yaml'), catalogYaml);
|
|
123
|
+
// Create artist.yaml
|
|
124
|
+
const artistYaml = `name: "Artist Name"
|
|
125
|
+
bio: "Write your biography here."
|
|
126
|
+
links:
|
|
127
|
+
- website: "https://example.com"
|
|
128
|
+
- bandcamp: "https://artistname.bandcamp.com"
|
|
129
|
+
`;
|
|
130
|
+
await fs.writeFile(path.join(targetDir, 'artist.yaml'), artistYaml);
|
|
131
|
+
// Create releases directory with example
|
|
132
|
+
const exampleReleaseDir = path.join(targetDir, 'releases', 'example-album');
|
|
133
|
+
await fs.ensureDir(path.join(exampleReleaseDir, 'tracks'));
|
|
134
|
+
const releaseYaml = `title: "Example Album"
|
|
135
|
+
date: "${new Date().toISOString().split('T')[0]}"
|
|
136
|
+
description: "An amazing album"
|
|
137
|
+
download: "free"
|
|
138
|
+
genres:
|
|
139
|
+
- "Electronic"
|
|
140
|
+
- "Experimental"
|
|
141
|
+
`;
|
|
142
|
+
await fs.writeFile(path.join(exampleReleaseDir, 'release.yaml'), releaseYaml);
|
|
143
|
+
// Create README
|
|
144
|
+
const readme = `# My Music Catalog
|
|
145
|
+
|
|
146
|
+
This is your Tunecamp catalog.
|
|
147
|
+
|
|
148
|
+
## Structure
|
|
149
|
+
|
|
150
|
+
- \`catalog.yaml\` - Main catalog configuration
|
|
151
|
+
- \`artist.yaml\` - Artist information
|
|
152
|
+
- \`releases/\` - Your music releases
|
|
153
|
+
- Each subdirectory is a release
|
|
154
|
+
- Add \`release.yaml\` to configure each release
|
|
155
|
+
- Add audio files and cover art
|
|
156
|
+
|
|
157
|
+
## Usage
|
|
158
|
+
|
|
159
|
+
1. Add your music files to \`releases/your-album-name/tracks/\`
|
|
160
|
+
2. Add cover art (cover.jpg, cover.png, etc.)
|
|
161
|
+
3. Configure \`release.yaml\` for each album
|
|
162
|
+
4. Build: \`tunecamp build . -o public\`
|
|
163
|
+
5. Deploy the \`public\` folder
|
|
164
|
+
|
|
165
|
+
## Documentation
|
|
166
|
+
|
|
167
|
+
See https://github.com/scobru/tunecamp for full documentation.
|
|
168
|
+
`;
|
|
169
|
+
await fs.writeFile(path.join(targetDir, 'README.md'), readme);
|
|
170
|
+
}
|
|
171
|
+
program.parse();
|
|
172
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embed Widget Generator for Tunecamp
|
|
3
|
+
* Creates embeddable HTML widgets for releases
|
|
4
|
+
*/
|
|
5
|
+
import { Catalog, Release } from "../types/index.js";
|
|
6
|
+
export interface EmbedOptions {
|
|
7
|
+
siteUrl: string;
|
|
8
|
+
basePath: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Generates embeddable HTML widgets
|
|
12
|
+
*/
|
|
13
|
+
export declare class EmbedGenerator {
|
|
14
|
+
private catalog;
|
|
15
|
+
private options;
|
|
16
|
+
constructor(catalog: Catalog, options: EmbedOptions);
|
|
17
|
+
/**
|
|
18
|
+
* Get the full URL for a path
|
|
19
|
+
*/
|
|
20
|
+
private getUrl;
|
|
21
|
+
/**
|
|
22
|
+
* Generate embed HTML for a release
|
|
23
|
+
*/
|
|
24
|
+
generateReleaseEmbed(release: Release): string;
|
|
25
|
+
/**
|
|
26
|
+
* Generate compact embed (smaller widget)
|
|
27
|
+
*/
|
|
28
|
+
generateCompactEmbed(release: Release): string;
|
|
29
|
+
/**
|
|
30
|
+
* Generate iframe embed code
|
|
31
|
+
*/
|
|
32
|
+
generateIframeEmbed(release: Release, width?: number, height?: number): string;
|
|
33
|
+
/**
|
|
34
|
+
* Escape HTML special characters
|
|
35
|
+
*/
|
|
36
|
+
private escapeHtml;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=embedGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedGenerator.d.ts","sourceRoot":"","sources":["../../src/generator/embedGenerator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,YAAY;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,OAAO,CAAe;gBAElB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY;IAKnD;;OAEG;IACH,OAAO,CAAC,MAAM;IAMd;;OAEG;IACH,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IA8B9C;;OAEG;IACH,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IAiB9C;;OAEG;IACH,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,GAAE,MAAY,EAAE,MAAM,GAAE,MAAY,GAAG,MAAM;IAKxF;;OAEG;IACH,OAAO,CAAC,UAAU;CAQrB"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embed Widget Generator for Tunecamp
|
|
3
|
+
* Creates embeddable HTML widgets for releases
|
|
4
|
+
*/
|
|
5
|
+
import path from "path";
|
|
6
|
+
/**
|
|
7
|
+
* Generates embeddable HTML widgets
|
|
8
|
+
*/
|
|
9
|
+
export class EmbedGenerator {
|
|
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
|
+
* Generate embed HTML for a release
|
|
26
|
+
*/
|
|
27
|
+
generateReleaseEmbed(release) {
|
|
28
|
+
const releaseUrl = this.getUrl(`releases/${release.slug}/index.html`);
|
|
29
|
+
const coverUrl = release.coverPath
|
|
30
|
+
? this.getUrl(`releases/${release.slug}/${path.basename(release.coverPath)}`)
|
|
31
|
+
: null;
|
|
32
|
+
const artistName = this.catalog.artist?.name || "Unknown Artist";
|
|
33
|
+
const trackCount = release.tracks.length;
|
|
34
|
+
const firstTrackUrl = release.tracks.length > 0
|
|
35
|
+
? this.getUrl(`releases/${release.slug}/${path.basename(release.tracks[0].file)}`)
|
|
36
|
+
: null;
|
|
37
|
+
// Compact embed widget with inline styles
|
|
38
|
+
return `<!-- Tunecamp Embed: ${release.config.title} -->
|
|
39
|
+
<div style="font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;max-width:400px;background:#1e293b;border-radius:12px;overflow:hidden;box-shadow:0 4px 20px rgba(0,0,0,0.3);">
|
|
40
|
+
<a href="${releaseUrl}" target="_blank" style="text-decoration:none;color:inherit;display:block;">
|
|
41
|
+
${coverUrl ? `<img src="${coverUrl}" alt="${this.escapeHtml(release.config.title)}" style="width:100%;display:block;aspect-ratio:1;object-fit:cover;">` : `<div style="width:100%;aspect-ratio:1;background:linear-gradient(135deg,#6366f1,#8b5cf6);display:flex;align-items:center;justify-content:center;font-size:4rem;color:rgba(255,255,255,0.3);">♪</div>`}
|
|
42
|
+
<div style="padding:1rem;">
|
|
43
|
+
<div style="font-size:1.1rem;font-weight:600;color:#f1f5f9;margin-bottom:0.25rem;">${this.escapeHtml(release.config.title)}</div>
|
|
44
|
+
<div style="font-size:0.9rem;color:#94a3b8;">${this.escapeHtml(artistName)}</div>
|
|
45
|
+
<div style="font-size:0.8rem;color:#64748b;margin-top:0.5rem;">${trackCount} track${trackCount !== 1 ? 's' : ''}</div>
|
|
46
|
+
</div>
|
|
47
|
+
</a>
|
|
48
|
+
${firstTrackUrl ? `<audio controls style="width:100%;height:40px;" preload="none"><source src="${firstTrackUrl}" type="audio/mpeg">Your browser does not support audio.</audio>` : ''}
|
|
49
|
+
<div style="padding:0.5rem 1rem;background:#0f172a;font-size:0.7rem;color:#64748b;text-align:right;">
|
|
50
|
+
Powered by <a href="https://github.com/scobru/tunecamp" target="_blank" style="color:#6366f1;text-decoration:none;">Tunecamp</a>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
<!-- End Tunecamp Embed -->`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generate compact embed (smaller widget)
|
|
57
|
+
*/
|
|
58
|
+
generateCompactEmbed(release) {
|
|
59
|
+
const releaseUrl = this.getUrl(`releases/${release.slug}/index.html`);
|
|
60
|
+
const coverUrl = release.coverPath
|
|
61
|
+
? this.getUrl(`releases/${release.slug}/${path.basename(release.coverPath)}`)
|
|
62
|
+
: null;
|
|
63
|
+
const artistName = this.catalog.artist?.name || "Unknown Artist";
|
|
64
|
+
return `<!-- Tunecamp Compact Embed -->
|
|
65
|
+
<a href="${releaseUrl}" target="_blank" style="display:inline-flex;align-items:center;gap:0.75rem;padding:0.5rem;background:#1e293b;border-radius:8px;text-decoration:none;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;max-width:300px;">
|
|
66
|
+
${coverUrl ? `<img src="${coverUrl}" alt="${this.escapeHtml(release.config.title)}" style="width:48px;height:48px;border-radius:4px;object-fit:cover;">` : `<div style="width:48px;height:48px;border-radius:4px;background:linear-gradient(135deg,#6366f1,#8b5cf6);display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,0.5);">♪</div>`}
|
|
67
|
+
<div style="min-width:0;">
|
|
68
|
+
<div style="font-size:0.9rem;font-weight:500;color:#f1f5f9;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">${this.escapeHtml(release.config.title)}</div>
|
|
69
|
+
<div style="font-size:0.75rem;color:#94a3b8;">${this.escapeHtml(artistName)}</div>
|
|
70
|
+
</div>
|
|
71
|
+
</a>`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Generate iframe embed code
|
|
75
|
+
*/
|
|
76
|
+
generateIframeEmbed(release, width = 400, height = 300) {
|
|
77
|
+
const embedUrl = this.getUrl(`releases/${release.slug}/embed.html`);
|
|
78
|
+
return `<iframe src="${embedUrl}" width="${width}" height="${height}" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe>`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Escape HTML special characters
|
|
82
|
+
*/
|
|
83
|
+
escapeHtml(str) {
|
|
84
|
+
return str
|
|
85
|
+
.replace(/&/g, "&")
|
|
86
|
+
.replace(/</g, "<")
|
|
87
|
+
.replace(/>/g, ">")
|
|
88
|
+
.replace(/"/g, """)
|
|
89
|
+
.replace(/'/g, "'");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=embedGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedGenerator.js","sourceRoot":"","sources":["../../src/generator/embedGenerator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RSS and Atom Feed Generator for Tunecamp
|
|
3
|
+
* Generates feed.xml (RSS 2.0) and atom.xml feeds
|
|
4
|
+
*/
|
|
5
|
+
import { Catalog } from "../types/index.js";
|
|
6
|
+
export interface FeedOptions {
|
|
7
|
+
siteUrl: string;
|
|
8
|
+
basePath: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Generates RSS 2.0 and Atom feeds from catalog
|
|
12
|
+
*/
|
|
13
|
+
export declare class FeedGenerator {
|
|
14
|
+
private catalog;
|
|
15
|
+
private options;
|
|
16
|
+
constructor(catalog: Catalog, options: FeedOptions);
|
|
17
|
+
/**
|
|
18
|
+
* Get the full URL for a path
|
|
19
|
+
*/
|
|
20
|
+
private getUrl;
|
|
21
|
+
/**
|
|
22
|
+
* Format date for RSS (RFC 822)
|
|
23
|
+
*/
|
|
24
|
+
private formatRssDate;
|
|
25
|
+
/**
|
|
26
|
+
* Format date for Atom (ISO 8601)
|
|
27
|
+
*/
|
|
28
|
+
private formatAtomDate;
|
|
29
|
+
/**
|
|
30
|
+
* Escape XML special characters
|
|
31
|
+
*/
|
|
32
|
+
private escapeXml;
|
|
33
|
+
/**
|
|
34
|
+
* Generate RSS 2.0 feed
|
|
35
|
+
*/
|
|
36
|
+
generateRssFeed(): string;
|
|
37
|
+
/**
|
|
38
|
+
* Generate a single RSS item for a release
|
|
39
|
+
*/
|
|
40
|
+
private generateRssItem;
|
|
41
|
+
/**
|
|
42
|
+
* Generate Atom feed
|
|
43
|
+
*/
|
|
44
|
+
generateAtomFeed(): string;
|
|
45
|
+
/**
|
|
46
|
+
* Generate a single Atom entry for a release
|
|
47
|
+
*/
|
|
48
|
+
private generateAtomEntry;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=feedGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedGenerator.d.ts","sourceRoot":"","sources":["../../src/generator/feedGenerator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAW,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,aAAa;IACtB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,OAAO,CAAc;gBAEjB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW;IAKlD;;OAEG;IACH,OAAO,CAAC,MAAM;IAMd;;OAEG;IACH,OAAO,CAAC,aAAa;IAKrB;;OAEG;IACH,OAAO,CAAC,cAAc;IAKtB;;OAEG;IACH,OAAO,CAAC,SAAS;IASjB;;OAEG;IACH,eAAe,IAAI,MAAM;IAmCzB;;OAEG;IACH,OAAO,CAAC,eAAe;IA0BvB;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAkC1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;CA6B5B"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RSS and Atom Feed Generator for Tunecamp
|
|
3
|
+
* Generates feed.xml (RSS 2.0) and atom.xml feeds
|
|
4
|
+
*/
|
|
5
|
+
import path from "path";
|
|
6
|
+
/**
|
|
7
|
+
* Generates RSS 2.0 and Atom feeds from catalog
|
|
8
|
+
*/
|
|
9
|
+
export class FeedGenerator {
|
|
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
|
+
* Format date for Atom (ISO 8601)
|
|
33
|
+
*/
|
|
34
|
+
formatAtomDate(dateStr) {
|
|
35
|
+
const date = new Date(dateStr);
|
|
36
|
+
return date.toISOString();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Escape XML special characters
|
|
40
|
+
*/
|
|
41
|
+
escapeXml(str) {
|
|
42
|
+
return str
|
|
43
|
+
.replace(/&/g, "&")
|
|
44
|
+
.replace(/</g, "<")
|
|
45
|
+
.replace(/>/g, ">")
|
|
46
|
+
.replace(/"/g, """)
|
|
47
|
+
.replace(/'/g, "'");
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Generate RSS 2.0 feed
|
|
51
|
+
*/
|
|
52
|
+
generateRssFeed() {
|
|
53
|
+
const title = this.escapeXml(this.catalog.config.title);
|
|
54
|
+
const description = this.escapeXml(this.catalog.config.description || "Music releases");
|
|
55
|
+
const link = this.getUrl("");
|
|
56
|
+
const language = this.catalog.config.language || "en";
|
|
57
|
+
const artistName = this.catalog.artist?.name || "Unknown Artist";
|
|
58
|
+
const now = new Date().toUTCString();
|
|
59
|
+
// Sort releases by date (newest first)
|
|
60
|
+
const sortedReleases = [...this.catalog.releases].sort((a, b) => new Date(b.config.date).getTime() - new Date(a.config.date).getTime());
|
|
61
|
+
const items = sortedReleases
|
|
62
|
+
.filter((release) => !release.config.unlisted)
|
|
63
|
+
.map((release) => this.generateRssItem(release))
|
|
64
|
+
.join("\n");
|
|
65
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
66
|
+
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
|
|
67
|
+
<channel>
|
|
68
|
+
<title>${title}</title>
|
|
69
|
+
<link>${link}</link>
|
|
70
|
+
<description>${description}</description>
|
|
71
|
+
<language>${language}</language>
|
|
72
|
+
<lastBuildDate>${now}</lastBuildDate>
|
|
73
|
+
<generator>Tunecamp</generator>
|
|
74
|
+
<atom:link href="${this.getUrl("feed.xml")}" rel="self" type="application/rss+xml"/>
|
|
75
|
+
<itunes:author>${this.escapeXml(artistName)}</itunes:author>
|
|
76
|
+
<itunes:category text="Music"/>
|
|
77
|
+
${items}
|
|
78
|
+
</channel>
|
|
79
|
+
</rss>`;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Generate a single RSS item for a release
|
|
83
|
+
*/
|
|
84
|
+
generateRssItem(release) {
|
|
85
|
+
const title = this.escapeXml(release.config.title);
|
|
86
|
+
const description = this.escapeXml(release.config.description || `New release: ${release.config.title}`);
|
|
87
|
+
const link = this.getUrl(`releases/${release.slug}/index.html`);
|
|
88
|
+
const pubDate = this.formatRssDate(release.config.date);
|
|
89
|
+
const guid = this.getUrl(`releases/${release.slug}/`);
|
|
90
|
+
let coverEnclosure = "";
|
|
91
|
+
if (release.coverPath) {
|
|
92
|
+
const coverUrl = this.getUrl(`releases/${release.slug}/${path.basename(release.coverPath)}`);
|
|
93
|
+
coverEnclosure = ` <enclosure url="${coverUrl}" type="image/jpeg"/>`;
|
|
94
|
+
}
|
|
95
|
+
const trackCount = release.tracks.length;
|
|
96
|
+
const genres = release.config.genres?.map((g) => this.escapeXml(g)).join(", ") || "";
|
|
97
|
+
return ` <item>
|
|
98
|
+
<title>${title}</title>
|
|
99
|
+
<link>${link}</link>
|
|
100
|
+
<description><![CDATA[${description}${trackCount > 0 ? ` (${trackCount} tracks)` : ""}${genres ? ` - ${genres}` : ""}]]></description>
|
|
101
|
+
<pubDate>${pubDate}</pubDate>
|
|
102
|
+
<guid isPermaLink="true">${guid}</guid>
|
|
103
|
+
${coverEnclosure}
|
|
104
|
+
</item>`;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Generate Atom feed
|
|
108
|
+
*/
|
|
109
|
+
generateAtomFeed() {
|
|
110
|
+
const title = this.escapeXml(this.catalog.config.title);
|
|
111
|
+
const subtitle = this.escapeXml(this.catalog.config.description || "Music releases");
|
|
112
|
+
const link = this.getUrl("");
|
|
113
|
+
const feedUrl = this.getUrl("atom.xml");
|
|
114
|
+
const artistName = this.catalog.artist?.name || "Unknown Artist";
|
|
115
|
+
const now = this.formatAtomDate(new Date().toISOString());
|
|
116
|
+
// Sort releases by date (newest first)
|
|
117
|
+
const sortedReleases = [...this.catalog.releases].sort((a, b) => new Date(b.config.date).getTime() - new Date(a.config.date).getTime());
|
|
118
|
+
const entries = sortedReleases
|
|
119
|
+
.filter((release) => !release.config.unlisted)
|
|
120
|
+
.map((release) => this.generateAtomEntry(release))
|
|
121
|
+
.join("\n");
|
|
122
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
123
|
+
<feed xmlns="http://www.w3.org/2005/Atom">
|
|
124
|
+
<title>${title}</title>
|
|
125
|
+
<subtitle>${subtitle}</subtitle>
|
|
126
|
+
<link href="${link}" rel="alternate" type="text/html"/>
|
|
127
|
+
<link href="${feedUrl}" rel="self" type="application/atom+xml"/>
|
|
128
|
+
<id>${link}</id>
|
|
129
|
+
<updated>${now}</updated>
|
|
130
|
+
<generator uri="https://github.com/scobru/tunecamp" version="0.1.0">Tunecamp</generator>
|
|
131
|
+
<author>
|
|
132
|
+
<name>${this.escapeXml(artistName)}</name>
|
|
133
|
+
</author>
|
|
134
|
+
${entries}
|
|
135
|
+
</feed>`;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Generate a single Atom entry for a release
|
|
139
|
+
*/
|
|
140
|
+
generateAtomEntry(release) {
|
|
141
|
+
const title = this.escapeXml(release.config.title);
|
|
142
|
+
const summary = this.escapeXml(release.config.description || `New release: ${release.config.title}`);
|
|
143
|
+
const link = this.getUrl(`releases/${release.slug}/index.html`);
|
|
144
|
+
const id = this.getUrl(`releases/${release.slug}/`);
|
|
145
|
+
const updated = this.formatAtomDate(release.config.date);
|
|
146
|
+
const published = this.formatAtomDate(release.config.date);
|
|
147
|
+
const trackCount = release.tracks.length;
|
|
148
|
+
const genres = release.config.genres?.join(", ") || "";
|
|
149
|
+
let content = `<p>${summary}</p>`;
|
|
150
|
+
if (trackCount > 0) {
|
|
151
|
+
content += `<p>Tracks: ${trackCount}</p>`;
|
|
152
|
+
}
|
|
153
|
+
if (genres) {
|
|
154
|
+
content += `<p>Genres: ${genres}</p>`;
|
|
155
|
+
}
|
|
156
|
+
return ` <entry>
|
|
157
|
+
<title>${title}</title>
|
|
158
|
+
<link href="${link}" rel="alternate" type="text/html"/>
|
|
159
|
+
<id>${id}</id>
|
|
160
|
+
<updated>${updated}</updated>
|
|
161
|
+
<published>${published}</published>
|
|
162
|
+
<summary>${summary}</summary>
|
|
163
|
+
<content type="html"><![CDATA[${content}]]></content>
|
|
164
|
+
</entry>`;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=feedGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedGenerator.js","sourceRoot":"","sources":["../../src/generator/feedGenerator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Podcast RSS Feed Generator for Tunecamp
|
|
3
|
+
* Creates podcast-specific RSS feeds for episodic content
|
|
4
|
+
*/
|
|
5
|
+
import { Catalog } from "../types/index.js";
|
|
6
|
+
export interface PodcastOptions {
|
|
7
|
+
siteUrl: string;
|
|
8
|
+
basePath: string;
|
|
9
|
+
podcastTitle?: string;
|
|
10
|
+
podcastDescription?: string;
|
|
11
|
+
podcastAuthor?: string;
|
|
12
|
+
podcastEmail?: string;
|
|
13
|
+
podcastCategory?: string;
|
|
14
|
+
podcastImage?: string;
|
|
15
|
+
explicit?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generates podcast-specific RSS 2.0 feeds
|
|
19
|
+
*/
|
|
20
|
+
export declare class PodcastFeedGenerator {
|
|
21
|
+
private catalog;
|
|
22
|
+
private options;
|
|
23
|
+
constructor(catalog: Catalog, options: PodcastOptions);
|
|
24
|
+
/**
|
|
25
|
+
* Get the full URL for a path
|
|
26
|
+
*/
|
|
27
|
+
private getUrl;
|
|
28
|
+
/**
|
|
29
|
+
* Format date for RSS (RFC 822)
|
|
30
|
+
*/
|
|
31
|
+
private formatRssDate;
|
|
32
|
+
/**
|
|
33
|
+
* Escape XML special characters
|
|
34
|
+
*/
|
|
35
|
+
private escapeXml;
|
|
36
|
+
/**
|
|
37
|
+
* Format duration in HH:MM:SS format for iTunes
|
|
38
|
+
*/
|
|
39
|
+
private formatItunesDuration;
|
|
40
|
+
/**
|
|
41
|
+
* Get MIME type for audio file
|
|
42
|
+
*/
|
|
43
|
+
private getAudioMimeType;
|
|
44
|
+
/**
|
|
45
|
+
* Generate Podcast RSS feed
|
|
46
|
+
* Each track becomes an episode
|
|
47
|
+
*/
|
|
48
|
+
generatePodcastFeed(): string;
|
|
49
|
+
/**
|
|
50
|
+
* Generate a single episode item
|
|
51
|
+
*/
|
|
52
|
+
private generateEpisodeItem;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=podcastFeedGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"podcastFeedGenerator.d.ts","sourceRoot":"","sources":["../../src/generator/podcastFeedGenerator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAA0B,MAAM,mBAAmB,CAAC;AAEpE,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,oBAAoB;IAC7B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,OAAO,CAAiB;gBAEpB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc;IAKrD;;OAEG;IACH,OAAO,CAAC,MAAM;IAMd;;OAEG;IACH,OAAO,CAAC,aAAa;IAKrB;;OAEG;IACH,OAAO,CAAC,SAAS;IASjB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAQ5B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAcxB;;;OAGG;IACH,mBAAmB,IAAI,MAAM;IA2E7B;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAiC9B"}
|