ravenscott-rocks/app.js

138 lines
4.2 KiB
JavaScript
Raw Normal View History

2024-10-17 04:39:30 -04:00
const express = require('express');
const app = express();
const path = require('path');
const SoundCloud = require('soundcloud-scraper');
const client = new SoundCloud.Client();
const fs = require('fs');
const PORT = process.env.PORT || 6767;
let tracks = []; // Store the tracks globally
const CACHE_FILE = path.join(__dirname, 'cache.json');
// Helper function to create a slug from track title
function generateSlug(title) {
return title
.toLowerCase() // Ensure lowercase
.replace(/[^a-z0-9]+/g, '-') // Replace non-alphanumeric characters with hyphens
.replace(/(^-|-$)/g, ''); // Remove leading and trailing hyphens
}
// Helper function to read the cache
function readCache() {
if (fs.existsSync(CACHE_FILE)) {
const data = fs.readFileSync(CACHE_FILE, 'utf8');
return JSON.parse(data);
}
return null;
}
// Helper function to save cache
function saveCache(data) {
fs.writeFileSync(CACHE_FILE, JSON.stringify(data), 'utf8');
}
// Fetch playlist tracks from SoundCloud
async function fetchPlaylist() {
const playlist = await client.getPlaylist('https://soundcloud.com/snxraven/sets/raven-scott-metal');
return playlist.tracks.map(track => {
const slug = generateSlug(track.title); // Generate slug here
return {
title: track.title,
description: track.description || 'No description available',
url: track.url,
playCount: track.playCount || 0,
publishedAt: track.publishedAt || new Date().toISOString(),
slug // Save the slug in the track object
};
});
}
// Get tracks from cache or SoundCloud
async function getTracks(fetch = false) {
const cache = readCache();
const oneWeekInMs = 7 * 24 * 60 * 60 * 1000; // One week in milliseconds
const now = Date.now();
if (fetch || !cache || (now - cache.timestamp) > oneWeekInMs) {
// Fetch fresh tracks from SoundCloud
tracks = await fetchPlaylist();
saveCache({ tracks, timestamp: now });
} else {
// Load from cache
tracks = cache.tracks;
// Ensure slug generation in case it is missing from the cached data
tracks = tracks.map(track => {
if (!track.slug) {
track.slug = generateSlug(track.title);
}
return track;
});
}
// Sort by playCount first, then by publishedAt
tracks.sort((a, b) => {
if (b.playCount !== a.playCount) return b.playCount - a.playCount;
return new Date(b.publishedAt) - new Date(a.publishedAt);
});
return tracks;
}
// Serve static files from public directory
app.use(express.static(path.join(__dirname, 'public')));
// Set EJS as templating engine
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Home page route
app.get('/', async (req, res) => {
const allTracks = await getTracks();
res.render('index', { tracks: allTracks });
});
// Individual track page route
app.get('/track/:slug', async (req, res) => {
const allTracks = await getTracks();
const track = allTracks.find(t => t.slug === req.params.slug);
if (!track) {
return res.status(404).send('Track not found');
}
res.render('track', { track });
});
2024-10-17 04:47:46 -04:00
// JSON endpoint to return cached tracks
app.get('/json', async (req, res) => {
const allTracks = await getTracks();
res.json(allTracks);
});
// Sitemap endpoint
app.get('/sitemap.xml', async (req, res) => {
const allTracks = await getTracks();
let sitemap = `<?xml version="1.0" encoding="UTF-8"?>\n`;
sitemap += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n`;
// Home page
sitemap += `<url>\n <loc>https://raven-scott.rocks/</loc>\n <priority>1.0</priority>\n</url>\n`;
// Track pages
allTracks.forEach(track => {
sitemap += `<url>\n <loc>https://raven-scott.rocks/track/${track.slug}</loc>\n <priority>0.8</priority>\n</url>\n`;
});
sitemap += `</urlset>`;
res.header('Content-Type', 'application/xml');
res.send(sitemap);
});
2024-10-17 04:39:30 -04:00
// Listen on the specified port
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});