Raven Scott Music
Raven Scott Music is a sophisticated, dark-themed web application designed to curate and display music playlists from SoundCloud across multiple genres: Metal, Alt Rock, Rap, Lo-Fi, EDM, and Cuts. Built with Node.js, Express, and EJS, this project combines server-side rendering, efficient caching, pagination, and real-time updates via WebSockets to deliver a seamless music discovery experience. Whether you're a developer exploring the code or a music enthusiast browsing tracks, this app offers a robust, scalable foundation with a polished user interface.
Table of Contents
- Features
- Live Demo
- Prerequisites
- Installation
- Usage
- Technical Overview
- File Structure
- Tech Stack Rationale
- Configuration
- Deployment
- Development
- Troubleshooting
Features
- Genre-Specific Playlists: Dynamically fetches and displays tracks from SoundCloud playlists for Metal, Alt Rock, Rap, Lo-Fi, EDM, and Cuts.
- Pagination: Displays 4 tracks per page per genre, with Previous/Next buttons for efficient navigation.
- Real-Time Updates: Uses Socket.IO for dynamic loading of paginated track data without full page reloads.
- Efficient Caching: Stores playlist data in local JSON files, refreshing only after a week to minimize API calls and improve load times.
- Unique Slugs: Ensures track slugs are unique within each genre to prevent URL conflicts.
- Responsive UI: Leverages Bootstrap 4.5.2 and custom CSS for a mobile-friendly, dark-mode interface with orange accents.
- Track Pages: Dedicated pages for each track with embedded SoundCloud players, titles, and descriptions.
- SEO Optimization: Generates a
sitemap.xml
dynamically for better search engine visibility. - JSON API: Provides a RESTful endpoint (
/json/:genre
) for programmatic access to track data. - Custom Styling: Features a slim dark-mode scrollbar, animated navbar hover effects, and a cohesive aesthetic tailored for music lovers.
- Sorting Logic:
- Most genres: Tracks sorted by play count (descending), then publication date (newest first).
- Cuts genre: Tracks sorted by EP number extracted from titles (ascending).
Live Demo
Explore the live site at raven-scott.rocks. Navigate through Metal, Alt Rock, Rap, Lo-Fi, EDM, and Cuts sections using pagination controls, dive into individual track pages, or inspect the sitemap at /sitemap.xml
.
Prerequisites
To run this project locally, ensure you have:
- Node.js: Version 14.x or higher (includes npm).
- npm: Package manager for installing dependencies.
- SoundCloud Access: The playlists specified in
music_site.js
must be public and accessible via thesoundcloud.ts
library. - Git: For cloning the repository (optional but recommended).
Installation
-
Clone the Repository:
git clone https://git.ssh.surf/snxraven/ravenscott-rocks.git cd ravenscott-rocks
-
Install Dependencies:
npm install
This installs
express
,soundcloud.ts
,ejs
,socket.io
, and other required packages listed inpackage.json
. -
Optional: Environment Variables:
- Create a
.env
file in the root directory to customize the port:PORT=6767
- Alternatively, set the
PORT
variable in your terminal:export PORT=6767 # Linux/macOS set PORT=6767 # Windows
- Create a
-
Start the Server:
node music_site.js
The app will run on
http://localhost:6767
(or your specified port). Open this URL in your browser to begin exploring.
Usage
- Home Page (
/
): Displays paginated genre playlists with embedded SoundCloud players and "More Details" links. - Genre Navigation (
/#genre
): Use the navbar to jump to specific genres (e.g.,#metal
,#altrock
,#rap
). - Pagination: Use Previous/Next buttons to navigate through tracks in each genre (4 tracks per page).
- Track Details (
/:genre/track/:slug
): Click "More Details" to view a track’s page with its SoundCloud player and description. - JSON API (
/json/:genre
): Fetch raw track data for a genre (e.g.,http://localhost:6767/json/metal
) in JSON format. - Sitemap (
/sitemap.xml
): Access a dynamically generated sitemap for SEO purposes.
Example API response:
[
{
"title": "Heavy Riffs",
"description": "A brutal metal track.",
"url": "https://soundcloud.com/snxraven/heavy-riffs",
"embedUrl": "https://w.soundcloud.com/player/?url=https%3A//soundcloud.com/snxraven/heavy-riffs&color=%23ff5500&auto_play=false...",
"playCount": 1200,
"publishedAt": "2023-05-10T12:00:00Z",
"slug": "heavy-riffs"
}
]
Technical Overview
Backend
- Framework: Uses Express.js to handle routing, static file serving, and API endpoints.
- SoundCloud Integration: The
soundcloud.ts
library fetches playlist data, including track titles, URLs, play counts, and publication dates. - WebSockets: Socket.IO enables real-time pagination, handling
request_page
events to deliver paginated track data. - Routing:
/
: Renders the home page with paginated genre tracks./:genre
: Redirects to the home page’s genre section (e.g.,/#metal
)./:genre/track/:slug
: Renders individual track pages using unique slugs./json/:genre
: Returns all track data for a genre in JSON./sitemap.xml
: Generates an XML sitemap with all track URLs.
- Slug Generation: Creates unique, URL-friendly slugs per genre (e.g., "Heavy Riffs" →
heavy-riffs
) with conflict resolution. - Pagination: Limits to 4 tracks per page, with server-side logic to calculate total pages and track subsets.
Frontend
- Templating: EJS renders dynamic HTML with paginated track data.
- Styling:
- Bootstrap 4.5.2 (via CDN) provides the grid system and card components.
- Custom CSS adds a dark theme, orange buttons, a fixed navbar with hover animations, a slim scrollbar, and pagination styling.
- Interactivity:
- Socket.IO client handles real-time page requests and updates.
- Client-side caching stores rendered pages to minimize server requests.
- Lazy-loaded iframes optimize performance by loading SoundCloud players only when in view.
- Scripts: jQuery, Popper.js, Bootstrap JS, and Socket.IO (via CDN) enable navbar toggling, pagination, and WebSocket communication.
Caching Mechanism
- Purpose: Reduces API calls to SoundCloud by storing playlist data locally.
- Implementation:
- Cache files (
cache_metal.json
, etc.) store tracks and a timestamp. - The
getTracks
function checks if the cache is older than 1 week (configurable viaoneWeekInMs
). - If outdated or missing, it fetches fresh data and updates the cache.
- Cache files (
- Sorting:
- Standard genres: Sort by play count (highest first), then publication date (newest first).
- Cuts genre: Sort by EP number (ascending).
File Structure
raven-scott-music/
├── public/ # Static assets
│ └── css/ # Custom CSS (currently empty; styles are inline in EJS)
├── views/ # EJS templates
│ ├── index.ejs # Home page with paginated genre sections
│ ├── layout.ejs # Base layout (not fully utilized in this setup)
│ └── track.ejs # Individual track page
├── cache_metal.json # Cached Metal tracks (auto-generated)
├── cache_altrock.json # Cached Alt Rock tracks (auto-generated)
├── cache_rap.json # Cached Rap tracks (auto-generated)
├── cache_lofi.json # Cached Lo-Fi tracks (auto-generated)
├── cache_edm.json # Cached EDM tracks (auto-generated)
├── cache_cuts.json # Cached Cuts tracks (auto-generated)
├── music_site.js # Core server logic, routing, and WebSocket handling
├── package.json # Project metadata and dependencies
├── package-lock.json # Dependency lock file
└── README.md # This documentation
Tech Stack Rationale
- Node.js & Express: Lightweight and fast for building a server-side application with minimal overhead.
- soundcloud.ts: Simplifies fetching public playlist data without requiring an official API key.
- Socket.IO: Enables real-time pagination, improving user experience by avoiding full page reloads.
- EJS: Offers server-side rendering with easy integration into Express, ideal for dynamic content like playlists.
- Bootstrap: Speeds up development with pre-built components and ensures responsiveness.
- File-System Caching: A simple, effective solution for persistence without a database.
Configuration
- Playlists: Modify the
playlists
object inmusic_site.js
:const playlists = { metal: { url: 'https://soundcloud.com/snxraven/sets/raven-scott-metal', ... }, // Add new genres here };
- Cache Refresh: Adjust
oneWeekInMs
(in milliseconds) ingetTracks
:const oneWeekInMs = 7 * 24 * 60 * 60 * 1000; // Change to 24 * 60 * 60 * 1000 for daily refresh
- Pagination: Modify
TRACKS_PER_PAGE
inmusic_site.js
:const TRACKS_PER_PAGE = 4; // Change to desired tracks per page
- Port: Set via
.env
or directly inmusic_site.js
:const PORT = process.env.PORT || 6767;
Deployment
-
Prepare for Production:
- Set
NODE_ENV=production
to optimize Express. - Ensure
.env
includes the production port or use a platform-specific configuration.
- Set
-
Example: Deploy to Render:
- Push the repository to a Git service (e.g., GitHub).
- Create a new Web Service on Render, linking to your repository.
- Set environment variables:
PORT=6767 NODE_ENV=production
- Configure the start command:
node music_site.js
.
-
Verify:
- Check the deployed URL for functionality.
- Monitor logs for errors related to SoundCloud fetching or caching.
Development
Getting Started
- Fork and clone the repo.
- Install dependencies (
npm install
). - Run locally (
node music_site.js
). - Make changes and test in your browser.
Enhancement Ideas
- Database Integration: Replace file caching with MongoDB or SQLite for scalability.
- Search Functionality: Add a search bar to filter tracks by title or description.
- User Accounts: Implement authentication (e.g., with Passport.js) for favoriting tracks.
- Additional Platforms: Integrate Spotify or YouTube using their APIs.
- Analytics: Track page views or play counts with Google Analytics.
- Infinite Scroll: Replace pagination with infinite scroll for seamless track loading.
Troubleshooting
- SoundCloud Fetch Fails:
- Verify playlist URLs in
music_site.js
are correct and public. - Update
soundcloud.ts
(npm install soundcloud.ts@latest
).
- Verify playlist URLs in
- Cache Issues:
- Delete
cache_*.json
files and restart the server to force a refresh. - Check file permissions if cache files aren’t being written.
- Delete
- WebSocket Errors:
- Ensure Socket.IO client and server versions match (
npm install socket.io@latest
). - Check browser console for connection issues (e.g., CORS or port mismatches).
- Ensure Socket.IO client and server versions match (
- Pagination Problems:
- Verify
TRACKS_PER_PAGE
is set correctly. - Check server logs for errors in
getTracks
or WebSocket handlers.
- Verify
- Port Conflicts:
- Change the
PORT
value or kill the conflicting process:lsof -i :6767 # Linux/macOS kill -9 <PID>
- Change the
- 404 Errors:
- Ensure genre or slug matches the data (case-sensitive).
- Check console logs for errors during playlist fetching or slug generation.
- Styling Problems:
- Clear browser cache if CSS changes don’t appear.
- Verify CDN links for Bootstrap, jQuery, and Socket.IO are accessible.