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,188 @@
|
|
|
1
|
+
<div class="container">
|
|
2
|
+
{{#if artist}}
|
|
3
|
+
<section class="artist-section">
|
|
4
|
+
<div class="artist-header">
|
|
5
|
+
{{#if artist.photo}}
|
|
6
|
+
<img src="{{path artist.photo}}" alt="{{artist.name}}" class="artist-photo">
|
|
7
|
+
{{/if}}
|
|
8
|
+
<div class="artist-info">
|
|
9
|
+
<h2>{{artist.name}}</h2>
|
|
10
|
+
{{#if artist.bio}}
|
|
11
|
+
<p class="artist-bio">{{artist.bio}}</p>
|
|
12
|
+
{{/if}}
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</section>
|
|
16
|
+
{{/if}}
|
|
17
|
+
|
|
18
|
+
<section class="releases-section">
|
|
19
|
+
<h2>Releases</h2>
|
|
20
|
+
|
|
21
|
+
<!-- Search and Filter Controls -->
|
|
22
|
+
<div class="releases-controls">
|
|
23
|
+
<div class="search-box">
|
|
24
|
+
<i class="fas fa-search"></i>
|
|
25
|
+
<input type="text" id="searchInput" placeholder="Search releases..." autocomplete="off">
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div class="filter-controls">
|
|
29
|
+
<select id="genreFilter" class="filter-select">
|
|
30
|
+
<option value="">All Genres</option>
|
|
31
|
+
</select>
|
|
32
|
+
|
|
33
|
+
<select id="sortBy" class="filter-select">
|
|
34
|
+
<option value="date-desc">Newest First</option>
|
|
35
|
+
<option value="date-asc">Oldest First</option>
|
|
36
|
+
<option value="title-asc">Title A-Z</option>
|
|
37
|
+
<option value="title-desc">Title Z-A</option>
|
|
38
|
+
</select>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
{{#if releases}}
|
|
43
|
+
<div class="releases-grid" id="releasesGrid">
|
|
44
|
+
{{#each releases}}
|
|
45
|
+
<article class="release-card"
|
|
46
|
+
data-title="{{config.title}}"
|
|
47
|
+
data-date="{{config.date}}"
|
|
48
|
+
data-genres="{{#if config.genres}}{{join config.genres ","}}{{/if}}"
|
|
49
|
+
data-description="{{config.description}}">
|
|
50
|
+
<a href="{{path url}}" class="release-link">
|
|
51
|
+
{{#if coverUrl}}
|
|
52
|
+
<div class="release-cover">
|
|
53
|
+
<img src="{{path coverUrl}}" alt="{{config.title}}" loading="lazy">
|
|
54
|
+
</div>
|
|
55
|
+
{{else}}
|
|
56
|
+
<div class="release-cover release-cover-placeholder">
|
|
57
|
+
<i class="fas fa-music"></i>
|
|
58
|
+
</div>
|
|
59
|
+
{{/if}}
|
|
60
|
+
|
|
61
|
+
<div class="release-info">
|
|
62
|
+
<h3 class="release-title">{{config.title}}</h3>
|
|
63
|
+
<p class="release-date">{{formatDate config.date}}</p>
|
|
64
|
+
|
|
65
|
+
{{#if config.genres}}
|
|
66
|
+
<div class="release-genres">
|
|
67
|
+
{{#each config.genres}}
|
|
68
|
+
<span class="genre-tag">{{this}}</span>
|
|
69
|
+
{{/each}}
|
|
70
|
+
</div>
|
|
71
|
+
{{/if}}
|
|
72
|
+
|
|
73
|
+
<p class="release-tracks-count">
|
|
74
|
+
{{tracks.length}} track{{#unless (eq tracks.length 1)}}s{{/unless}}
|
|
75
|
+
</p>
|
|
76
|
+
|
|
77
|
+
{{#if config.download}}
|
|
78
|
+
<div class="release-download-badge">
|
|
79
|
+
{{#if (eq config.download "free")}}
|
|
80
|
+
<i class="fas fa-download"></i> Free Download
|
|
81
|
+
{{else if (eq config.download "paycurtain")}}
|
|
82
|
+
<i class="fas fa-dollar-sign"></i> Pay What You Want
|
|
83
|
+
{{else if (eq config.download "codes")}}
|
|
84
|
+
<i class="fas fa-key"></i> Download Codes
|
|
85
|
+
{{/if}}
|
|
86
|
+
</div>
|
|
87
|
+
{{/if}}
|
|
88
|
+
</div>
|
|
89
|
+
</a>
|
|
90
|
+
</article>
|
|
91
|
+
{{/each}}
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<p class="no-results" id="noResults" style="display: none;">No releases match your search.</p>
|
|
95
|
+
{{else}}
|
|
96
|
+
<p class="no-releases">No releases yet. Check back soon!</p>
|
|
97
|
+
{{/if}}
|
|
98
|
+
</section>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<script>
|
|
102
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
103
|
+
const searchInput = document.getElementById('searchInput');
|
|
104
|
+
const genreFilter = document.getElementById('genreFilter');
|
|
105
|
+
const sortBy = document.getElementById('sortBy');
|
|
106
|
+
const releasesGrid = document.getElementById('releasesGrid');
|
|
107
|
+
const noResults = document.getElementById('noResults');
|
|
108
|
+
|
|
109
|
+
if (!releasesGrid) return;
|
|
110
|
+
|
|
111
|
+
const releaseCards = Array.from(releasesGrid.querySelectorAll('.release-card'));
|
|
112
|
+
|
|
113
|
+
// Populate genre filter
|
|
114
|
+
const allGenres = new Set();
|
|
115
|
+
releaseCards.forEach(card => {
|
|
116
|
+
const genres = card.dataset.genres;
|
|
117
|
+
if (genres) {
|
|
118
|
+
genres.split(',').forEach(g => allGenres.add(g.trim()));
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
Array.from(allGenres).sort().forEach(genre => {
|
|
123
|
+
const option = document.createElement('option');
|
|
124
|
+
option.value = genre;
|
|
125
|
+
option.textContent = genre;
|
|
126
|
+
genreFilter.appendChild(option);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
function filterAndSort() {
|
|
130
|
+
const searchTerm = searchInput.value.toLowerCase();
|
|
131
|
+
const selectedGenre = genreFilter.value;
|
|
132
|
+
const sortValue = sortBy.value;
|
|
133
|
+
|
|
134
|
+
// Filter
|
|
135
|
+
let visibleCards = releaseCards.filter(card => {
|
|
136
|
+
const title = (card.dataset.title || '').toLowerCase();
|
|
137
|
+
const description = (card.dataset.description || '').toLowerCase();
|
|
138
|
+
const genres = card.dataset.genres || '';
|
|
139
|
+
|
|
140
|
+
const matchesSearch = !searchTerm ||
|
|
141
|
+
title.includes(searchTerm) ||
|
|
142
|
+
description.includes(searchTerm);
|
|
143
|
+
|
|
144
|
+
const matchesGenre = !selectedGenre ||
|
|
145
|
+
genres.split(',').map(g => g.trim()).includes(selectedGenre);
|
|
146
|
+
|
|
147
|
+
return matchesSearch && matchesGenre;
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Sort
|
|
151
|
+
visibleCards.sort((a, b) => {
|
|
152
|
+
switch (sortValue) {
|
|
153
|
+
case 'date-desc':
|
|
154
|
+
return new Date(b.dataset.date) - new Date(a.dataset.date);
|
|
155
|
+
case 'date-asc':
|
|
156
|
+
return new Date(a.dataset.date) - new Date(b.dataset.date);
|
|
157
|
+
case 'title-asc':
|
|
158
|
+
return (a.dataset.title || '').localeCompare(b.dataset.title || '');
|
|
159
|
+
case 'title-desc':
|
|
160
|
+
return (b.dataset.title || '').localeCompare(a.dataset.title || '');
|
|
161
|
+
default:
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Apply visibility and order
|
|
167
|
+
releaseCards.forEach(card => {
|
|
168
|
+
card.style.display = 'none';
|
|
169
|
+
card.style.order = '';
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
visibleCards.forEach((card, index) => {
|
|
173
|
+
card.style.display = '';
|
|
174
|
+
card.style.order = index;
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Show/hide no results message
|
|
178
|
+
if (noResults) {
|
|
179
|
+
noResults.style.display = visibleCards.length === 0 ? 'block' : 'none';
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
searchInput.addEventListener('input', filterAndSort);
|
|
184
|
+
genreFilter.addEventListener('change', filterAndSort);
|
|
185
|
+
sortBy.addEventListener('change', filterAndSort);
|
|
186
|
+
});
|
|
187
|
+
</script>
|
|
188
|
+
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="{{catalog.language}}" data-theme="dark">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>{{#if pageTitle}}{{pageTitle}} - {{/if}}{{catalog.title}}</title>
|
|
8
|
+
{{#if catalog.description}}
|
|
9
|
+
<meta name="description" content="{{catalog.description}}">
|
|
10
|
+
{{/if}}
|
|
11
|
+
<!-- Tunecamp Metadata (for community registry) -->
|
|
12
|
+
<meta name="generator" content="Tunecamp 0.1.0">
|
|
13
|
+
<meta name="tunecamp-title" content="{{catalog.title}}">
|
|
14
|
+
{{#if artist}}
|
|
15
|
+
<meta name="tunecamp-artist" content="{{artist.name}}">
|
|
16
|
+
{{/if}}
|
|
17
|
+
<!-- RSS/Atom Feeds -->
|
|
18
|
+
<link rel="alternate" type="application/rss+xml" title="{{catalog.title}} RSS Feed" href="{{assetPath 'feed.xml'}}">
|
|
19
|
+
<link rel="alternate" type="application/atom+xml" title="{{catalog.title}} Atom Feed" href="{{assetPath 'atom.xml'}}">
|
|
20
|
+
{{#if catalog.customFontUrl}}
|
|
21
|
+
<link rel="stylesheet" href="{{catalog.customFontUrl}}">
|
|
22
|
+
{{/if}}
|
|
23
|
+
<link rel="stylesheet" href="{{assetPath "assets/style.css"}}">
|
|
24
|
+
{{#if catalog.customFontFamily}}
|
|
25
|
+
<style>
|
|
26
|
+
:root {
|
|
27
|
+
--custom-font-family: '{{catalog.customFontFamily}}', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
|
|
28
|
+
}
|
|
29
|
+
body {
|
|
30
|
+
font-family: var(--custom-font-family);
|
|
31
|
+
}
|
|
32
|
+
</style>
|
|
33
|
+
{{/if}}
|
|
34
|
+
{{#if catalog.customCSSUrl}}
|
|
35
|
+
{{#if (or (startsWith catalog.customCSSUrl "http://") (startsWith catalog.customCSSUrl "https://"))}}
|
|
36
|
+
<link rel="stylesheet" href="{{catalog.customCSSUrl}}">
|
|
37
|
+
{{else}}
|
|
38
|
+
<link rel="stylesheet" href="{{path catalog.customCSSUrl}}">
|
|
39
|
+
{{/if}}
|
|
40
|
+
{{/if}}
|
|
41
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
42
|
+
<script>
|
|
43
|
+
// Initialize theme from localStorage or system preference
|
|
44
|
+
(function () {
|
|
45
|
+
const saved = localStorage.getItem('theme');
|
|
46
|
+
if (saved) {
|
|
47
|
+
document.documentElement.setAttribute('data-theme', saved);
|
|
48
|
+
} else if (window.matchMedia('(prefers-color-scheme: light)').matches) {
|
|
49
|
+
document.documentElement.setAttribute('data-theme', 'light');
|
|
50
|
+
}
|
|
51
|
+
})();
|
|
52
|
+
</script>
|
|
53
|
+
</head>
|
|
54
|
+
|
|
55
|
+
<body>
|
|
56
|
+
<header class="site-header">
|
|
57
|
+
<div class="container">
|
|
58
|
+
{{#if catalog.headerImageUrl}}
|
|
59
|
+
<div class="header-image-wrapper">
|
|
60
|
+
<div class="site-header-image">
|
|
61
|
+
<a href="{{#if backUrl}}{{path backUrl}}{{else}}{{path "index.html"}}{{/if}}">
|
|
62
|
+
<img src="{{path catalog.headerImageUrl}}" alt="{{catalog.title}}" class="header-image">
|
|
63
|
+
</a>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
{{else}}
|
|
67
|
+
<div class="header-row">
|
|
68
|
+
<h1 class="site-title">
|
|
69
|
+
<a href="{{#if backUrl}}{{path backUrl}}{{else}}{{path "index.html"}}{{/if}}">{{catalog.title}}</a>
|
|
70
|
+
</h1>
|
|
71
|
+
</div>
|
|
72
|
+
{{/if}}
|
|
73
|
+
{{#if catalog.description}}
|
|
74
|
+
{{#unless catalog.headerImageUrl}}
|
|
75
|
+
<p class="site-description">{{catalog.description}}</p>
|
|
76
|
+
{{/unless}}
|
|
77
|
+
{{/if}}
|
|
78
|
+
</div>
|
|
79
|
+
</header>
|
|
80
|
+
|
|
81
|
+
<main class="site-main">
|
|
82
|
+
{{{content}}}
|
|
83
|
+
</main>
|
|
84
|
+
|
|
85
|
+
<footer class="site-footer">
|
|
86
|
+
<div class="container">
|
|
87
|
+
<p>
|
|
88
|
+
{{#if artist}}
|
|
89
|
+
© {{artist.name}} -
|
|
90
|
+
{{/if}}
|
|
91
|
+
Powered by <a href="https://github.com/scobru/tunecamp" target="_blank">Tunecamp</a>
|
|
92
|
+
</p>
|
|
93
|
+
{{#if artist.links}}
|
|
94
|
+
<div class="social-links">
|
|
95
|
+
{{#each artist.links}}
|
|
96
|
+
{{#each this}}
|
|
97
|
+
<a href="{{this}}" target="_blank" rel="noopener" class="social-link">
|
|
98
|
+
<i class="fab fa-{{@key}}"></i>
|
|
99
|
+
</a>
|
|
100
|
+
{{/each}}
|
|
101
|
+
{{/each}}
|
|
102
|
+
</div>
|
|
103
|
+
{{/if}}
|
|
104
|
+
</div>
|
|
105
|
+
</footer>
|
|
106
|
+
|
|
107
|
+
<script src="{{assetPath "assets/player.js"}}"></script>
|
|
108
|
+
|
|
109
|
+
<!-- Interactive Theme Widget -->
|
|
110
|
+
<script src="{{assetPath "assets/theme-widget.js"}}"></script>
|
|
111
|
+
|
|
112
|
+
<!-- Tunecamp Community Registry (auto-registers site) -->
|
|
113
|
+
<script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
|
|
114
|
+
<script src="{{assetPath "assets/community-registry.js"}}"></script>
|
|
115
|
+
</body>
|
|
116
|
+
|
|
117
|
+
</html>
|