UNPKG

lyric-karaoke-cli

Version:

A CLI application for displaying song lyrics in a karaoke-style format

240 lines (213 loc) 6.09 kB
/** * Caching module for storing fetched song data */ const fs = require('fs').promises; const path = require('path'); const { logger } = require('../utils'); // Cache directory path const CACHE_DIR = path.join(process.cwd(), '.cache'); const CACHE_FILE = path.join(CACHE_DIR, 'songs.json'); const CACHE_EXPIRY = 24 * 60 * 60 * 1000; // 24 hours in milliseconds // Cache object to store data in memory let cache = {}; /** * Initialize cache */ async function init() { try { // Create cache directory if it doesn't exist await fs.mkdir(CACHE_DIR, { recursive: true }); // Load cache from file if it exists try { const data = await fs.readFile(CACHE_FILE, 'utf8'); cache = JSON.parse(data); // Clean expired cache entries const now = Date.now(); Object.keys(cache).forEach(key => { if (now - cache[key].timestamp > CACHE_EXPIRY) { delete cache[key]; } }); await saveCache(); logger.info('Cache loaded successfully'); } catch (error) { if (error.code !== 'ENOENT') { logger.error('Error loading cache:', error.message); } // Initialize empty cache if file doesn't exist or can't be read cache = {}; await saveCache(); logger.info('Initialized new cache'); } } catch (error) { logger.error('Failed to initialize cache:', error.message); throw error; } } /** * Save cache to file */ async function saveCache() { try { await fs.writeFile(CACHE_FILE, JSON.stringify(cache, null, 2), 'utf8'); } catch (error) { logger.error('Error saving cache:', error.message); throw error; } } /** * Get cached data by key * @param {string} key - Cache key * @returns {Promise<any>} - Cached data or null if not found/expired */ async function get(key) { try { const cacheEntry = cache[key]; if (!cacheEntry) { return null; } const now = Date.now(); if (now - cacheEntry.timestamp > CACHE_EXPIRY) { // Entry has expired delete cache[key]; await saveCache(); return null; } return cacheEntry.data; } catch (error) { logger.error('Error retrieving from cache:', error.message); return null; } } /** * Set data in cache * @param {string} key - Cache key * @param {any} data - Data to cache * @returns {Promise<void>} */ async function set(key, data) { try { cache[key] = { data, timestamp: Date.now() }; await saveCache(); } catch (error) { logger.error('Error setting cache:', error.message); throw error; } } /** * Clear the cache * @returns {Promise<void>} */ async function clear() { try { cache = {}; await saveCache(); logger.info('Cache cleared successfully'); } catch (error) { logger.error('Error clearing cache:', error.message); throw error; } } /** * Get list of recent songs from cache * @returns {Promise<Array>} - List of recent songs */ async function getRecentSongs() { try { const songEntries = Object.entries(cache) .filter(([key, _]) => key.startsWith('song:')) .map(([_, entry]) => ({ ...entry.data, cachedAt: entry.timestamp })) .sort((a, b) => b.cachedAt - a.cachedAt) .slice(0, 10); // Get most recent 10 songs return songEntries; } catch (error) { logger.error('Error getting recent songs:', error.message); return []; } } /** * Store lyrics data in the cache * @param {string} artistName - Name of the artist * @param {string} songTitle - Title of the song * @param {string} lyrics - Full lyrics text * @param {Object} metadata - Additional song metadata * @returns {Promise<void>} */ async function store(artistName, songTitle, lyrics, metadata = {}) { try { const key = `lyrics:${artistName.toLowerCase()}:${songTitle.toLowerCase()}`; const data = { artistName, songTitle, lyrics, metadata, retrievedAt: new Date().toISOString() }; await set(key, data); logger.info(`Cached lyrics for "${songTitle}" by ${artistName}`); return true; } catch (error) { logger.error('Error storing lyrics in cache:', error.message); return false; } } /** * Retrieve lyrics data from the cache * @param {string} artistName - Name of the artist * @param {string} songTitle - Title of the song * @returns {Promise<Object|null>} - Lyrics data or null if not found */ async function retrieve(artistName, songTitle) { try { const key = `lyrics:${artistName.toLowerCase()}:${songTitle.toLowerCase()}`; const data = await get(key); if (!data) { logger.info(`No cached lyrics found for "${songTitle}" by ${artistName}`); return null; } logger.info(`Retrieved cached lyrics for "${songTitle}" by ${artistName}`); return data; } catch (error) { logger.error('Error retrieving lyrics from cache:', error.message); return null; } } /** * Get list of recent lyrics from cache * @param {number} limit - Maximum number of entries to return * @returns {Promise<Array>} - List of recent lyrics entries */ async function getRecentLyrics(limit = 10) { try { const lyricsEntries = Object.entries(cache) .filter(([key, _]) => key.startsWith('lyrics:')) .map(([_, entry]) => ({ artistName: entry.data.artistName, songTitle: entry.data.songTitle, retrievedAt: entry.data.retrievedAt, cachedAt: entry.timestamp })) .sort((a, b) => b.cachedAt - a.cachedAt) .slice(0, limit); return lyricsEntries; } catch (error) { logger.error('Error getting recent lyrics:', error.message); return []; } } module.exports = { init, get, set, clear, getRecentSongs, store, retrieve, getRecentLyrics };