Add holiday promotion, snowflakes effect, and Spotify music widget

- Added holiday promotion banner with 2026WITHMARINARA discount code
- Added dismiss functionality for promotion with persistent state
- Implemented snowflakes animation effect with toggle
- Added Spotify music widget above chat input
- Widget matches extension theme colors and positioning
- Added Display Options toggles to show/hide feature toggles
- Improved responsive design and mobile support
This commit is contained in:
Spicy_Marinara
2025-12-30 20:56:38 +01:00
parent 51535c5fdc
commit 3f58c7ceca
17 changed files with 1170 additions and 199 deletions
+79
View File
@@ -0,0 +1,79 @@
/**
* Music Player Module
* Handles parsing and storing Spotify URLs from AI responses
*/
import { extensionSettings, committedTrackerData } from '../../core/state.js';
/**
* Extracts song suggestion from AI response in <spotify:Song - Artist/> format
* @param {string} responseText - The raw AI response text
* @returns {Object|null} Object with {song, artist, searchQuery} or null if not found
*/
export function extractSpotifyUrl(responseText) {
if (!responseText || !extensionSettings.enableSpotifyMusic) return null;
// Match <spotify:Song Title - Artist Name/> format
const songMatch = responseText.match(/<spotify:([^<>-]+)\s*-\s*([^<>\/]+)\/>/i);
if (songMatch) {
const song = songMatch[1].trim();
const artist = songMatch[2].trim();
const searchQuery = `${song} ${artist}`;
return {
song,
artist,
searchQuery,
displayText: `${song} - ${artist}`
};
}
return null;
}
/**
* Converts song data to Spotify app protocol URL
* @param {Object} songData - Object with {song, artist, searchQuery}
* @returns {string} Spotify app protocol URL
*/
export function convertToEmbedUrl(songData) {
if (!songData || !songData.searchQuery) return '';
// Use Spotify app protocol for direct app opening
const encodedQuery = encodeURIComponent(songData.searchQuery);
return `spotify:search:${encodedQuery}`;
}
/**
* Parses AI response for song suggestion and stores it
* @param {string} responseText - The raw AI response text
* @returns {boolean} True if song was found and stored
*/
export function parseAndStoreSpotifyUrl(responseText) {
if (!extensionSettings.enableSpotifyMusic) return false;
const songData = extractSpotifyUrl(responseText);
console.log('[RPG Companion] Spotify Parser: Found song:', songData);
if (songData) {
// Store in committed tracker data
committedTrackerData.spotifyUrl = songData;
console.log('[RPG Companion] Spotify Parser: Stored song in committedTrackerData:', committedTrackerData.spotifyUrl);
return true;
}
return false;
}
/**
* Gets the current song data from committed tracker data
* @returns {Object|null} Current song data or null
*/
export function getCurrentSpotifyUrl() {
return committedTrackerData.spotifyUrl || null;
}
/**
* Clears the current song data
*/
export function clearSpotifyUrl() {
committedTrackerData.spotifyUrl = null;
}