Initial commit: KeySelector implementation

This commit is contained in:
Jannik committed 2026-08-26 00:32:17 +02:00
commit 48cdda01ca
30 files changed
+2272

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const path = require('path');
const recognizeRoute = require('./routes/recognize');
const metadataRoute = require('./routes/metadata');
const suggestionsRoute = require('./routes/suggestions');
const coverRoute = require('./routes/cover');
require('./workers/poll-quota'); // Start quota worker
const app = express();
const port = process.env.PORT || 3000;
app.use(cors());
app.use(express.json());
// Serve static frontend
app.use(express.static(path.join(__dirname, '../public')));
app.use('/shared', express.static(path.join(__dirname, '../shared')));
// API Routes
app.use('/api/recognize', recognizeRoute);
app.use('/api/metadata', metadataRoute);
app.use('/api/suggestions', suggestionsRoute);
app.use('/api/cover', coverRoute);
app.listen(port, () => {
console.log(`KeySelector backend listening on port ${port}`);
});
+15
View File
@@ -0,0 +1,15 @@
{
"name": "keyselector",
"version": "1.0.0",
"description": "Browser-basiertes DJ-Tool",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"node-fetch": "^3.3.2"
}
}
+27
View File
@@ -0,0 +1,27 @@
const express = require('express');
const fetch = require('node-fetch');
const router = express.Router();
// Fetch cover from iTunes API to avoid frontend CORS issues
router.get('/', async (req, res) => {
const q = req.query.q;
if (!q) return res.status(400).json({ error: 'Missing q parameter' });
try {
const url = `https://itunes.apple.com/search?term=${encodeURIComponent(q)}&media=music&entity=song&limit=1`;
const response = await fetch(url);
const data = await response.json();
if (data.results && data.results[0] && data.results[0].artworkUrl100) {
const src = data.results[0].artworkUrl100.replace('100x100bb', '300x300bb');
return res.json({ url: src });
}
res.json({ url: null });
} catch (err) {
console.error('iTunes cover fetch error', err);
res.status(500).json({ error: 'Server error fetching cover' });
}
});
module.exports = router;
+21
View File
@@ -0,0 +1,21 @@
const express = require('express');
const router = express.Router();
// Mock metadata route
router.get('/', async (req, res) => {
const track = req.query.track || 'Mock Track';
// In production, this would call GetSongBPM and Last.fm
// to fetch BPM, Camelot Key, and genre/mood tags.
res.json({
status: 'success',
data: {
key: '4B',
bpm: 120,
tags: ['Electronic', 'Synthpop']
}
});
});
module.exports = router;
+19
View File
@@ -0,0 +1,19 @@
const express = require('express');
const router = express.Router();
// Mock recognize route
router.post('/', async (req, res) => {
// In production, this would receive an audio buffer, fingerpint it,
// and call the AcoustID API.
res.json({
status: 'success',
data: {
title: 'Mock Track',
artist: 'Mock Artist',
matchScore: '95%'
}
});
});
module.exports = router;
+22
View File
@@ -0,0 +1,22 @@
const express = require('express');
const router = express.Router();
// const { mixingRules } = require('../../shared/mixing-rules');
// Mock suggestions route
router.get('/', async (req, res) => {
const key = req.query.key;
const bpm = parseInt(req.query.bpm) || 120;
// In production, this queries the PostgreSQL database populated with AcousticBrainz data
// to find tracks matching the compatible Camelot keys.
res.json({
status: 'success',
data: [
{ title: 'Suggestion 1', artist: 'Artist 1', key: '4A', bpm: bpm + 2 },
{ title: 'Suggestion 2', artist: 'Artist 2', key: '3B', bpm: bpm - 1 }
]
});
});
module.exports = router;
+14
View File
@@ -0,0 +1,14 @@
// Simple worker to simulate quota polling
const ntfyUrl = process.env.NTFY_URL;
function checkQuota() {
// In production, check API quotas for Last.fm, GetSongBPM, AcoustID
// and send a push notification via ntfy if they run low.
console.log('[Worker] Checking API quotas...');
}
// Check daily
setInterval(checkQuota, 24 * 60 * 60 * 1000);
// Run once on startup
setTimeout(checkQuota, 5000);