| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Mureka Music Generator</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| .glass-effect { |
| background: rgba(255, 255, 255, 0.15); |
| backdrop-filter: blur(10px); |
| -webkit-backdrop-filter: blur(10px); |
| border-radius: 20px; |
| border: 1px solid rgba(255, 255, 255, 0.18); |
| box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15); |
| } |
| |
| .gradient-bg { |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| } |
| |
| .song-card { |
| transition: all 0.3s ease; |
| } |
| |
| .song-card:hover { |
| transform: translateY(-5px); |
| box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); |
| } |
| |
| .progress-bar { |
| height: 4px; |
| background: rgba(255, 255, 255, 0.3); |
| border-radius: 2px; |
| } |
| |
| .progress-fill { |
| height: 100%; |
| background: white; |
| border-radius: 2px; |
| transition: width 0.3s ease; |
| } |
| |
| .lyrics-input { |
| min-height: 150px; |
| resize: none; |
| } |
| |
| .audio-player { |
| width: 100%; |
| height: 40px; |
| background: rgba(255, 255, 255, 0.1); |
| border-radius: 20px; |
| } |
| |
| |
| ::-webkit-scrollbar { |
| width: 8px; |
| } |
| |
| ::-webkit-scrollbar-track { |
| background: rgba(255, 255, 255, 0.1); |
| border-radius: 10px; |
| } |
| |
| ::-webkit-scrollbar-thumb { |
| background: rgba(255, 255, 255, 0.3); |
| border-radius: 10px; |
| } |
| |
| ::-webkit-scrollbar-thumb:hover { |
| background: rgba(255, 255, 255, 0.5); |
| } |
| |
| |
| .tab { |
| padding: 10px 20px; |
| cursor: pointer; |
| border-radius: 9999px; |
| transition: all 0.3s ease; |
| } |
| |
| .tab.active { |
| background: rgba(255, 255, 255, 0.2); |
| font-weight: 500; |
| } |
| |
| |
| .spinner { |
| width: 24px; |
| height: 24px; |
| border: 3px solid rgba(255,255,255,0.3); |
| border-radius: 50%; |
| border-top-color: white; |
| animation: spin 1s ease-in-out infinite; |
| } |
| |
| @keyframes spin { |
| to { transform: rotate(360deg); } |
| } |
| </style> |
| </head> |
| <body class="gradient-bg min-h-screen text-white font-sans"> |
| <div class="container mx-auto px-4 py-8"> |
| |
| <header class="flex justify-between items-center mb-8"> |
| <div class="flex items-center"> |
| <i class="fas fa-music text-3xl mr-3"></i> |
| <h1 class="text-3xl font-bold">Mureka Music</h1> |
| </div> |
| <div class="flex items-center space-x-4"> |
| <button id="accountBtn" class="glass-effect px-4 py-2 rounded-full flex items-center"> |
| <i class="fas fa-user mr-2"></i> |
| <span>Account</span> |
| </button> |
| <button id="settingsBtn" class="glass-effect px-4 py-2 rounded-full flex items-center"> |
| <i class="fas fa-cog mr-2"></i> |
| <span>Settings</span> |
| </button> |
| </div> |
| </header> |
|
|
| |
| <main class="grid grid-cols-1 lg:grid-cols-3 gap-8"> |
| |
| <div class="glass-effect p-6 rounded-2xl lg:col-span-2"> |
| <div class="flex space-x-2 mb-6"> |
| <div class="tab active" data-tab="song">Song</div> |
| <div class="tab" data-tab="instrumental">Instrumental</div> |
| <div class="tab" data-tab="lyrics">Lyrics</div> |
| <div class="tab" data-tab="video">Video</div> |
| </div> |
| |
| |
| <div id="songTab" class="tab-content"> |
| <h2 class="text-2xl font-semibold mb-6">Create New Song</h2> |
| |
| <div class="mb-6"> |
| <label class="block text-sm font-medium mb-2">Song Title</label> |
| <input type="text" id="songTitle" placeholder="Enter song title" |
| class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| </div> |
| |
| <div class="mb-6"> |
| <label class="block text-sm font-medium mb-2">Lyrics</label> |
| <textarea id="songLyrics" placeholder="Enter your lyrics here..." |
| class="lyrics-input glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"></textarea> |
| </div> |
| |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> |
| <div> |
| <label class="block text-sm font-medium mb-2">Genre</label> |
| <select id="songGenre" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="pop">Pop</option> |
| <option value="rock">Rock</option> |
| <option value="r&b">R&B</option> |
| <option value="hiphop">Hip Hop</option> |
| <option value="electronic">Electronic</option> |
| <option value="jazz">Jazz</option> |
| <option value="classical">Classical</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Mood</label> |
| <select id="songMood" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="happy">Happy</option> |
| <option value="sad">Sad</option> |
| <option value="energetic">Energetic</option> |
| <option value="calm">Calm</option> |
| <option value="romantic">Romantic</option> |
| <option value="angry">Angry</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Vocal Type</label> |
| <select id="songVocal" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="male">Male</option> |
| <option value="female">Female</option> |
| <option value="duet">Duet</option> |
| <option value="choir">Choir</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Model</label> |
| <select id="songModel" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="auto">Auto (Recommended)</option> |
| <option value="mureka-6">Mureka V6</option> |
| <option value="mureka-5.5">Mureka V5.5</option> |
| <option value="mureka-o1">Mureka O1</option> |
| </select> |
| </div> |
| </div> |
| |
| <div class="flex justify-between items-center"> |
| <div class="flex items-center space-x-2"> |
| <input type="checkbox" id="advancedOptions" class="rounded"> |
| <label for="advancedOptions">Advanced Options</label> |
| </div> |
| |
| <button id="generateSongBtn" class="bg-white text-purple-700 px-6 py-3 rounded-full font-medium hover:bg-white/90 transition flex items-center"> |
| <i class="fas fa-magic mr-2"></i> Generate Song |
| </button> |
| </div> |
| |
| |
| <div id="advancedOptionsPanel" class="mt-6 hidden"> |
| <h3 class="text-lg font-medium mb-4">Advanced Options</h3> |
| |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4"> |
| <div> |
| <label class="block text-sm font-medium mb-2">Tempo (BPM)</label> |
| <input type="range" id="songTempo" min="60" max="200" value="120" |
| class="w-full h-2 bg-white/20 rounded-lg appearance-none cursor-pointer"> |
| <div class="flex justify-between text-xs mt-1"> |
| <span>60</span> |
| <span id="tempoValue">120</span> |
| <span>200</span> |
| </div> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Duration (seconds)</label> |
| <input type="range" id="songDuration" min="30" max="300" value="180" |
| class="w-full h-2 bg-white/20 rounded-lg appearance-none cursor-pointer"> |
| <div class="flex justify-between text-xs mt-1"> |
| <span>30</span> |
| <span id="durationValue">180</span> |
| <span>300</span> |
| </div> |
| </div> |
| </div> |
| |
| <div class="mb-4"> |
| <label class="block text-sm font-medium mb-2">Reference Track (URL)</label> |
| <input type="text" id="songReference" placeholder="Paste a YouTube or Spotify URL" |
| class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Additional Description</label> |
| <textarea id="songDescription" placeholder="Describe the style, instruments, or any specific requirements..." |
| class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"></textarea> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="instrumentalTab" class="tab-content hidden"> |
| <h2 class="text-2xl font-semibold mb-6">Create Instrumental</h2> |
| |
| <div class="mb-6"> |
| <label class="block text-sm font-medium mb-2">Track Title</label> |
| <input type="text" id="instrumentalTitle" placeholder="Enter track title" |
| class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| </div> |
| |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> |
| <div> |
| <label class="block text-sm font-medium mb-2">Genre</label> |
| <select id="instrumentalGenre" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="electronic">Electronic</option> |
| <option value="orchestral">Orchestral</option> |
| <option value="jazz">Jazz</option> |
| <option value="rock">Rock</option> |
| <option value="ambient">Ambient</option> |
| <option value="hiphop">Hip Hop</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Mood</label> |
| <select id="instrumentalMood" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="happy">Happy</option> |
| <option value="sad">Sad</option> |
| <option value="energetic">Energetic</option> |
| <option value="calm">Calm</option> |
| <option value="dark">Dark</option> |
| <option value="uplifting">Uplifting</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Instruments</label> |
| <select id="instrumentalInstruments" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="piano">Piano</option> |
| <option value="guitar">Guitar</option> |
| <option value="strings">Strings</option> |
| <option value="synth">Synth</option> |
| <option value="drums">Drums</option> |
| <option value="full-band">Full Band</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Model</label> |
| <select id="instrumentalModel" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="auto">Auto (Recommended)</option> |
| <option value="mureka-6">Mureka V6</option> |
| <option value="mureka-5.5">Mureka V5.5</option> |
| <option value="mureka-o1">Mureka O1</option> |
| </select> |
| </div> |
| </div> |
| |
| <div class="flex justify-between items-center"> |
| <div class="flex items-center space-x-2"> |
| <input type="checkbox" id="instrumentalAdvancedOptions" class="rounded"> |
| <label for="instrumentalAdvancedOptions">Advanced Options</label> |
| </div> |
| |
| <button id="generateInstrumentalBtn" class="bg-white text-purple-700 px-6 py-3 rounded-full font-medium hover:bg-white/90 transition flex items-center"> |
| <i class="fas fa-magic mr-2"></i> Generate Instrumental |
| </button> |
| </div> |
| |
| |
| <div id="instrumentalAdvancedOptionsPanel" class="mt-6 hidden"> |
| <h3 class="text-lg font-medium mb-4">Advanced Options</h3> |
| |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4"> |
| <div> |
| <label class="block text-sm font-medium mb-2">Tempo (BPM)</label> |
| <input type="range" id="instrumentalTempo" min="60" max="200" value="120" |
| class="w-full h-2 bg-white/20 rounded-lg appearance-none cursor-pointer"> |
| <div class="flex justify-between text-xs mt-1"> |
| <span>60</span> |
| <span id="instrumentalTempoValue">120</span> |
| <span>200</span> |
| </div> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Duration (seconds)</label> |
| <input type="range" id="instrumentalDuration" min="30" max="300" value="180" |
| class="w-full h-2 bg-white/20 rounded-lg appearance-none cursor-pointer"> |
| <div class="flex justify-between text-xs mt-1"> |
| <span>30</span> |
| <span id="instrumentalDurationValue">180</span> |
| <span>300</span> |
| </div> |
| </div> |
| </div> |
| |
| <div class="mb-4"> |
| <label class="block text-sm font-medium mb-2">Reference Track (URL)</label> |
| <input type="text" id="instrumentalReference" placeholder="Paste a YouTube or Spotify URL" |
| class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Additional Description</label> |
| <textarea id="instrumentalDescription" placeholder="Describe the style, instruments, or any specific requirements..." |
| class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"></textarea> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="lyricsTab" class="tab-content hidden"> |
| <h2 class="text-2xl font-semibold mb-6">Generate Lyrics</h2> |
| |
| <div class="mb-6"> |
| <label class="block text-sm font-medium mb-2">Song Title</label> |
| <input type="text" id="lyricsTitle" placeholder="Enter song title" |
| class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| </div> |
| |
| <div class="mb-6"> |
| <label class="block text-sm font-medium mb-2">Theme/Subject</label> |
| <textarea id="lyricsTheme" placeholder="Describe what the song should be about..." |
| class="lyrics-input glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"></textarea> |
| </div> |
| |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> |
| <div> |
| <label class="block text-sm font-medium mb-2">Genre</label> |
| <select id="lyricsGenre" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="pop">Pop</option> |
| <option value="rock">Rock</option> |
| <option value="r&b">R&B</option> |
| <option value="hiphop">Hip Hop</option> |
| <option value="country">Country</option> |
| <option value="jazz">Jazz</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Mood</label> |
| <select id="lyricsMood" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="happy">Happy</option> |
| <option value="sad">Sad</option> |
| <option value="romantic">Romantic</option> |
| <option value="angry">Angry</option> |
| <option value="nostalgic">Nostalgic</option> |
| <option value="hopeful">Hopeful</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Style</label> |
| <select id="lyricsStyle" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="standard">Standard</option> |
| <option value="poetic">Poetic</option> |
| <option value="simple">Simple</option> |
| <option value="complex">Complex</option> |
| <option value="metaphorical">Metaphorical</option> |
| <option value="direct">Direct</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Length</label> |
| <select id="lyricsLength" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="short">Short (1 verse + chorus)</option> |
| <option value="medium" selected>Medium (2 verses + chorus)</option> |
| <option value="long">Long (3 verses + chorus + bridge)</option> |
| </select> |
| </div> |
| </div> |
| |
| <div class="flex justify-between items-center"> |
| <div class="flex items-center space-x-2"> |
| <input type="checkbox" id="lyricsAdvancedOptions" class="rounded"> |
| <label for="lyricsAdvancedOptions">Advanced Options</label> |
| </div> |
| |
| <button id="generateLyricsBtn" class="bg-white text-purple-700 px-6 py-3 rounded-full font-medium hover:bg-white/90 transition flex items-center"> |
| <i class="fas fa-magic mr-2"></i> Generate Lyrics |
| </button> |
| </div> |
| |
| |
| <div id="lyricsAdvancedOptionsPanel" class="mt-6 hidden"> |
| <h3 class="text-lg font-medium mb-4">Advanced Options</h3> |
| |
| <div class="mb-4"> |
| <label class="block text-sm font-medium mb-2">Reference Artist/Song</label> |
| <input type="text" id="lyricsReference" placeholder="E.g., 'Taylor Swift style'" |
| class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Specific Instructions</label> |
| <textarea id="lyricsInstructions" placeholder="Any specific requirements for the lyrics..." |
| class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"></textarea> |
| </div> |
| </div> |
| |
| |
| <div id="generatedLyricsContainer" class="mt-6 hidden"> |
| <h3 class="text-lg font-medium mb-4">Generated Lyrics</h3> |
| <div id="generatedLyrics" class="glass-effect p-4 rounded-xl whitespace-pre-line"></div> |
| <div class="flex justify-end mt-4"> |
| <button id="copyLyricsBtn" class="glass-effect px-4 py-2 rounded-full mr-2"> |
| <i class="fas fa-copy mr-2"></i> Copy |
| </button> |
| <button id="useLyricsBtn" class="bg-white text-purple-700 px-4 py-2 rounded-full"> |
| <i class="fas fa-music mr-2"></i> Use for Song |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="videoTab" class="tab-content hidden"> |
| <h2 class="text-2xl font-semibold mb-6">Generate Music Video</h2> |
| |
| <div class="mb-6"> |
| <label class="block text-sm font-medium mb-2">Select Song</label> |
| <select id="videoSongSelect" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="">Select a generated song...</option> |
| |
| </select> |
| </div> |
| |
| <div class="mb-6"> |
| <label class="block text-sm font-medium mb-2">Video Style</label> |
| <select id="videoStyle" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="abstract">Abstract</option> |
| <option value="performance">Performance</option> |
| <option value="story">Story</option> |
| <option value="lyric">Lyric Video</option> |
| <option value="concert">Concert</option> |
| <option value="animation">Animation</option> |
| </select> |
| </div> |
| |
| <div class="mb-6"> |
| <label class="block text-sm font-medium mb-2">Theme/Concept</label> |
| <textarea id="videoTheme" placeholder="Describe the video concept or provide reference images/links..." |
| class="lyrics-input glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"></textarea> |
| </div> |
| |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> |
| <div> |
| <label class="block text-sm font-medium mb-2">Color Palette</label> |
| <select id="videoColors" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="vibrant">Vibrant</option> |
| <option value="pastel">Pastel</option> |
| <option value="monochrome">Monochrome</option> |
| <option value="dark">Dark</option> |
| <option value="light">Light</option> |
| <option value="custom">Custom</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Video Length</label> |
| <select id="videoLength" class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| <option value="full">Full Song</option> |
| <option value="30s">30 Seconds</option> |
| <option value="60s">60 Seconds</option> |
| <option value="90s">90 Seconds</option> |
| <option value="teaser">Teaser (15s)</option> |
| </select> |
| </div> |
| </div> |
| |
| <div class="flex justify-between items-center"> |
| <div class="flex items-center space-x-2"> |
| <input type="checkbox" id="videoAdvancedOptions" class="rounded"> |
| <label for="videoAdvancedOptions">Advanced Options</label> |
| </div> |
| |
| <button id="generateVideoBtn" class="bg-white text-purple-700 px-6 py-3 rounded-full font-medium hover:bg-white/90 transition flex items-center"> |
| <i class="fas fa-video mr-2"></i> Generate Video |
| </button> |
| </div> |
| |
| |
| <div id="videoAdvancedOptionsPanel" class="mt-6 hidden"> |
| <h3 class="text-lg font-medium mb-4">Advanced Options</h3> |
| |
| <div class="mb-4"> |
| <label class="block text-sm font-medium mb-2">Reference Videos (URLs)</label> |
| <input type="text" id="videoReferences" placeholder="Paste YouTube or Vimeo URLs separated by commas" |
| class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Specific Instructions</label> |
| <textarea id="videoInstructions" placeholder="Any specific requirements for the video..." |
| class="glass-effect w-full px-4 py-3 rounded-xl bg-transparent border border-white/20 focus:outline-none focus:ring-2 focus:ring-white/30"></textarea> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="generationProgress" class="mt-6 hidden"> |
| <div class="flex justify-between items-center mb-2"> |
| <span class="font-medium" id="progressTitle">Generating your song...</span> |
| <span id="progressPercent">0%</span> |
| </div> |
| <div class="progress-bar"> |
| <div id="progressFill" class="progress-fill" style="width: 0%"></div> |
| </div> |
| <div class="text-sm text-center mt-2" id="statusMessage">Preparing generation...</div> |
| </div> |
| </div> |
| |
| |
| <div class="glass-effect p-6 rounded-2xl"> |
| <div class="flex justify-between items-center mb-6"> |
| <h2 class="text-2xl font-semibold">Your Library</h2> |
| <button id="refreshLibraryBtn" class="glass-effect px-3 py-1 rounded-full text-sm"> |
| <i class="fas fa-sync-alt mr-1"></i> Refresh |
| </button> |
| </div> |
| |
| <div class="flex space-x-2 mb-4"> |
| <div class="tab active" data-filter="all">All</div> |
| <div class="tab" data-filter="songs">Songs</div> |
| <div class="tab" data-filter="instrumentals">Instrumentals</div> |
| <div class="tab" data-filter="videos">Videos</div> |
| </div> |
| |
| <div id="libraryContent" class="space-y-4 max-h-[600px] overflow-y-auto pr-2"> |
| |
| <div class="text-center py-8"> |
| <i class="fas fa-music text-4xl mb-4 opacity-50"></i> |
| <p class="opacity-70">Your generated content will appear here</p> |
| </div> |
| </div> |
| </div> |
| </main> |
| </div> |
|
|
| |
| <div id="accountModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> |
| <div class="glass-effect w-full max-w-md p-6 rounded-2xl"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-xl font-semibold">Account</h3> |
| <button id="closeAccountModal" class="text-xl">×</button> |
| </div> |
| |
| <div class="mb-6"> |
| <div class="flex items-center mb-4"> |
| <div class="w-16 h-16 rounded-full bg-white/20 flex items-center justify-center mr-4"> |
| <i class="fas fa-user text-2xl"></i> |
| </div> |
| <div> |
| <h4 class="font-medium" id="accountName">Guest User</h4> |
| <p class="text-sm opacity-70" id="accountEmail">guest@example.com</p> |
| </div> |
| </div> |
| |
| <div class="glass-effect p-4 rounded-xl mb-4"> |
| <div class="flex justify-between items-center mb-2"> |
| <span class="font-medium">Plan</span> |
| <span id="accountPlan" class="bg-white text-purple-700 px-2 py-1 rounded-full text-xs">Basic</span> |
| </div> |
| <div class="flex justify-between items-center"> |
| <span>Credits</span> |
| <span id="accountCredits">400</span> |
| </div> |
| </div> |
| |
| <div class="glass-effect p-4 rounded-xl"> |
| <div class="flex justify-between items-center mb-2"> |
| <span class="font-medium">API Key</span> |
| <button id="showApiKey" class="text-xs">Show</button> |
| </div> |
| <div class="relative"> |
| <input type="password" id="apiKeyField" value="sk_test_1234567890abcdef" |
| class="glass-effect w-full px-3 py-2 rounded bg-transparent border border-white/20 text-sm" readonly> |
| <button id="copyApiKey" class="absolute right-2 top-1/2 transform -translate-y-1/2"> |
| <i class="fas fa-copy"></i> |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| <div class="flex justify-between"> |
| <button class="glass-effect px-4 py-2 rounded-full"> |
| <i class="fas fa-sign-out-alt mr-2"></i> Logout |
| </button> |
| <button class="bg-white text-purple-700 px-4 py-2 rounded-full"> |
| <i class="fas fa-crown mr-2"></i> Upgrade |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="settingsModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> |
| <div class="glass-effect w-full max-w-md p-6 rounded-2xl"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-xl font-semibold">Settings</h3> |
| <button id="closeSettingsModal" class="text-xl">×</button> |
| </div> |
| |
| <div class="space-y-4"> |
| <div> |
| <label class="block text-sm font-medium mb-2">Default Model</label> |
| <select class="glass-effect w-full px-4 py-2 rounded-xl bg-transparent border border-white/20"> |
| <option value="auto">Auto (Recommended)</option> |
| <option value="mureka-6">Mureka V6</option> |
| <option value="mureka-5.5">Mureka V5.5</option> |
| <option value="mureka-o1">Mureka O1</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Default Quality</label> |
| <select class="glass-effect w-full px-4 py-2 rounded-xl bg-transparent border border-white/20"> |
| <option value="standard">Standard</option> |
| <option value="high">High (uses more credits)</option> |
| <option value="premium">Premium (best quality)</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-2">Default Duration</label> |
| <select class="glass-effect w-full px-4 py-2 rounded-xl bg-transparent border border-white/20"> |
| <option value="short">Short (30-60s)</option> |
| <option value="medium" selected>Medium (2-3 min)</option> |
| <option value="full">Full Length (3-5 min)</option> |
| </select> |
| </div> |
| |
| <div class="flex items-center justify-between pt-4 border-t border-white/20"> |
| <span>Dark Mode</span> |
| <label class="relative inline-flex items-center cursor-pointer"> |
| <input type="checkbox" class="sr-only peer" checked> |
| <div class="w-11 h-6 bg-white/20 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-purple-600"></div> |
| </label> |
| </div> |
| |
| <div class="flex items-center justify-between"> |
| <span>Auto-save generations</span> |
| <label class="relative inline-flex items-center cursor-pointer"> |
| <input type="checkbox" class="sr-only peer" checked> |
| <div class="w-11 h-6 bg-white/20 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-purple-600"></div> |
| </label> |
| </div> |
| </div> |
| |
| <div class="mt-6 flex justify-end"> |
| <button class="bg-white text-purple-700 px-4 py-2 rounded-full"> |
| Save Settings |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| // DOM Elements |
| const tabs = document.querySelectorAll('[data-tab]'); |
| const tabContents = document.querySelectorAll('.tab-content'); |
| const filterTabs = document.querySelectorAll('[data-filter]'); |
| const advancedOptionsCheckbox = document.getElementById('advancedOptions'); |
| const advancedOptionsPanel = document.getElementById('advancedOptionsPanel'); |
| const instrumentalAdvancedOptionsCheckbox = document.getElementById('instrumentalAdvancedOptions'); |
| const instrumentalAdvancedOptionsPanel = document.getElementById('instrumentalAdvancedOptionsPanel'); |
| const lyricsAdvancedOptionsCheckbox = document.getElementById('lyricsAdvancedOptions'); |
| const lyricsAdvancedOptionsPanel = document.getElementById('lyricsAdvancedOptionsPanel'); |
| const videoAdvancedOptionsCheckbox = document.getElementById('videoAdvancedOptions'); |
| const videoAdvancedOptionsPanel = document.getElementById('videoAdvancedOptionsPanel'); |
| |
| // Generation buttons |
| const generateSongBtn = document.getElementById('generateSongBtn'); |
| const generateInstrumentalBtn = document.getElementById('generateInstrumentalBtn'); |
| const generateLyricsBtn = document.getElementById('generateLyricsBtn'); |
| const generateVideoBtn = document.getElementById('generateVideoBtn'); |
| |
| // Progress elements |
| const generationProgress = document.getElementById('generationProgress'); |
| const progressFill = document.getElementById('progressFill'); |
| const progressPercent = document.getElementById('progressPercent'); |
| const progressTitle = document.getElementById('progressTitle'); |
| const statusMessage = document.getElementById('statusMessage'); |
| |
| // Library elements |
| const libraryContent = document.getElementById('libraryContent'); |
| const refreshLibraryBtn = document.getElementById('refreshLibraryBtn'); |
| const videoSongSelect = document.getElementById('videoSongSelect'); |
| |
| // Lyrics elements |
| const generatedLyricsContainer = document.getElementById('generatedLyricsContainer'); |
| const generatedLyrics = document.getElementById('generatedLyrics'); |
| const copyLyricsBtn = document.getElementById('copyLyricsBtn'); |
| const useLyricsBtn = document.getElementById('useLyricsBtn'); |
| |
| // Modal elements |
| const accountBtn = document.getElementById('accountBtn'); |
| const accountModal = document.getElementById('accountModal'); |
| const closeAccountModal = document.getElementById('closeAccountModal'); |
| const showApiKey = document.getElementById('showApiKey'); |
| const apiKeyField = document.getElementById('apiKeyField'); |
| const copyApiKey = document.getElementById('copyApiKey'); |
| |
| const settingsBtn = document.getElementById('settingsBtn'); |
| const settingsModal = document.getElementById('settingsModal'); |
| const closeSettingsModal = document.getElementById('closeSettingsModal'); |
| |
| // Form elements |
| const songTitle = document.getElementById('songTitle'); |
| const songLyrics = document.getElementById('songLyrics'); |
| const songGenre = document.getElementById('songGenre'); |
| const songMood = document.getElementById('songMood'); |
| const songVocal = document.getElementById('songVocal'); |
| const songModel = document.getElementById('songModel'); |
| const songTempo = document.getElementById('songTempo'); |
| const tempoValue = document.getElementById('tempoValue'); |
| const songDuration = document.getElementById('songDuration'); |
| const durationValue = document.getElementById('durationValue'); |
| const songReference = document.getElementById('songReference'); |
| const songDescription = document.getElementById('songDescription'); |
| |
| const instrumentalTitle = document.getElementById('instrumentalTitle'); |
| const instrumentalGenre = document.getElementById('instrumentalGenre'); |
| const instrumentalMood = document.getElementById('instrumentalMood'); |
| const instrumentalInstruments = document.getElementById('instrumentalInstruments'); |
| const instrumentalModel = document.getElementById('instrumentalModel'); |
| const instrumentalTempo = document.getElementById('instrumentalTempo'); |
| const instrumentalTempoValue = document.getElementById('instrumentalTempoValue'); |
| const instrumentalDuration = document.getElementById('instrumentalDuration'); |
| const instrumentalDurationValue = document.getElementById('instrumentalDurationValue'); |
| const instrumentalReference = document.getElementById('instrumentalReference'); |
| const instrumentalDescription = document.getElementById('instrumentalDescription'); |
| |
| const lyricsTitle = document.getElementById('lyricsTitle'); |
| const lyricsTheme = document.getElementById('lyricsTheme'); |
| const lyricsGenre = document.getElementById('lyricsGenre'); |
| const lyricsMood = document.getElementById('lyricsMood'); |
| const lyricsStyle = document.getElementById('lyricsStyle'); |
| const lyricsLength = document.getElementById('lyricsLength'); |
| const lyricsReference = document.getElementById('lyricsReference'); |
| const lyricsInstructions = document.getElementById('lyricsInstructions'); |
| |
| const videoStyle = document.getElementById('videoStyle'); |
| const videoTheme = document.getElementById('videoTheme'); |
| const videoColors = document.getElementById('videoColors'); |
| const videoLength = document.getElementById('videoLength'); |
| const videoReferences = document.getElementById('videoReferences'); |
| const videoInstructions = document.getElementById('videoInstructions'); |
| |
| // Mock data |
| const mockSongs = [ |
| { |
| id: 'song1', |
| title: 'Summer Breeze', |
| type: 'song', |
| genre: 'Pop', |
| mood: 'Happy', |
| vocal: 'Female', |
| duration: '2:45', |
| date: '2023-06-15', |
| cover: 'https://via.placeholder.com/150', |
| audio: 'https://example.com/audio1.mp3' |
| }, |
| { |
| id: 'song2', |
| title: 'Midnight Thoughts', |
| type: 'song', |
| genre: 'R&B', |
| mood: 'Sad', |
| vocal: 'Male', |
| duration: '3:12', |
| date: '2023-06-10', |
| cover: 'https://via.placeholder.com/150', |
| audio: 'https://example.com/audio2.mp3' |
| }, |
| { |
| id: 'inst1', |
| title: 'Dreamscape', |
| type: 'instrumental', |
| genre: 'Ambient', |
| mood: 'Calm', |
| vocal: 'None', |
| duration: '4:20', |
| date: '2023-06-05', |
| cover: 'https://via.placeholder.com/150', |
| audio: 'https://example.com/audio3.mp3' |
| }, |
| { |
| id: 'video1', |
| title: 'Summer Breeze Video', |
| type: 'video', |
| genre: 'Pop', |
| mood: 'Happy', |
| duration: '2:45', |
| date: '2023-06-18', |
| cover: 'https://via.placeholder.com/150', |
| video: 'https://example.com/video1.mp4' |
| } |
| ]; |
| |
| // Mock API Key - In a real app, this would be securely stored and retrieved |
| const MUREKA_API_KEY = 'your_api_key_here'; |
| |
| // Initialize the app |
| function initApp() { |
| // Load library content |
| loadLibraryContent('all'); |
| |
| // Populate video song select |
| populateVideoSongSelect(); |
| } |
| |
| // Tab switching |
| tabs.forEach(tab => { |
| tab.addEventListener('click', () => { |
| // Remove active class from all tabs |
| tabs.forEach(t => t.classList.remove('active')); |
| // Add active class to clicked tab |
| tab.classList.add('active'); |
| |
| // Hide all tab contents |
| tabContents.forEach(content => content.classList.add('hidden')); |
| // Show the selected tab content |
| const tabId = tab.getAttribute('data-tab') + 'Tab'; |
| document.getElementById(tabId).classList.remove('hidden'); |
| |
| // Update progress title based on tab |
| switch(tab.getAttribute('data-tab')) { |
| case 'song': |
| progressTitle.textContent = 'Generating your song...'; |
| break; |
| case 'instrumental': |
| progressTitle.textContent = 'Generating instrumental...'; |
| break; |
| case 'lyrics': |
| progressTitle.textContent = 'Generating lyrics...'; |
| break; |
| case 'video': |
| progressTitle.textContent = 'Generating video...'; |
| break; |
| } |
| }); |
| }); |
| |
| // Filter switching |
| filterTabs.forEach(tab => { |
| tab.addEventListener('click', () => { |
| // Remove active class from all filter tabs |
| filterTabs.forEach(t => t.classList.remove('active')); |
| // Add active class to clicked tab |
| tab.classList.add('active'); |
| |
| // Load content based on filter |
| const filter = tab.getAttribute('data-filter'); |
| loadLibraryContent(filter); |
| }); |
| }); |
| |
| // Advanced options toggles |
| advancedOptionsCheckbox.addEventListener('change', function() { |
| advancedOptionsPanel.classList.toggle('hidden', !this.checked); |
| }); |
| |
| instrumentalAdvancedOptionsCheckbox.addEventListener('change', function() { |
| instrumentalAdvancedOptionsPanel.classList.toggle('hidden', !this.checked); |
| }); |
| |
| lyricsAdvancedOptionsCheckbox.addEventListener('change', function() { |
| lyricsAdvancedOptionsPanel.classList.toggle('hidden', !this.checked); |
| }); |
| |
| videoAdvancedOptionsCheckbox.addEventListener('change', function() { |
| videoAdvancedOptionsPanel.classList.toggle('hidden', !this.checked); |
| }); |
| |
| // Range input updates |
| songTempo.addEventListener('input', function() { |
| tempoValue.textContent = this.value; |
| }); |
| |
| songDuration.addEventListener('input', function() { |
| durationValue.textContent = this.value; |
| }); |
| |
| instrumentalTempo.addEventListener('input', function() { |
| instrumentalTempoValue.textContent = this.value; |
| }); |
| |
| instrumentalDuration.addEventListener('input', function() { |
| instrumentalDurationValue.textContent = this.value; |
| }); |
| |
| // Generate buttons |
| generateSongBtn.addEventListener('click', generateSong); |
| generateInstrumentalBtn.addEventListener('click', generateInstrumental); |
| generateLyricsBtn.addEventListener('click', generateLyrics); |
| generateVideoBtn.addEventListener('click', generateVideo); |
| |
| // Library refresh |
| refreshLibraryBtn.addEventListener('click', function() { |
| const activeFilter = document.querySelector('[data-filter].active').getAttribute('data-filter'); |
| loadLibraryContent(activeFilter); |
| }); |
| |
| // Lyrics actions |
| copyLyricsBtn.addEventListener('click', copyLyrics); |
| useLyricsBtn.addEventListener('click', useLyricsForSong); |
| |
| // Modal controls |
| accountBtn.addEventListener('click', () => accountModal.classList.remove('hidden')); |
| closeAccountModal.addEventListener('click', () => accountModal.classList.add('hidden')); |
| |
| settingsBtn.addEventListener('click', () => settingsModal.classList.remove('hidden')); |
| closeSettingsModal.addEventListener('click', () => settingsModal.classList.add('hidden')); |
| |
| // API key controls |
| showApiKey.addEventListener('click', function() { |
| if (apiKeyField.type === 'password') { |
| apiKeyField.type = 'text'; |
| this.textContent = 'Hide'; |
| } else { |
| apiKeyField.type = 'password'; |
| this.textContent = 'Show'; |
| } |
| }); |
| |
| copyApiKey.addEventListener('click', function() { |
| apiKeyField.select(); |
| document.execCommand('copy'); |
| |
| // Show copied feedback |
| const originalText = this.innerHTML; |
| this.innerHTML = '<i class="fas fa-check"></i> Copied!'; |
| setTimeout(() => { |
| this.innerHTML = originalText; |
| }, 2000); |
| }); |
| |
| // Close modals when clicking outside |
| window.addEventListener('click', (e) => { |
| if (e.target === accountModal) { |
| accountModal.classList.add('hidden'); |
| } |
| if (e.target === settingsModal) { |
| settingsModal.classList.add('hidden'); |
| } |
| }); |
| |
| // Load library content |
| function loadLibraryContent(filter) { |
| // In a real app, this would fetch from API |
| let content = mockSongs; |
| |
| if (filter !== 'all') { |
| content = content.filter(item => item.type === filter || |
| (filter === 'songs' && item.type === 'song') || |
| (filter === 'instrumentals' && item.type === 'instrumental') || |
| (filter === 'videos' && item.type === 'video')); |
| } |
| |
| if (content.length === 0) { |
| libraryContent.innerHTML = ` |
| <div class="text-center py-8"> |
| <i class="fas fa-music text-4xl mb-4 opacity-50"></i> |
| <p class="opacity-70">No ${filter} found in your library</p> |
| </div> |
| `; |
| return; |
| } |
| |
| libraryContent.innerHTML = ''; |
| |
| content.forEach(item => { |
| const card = document.createElement('div'); |
| card.className = 'song-card glass-effect p-4 rounded-xl'; |
| |
| let typeIcon = 'fa-music'; |
| if (item.type === 'instrumental') typeIcon = 'fa-headphones'; |
| if (item.type === 'video') typeIcon = 'fa-video'; |
| |
| card.innerHTML = ` |
| <div class="flex justify-between items-start mb-2"> |
| <div> |
| <h3 class="font-medium">${item.title}</h3> |
| <p class="text-sm opacity-70">${item.genre} • ${item.mood}${item.vocal !== 'None' ? ' • ' + item.vocal : ''}</p> |
| </div> |
| <div class="flex space-x-2"> |
| <button class="glass-effect p-2 rounded-full" data-id="${item.id}" data-type="${item.type}"> |
| <i class="fas fa-download"></i> |
| </button> |
| <button class="glass-effect p-2 rounded-full" data-id="${item.id}" data-type="${item.type}"> |
| <i class="fas fa-share-alt"></i> |
| </button> |
| </div> |
| </div> |
| <div class="flex items-center justify-between text-sm opacity-70 mb-2"> |
| <span><i class="fas ${typeIcon} mr-1"></i> ${item.type.charAt(0).toUpperCase() + item.type.slice(1)}</span> |
| <span>${item.date}</span> |
| </div> |
| <div class="audio-player flex items-center px-3"> |
| <button class="mr-3"> |
| <i class="fas fa-play"></i> |
| </button> |
| <div class="flex-1"> |
| <input type="range" class="w-full" value="0"> |
| </div> |
| <span class="ml-3 text-xs">${item.duration}</span> |
| </div> |
| `; |
| |
| // Add play button functionality |
| const playBtn = card.querySelector('.audio-player button'); |
| playBtn.addEventListener('click', function() { |
| const icon = this.querySelector('i'); |
| if(icon.classList.contains('fa-play')) { |
| icon.classList.remove('fa-play'); |
| icon.classList.add('fa-pause'); |
| // In a real app, would play the audio here |
| } else { |
| icon.classList.remove('fa-pause'); |
| icon.classList.add('fa-play'); |
| // In a real app, would pause the audio here |
| } |
| }); |
| |
| libraryContent.appendChild(card); |
| }); |
| } |
| |
| // Populate video song select |
| function populateVideoSongSelect() { |
| // In a real app, this would fetch from API |
| const songs = mockSongs.filter(item => item.type === 'song'); |
| |
| videoSongSelect.innerHTML = '<option value="">Select a generated song...</option>'; |
| |
| songs.forEach(song => { |
| const option = document.createElement('option'); |
| option.value = song.id; |
| option.textContent = song.title; |
| videoSongSelect.appendChild(option); |
| }); |
| } |
| |
| // Generate song |
| async function generateSong() { |
| // Validate inputs |
| if(!songLyrics.value.trim()) { |
| alert('Please enter lyrics for your song'); |
| return; |
| } |
| |
| // Show loading state on button |
| const originalBtnContent = generateSongBtn.innerHTML; |
| generateSongBtn.innerHTML = '<div class="spinner mr-2"></div> Generating...'; |
| generateSongBtn.disabled = true; |
| |
| // Show progress |
| generationProgress.classList.remove('hidden'); |
| |
| // Prepare request data |
| const requestData = { |
| lyrics: songLyrics.value, |
| title: songTitle.value || 'Untitled Song', |
| model: songModel.value, |
| prompt: `${songGenre.value}, ${songMood.value}, ${songVocal.value} vocal` |
| }; |
| |
| // Add advanced options if enabled |
| if(advancedOptionsCheckbox.checked) { |
| requestData.tempo = songTempo.value; |
| requestData.duration = songDuration.value; |
| requestData.reference = songReference.value; |
| requestData.additional_description = songDescription.value; |
| } |
| |
| // Simulate API call with progress updates |
| await simulateApiCall(requestData, 'song'); |
| |
| // Restore button state |
| generateSongBtn.innerHTML = originalBtnContent; |
| generateSongBtn.disabled = false; |
| } |
| |
| // Generate instrumental |
| async function generateInstrumental() { |
| // Show loading state on button |
| const originalBtnContent = generateInstrumentalBtn.innerHTML; |
| generateInstrumentalBtn.innerHTML = '<div class="spinner mr-2"></div> Generating...'; |
| generateInstrumentalBtn.disabled = true; |
| |
| // Show progress |
| generationProgress.classList.remove('hidden'); |
| |
| // Prepare request data |
| const requestData = { |
| title: instrumentalTitle.value || 'Untitled Instrumental', |
| model: instrumentalModel.value, |
| prompt: `${instrumentalGenre.value}, ${instrumentalMood.value}, ${instrumentalInstruments.value}` |
| }; |
| |
| // Add advanced options if enabled |
| if(instrumentalAdvancedOptionsCheckbox.checked) { |
| requestData.tempo = instrumentalTempo.value; |
| requestData.duration = instrumentalDuration.value; |
| requestData.reference = instrumentalReference.value; |
| requestData.additional_description = instrumentalDescription.value; |
| } |
| |
| // Simulate API call with progress updates |
| await simulateApiCall(requestData, 'instrumental'); |
| |
| // Restore button state |
| generateInstrumentalBtn.innerHTML = originalBtnContent; |
| generateInstrumentalBtn.disabled = false; |
| } |
| |
| // Generate lyrics |
| async function generateLyrics() { |
| // Validate inputs |
| if(!lyricsTheme.value.trim()) { |
| alert('Please enter a theme or subject for the lyrics'); |
| return; |
| } |
| |
| // Show loading state on button |
| const originalBtnContent = generateLyricsBtn.innerHTML; |
| generateLyricsBtn.innerHTML = '<div class="spinner mr-2"></div> Generating...'; |
| generateLyricsBtn.disabled = true; |
| |
| // Show progress |
| generationProgress.classList.remove('hidden'); |
| |
| // Prepare request data |
| const requestData = { |
| theme: lyricsTheme.value, |
| title: lyricsTitle.value || 'Untitled Lyrics', |
| genre: lyricsGenre.value, |
| mood: lyricsMood.value, |
| style: lyricsStyle.value, |
| length: lyricsLength.value |
| }; |
| |
| // Add advanced options if enabled |
| if(lyricsAdvancedOptionsCheckbox.checked) { |
| requestData.reference = lyricsReference.value; |
| requestData.instructions = lyricsInstructions.value; |
| } |
| |
| // Simulate API call with progress updates |
| await simulateApiCall(requestData, 'lyrics'); |
| |
| // Restore button state |
| generateLyricsBtn.innerHTML = originalBtnContent; |
| generateLyricsBtn.disabled = false; |
| } |
| |
| // Generate video |
| async function generateVideo() { |
| // Validate inputs |
| if(!videoSongSelect.value) { |
| alert('Please select a song to create a video for'); |
| return; |
| } |
| |
| // Show loading state on button |
| const originalBtnContent = generateVideoBtn.innerHTML; |
| generateVideoBtn.innerHTML = '<div class="spinner mr-2"></div> Generating...'; |
| generateVideoBtn.disabled = true; |
| |
| // Show progress |
| generationProgress.classList.remove('hidden'); |
| |
| // Prepare request data |
| const selectedSong = mockSongs.find(song => song.id === videoSongSelect.value); |
| const requestData = { |
| song_id: videoSongSelect.value, |
| song_title: selectedSong.title, |
| style: videoStyle.value, |
| theme: videoTheme.value, |
| color_palette: videoColors.value, |
| length: videoLength.value |
| }; |
| |
| // Add advanced options if enabled |
| if(videoAdvancedOptionsCheckbox.checked) { |
| requestData.references = videoReferences.value; |
| requestData.instructions = videoInstructions.value; |
| } |
| |
| // Simulate API call with progress updates |
| await simulateApiCall(requestData, 'video'); |
| |
| // Restore button state |
| generateVideoBtn.innerHTML = originalBtnContent; |
| generateVideoBtn.disabled = false; |
| } |
| |
| // Simulate API call with progress updates |
| function simulateApiCall(requestData, type) { |
| return new Promise((resolve) => { |
| let progress = 0; |
| const interval = setInterval(() => { |
| progress += Math.random() * 10; |
| if(progress > 100) progress = 100; |
| |
| progressFill.style.width = `${progress}%`; |
| progressPercent.textContent = `${Math.floor(progress)}%`; |
| |
| // Update status messages based on type |
| if(type === 'song') { |
| if(progress < 20) { |
| statusMessage.textContent = 'Preparing generation...'; |
| } else if(progress < 50) { |
| statusMessage.textContent = 'Generating melody...'; |
| } else if(progress < 80) { |
| statusMessage.textContent = 'Adding vocals...'; |
| } else { |
| statusMessage.textContent = 'Finalizing your song...'; |
| } |
| } |
| else if(type === 'instrumental') { |
| if(progress < 20) { |
| statusMessage.textContent = 'Preparing generation...'; |
| } else if(progress < 60) { |
| statusMessage.textContent = 'Composing instrumental...'; |
| } else { |
| statusMessage.textContent = 'Finalizing your track...'; |
| } |
| } |
| else if(type === 'lyrics') { |
| if(progress < 30) { |
| statusMessage.textContent = 'Brainstorming ideas...'; |
| } else if(progress < 70) { |
| statusMessage.textContent = 'Writing lyrics...'; |
| } else { |
| statusMessage.textContent = 'Refining your lyrics...'; |
| } |
| } |
| else if(type === 'video') { |
| if(progress < 20) { |
| statusMessage.textContent = 'Analyzing song...'; |
| } else if(progress < 50) { |
| statusMessage.textContent = 'Generating visuals...'; |
| } else if(progress < 80) { |
| statusMessage.textContent = 'Editing video...'; |
| } else { |
| statusMessage.textContent = 'Rendering final video...'; |
| } |
| } |
| |
| // When complete |
| if(progress >= 100) { |
| clearInterval(interval); |
| statusMessage.textContent = 'Generation complete!'; |
| |
| // Add the new content to the library after a short delay |
| setTimeout(() => { |
| if(type === 'lyrics') { |
| showGeneratedLyrics(requestData); |
| } else { |
| addGeneratedContent(requestData, type); |
| } |
| |
| generationProgress.classList.add('hidden'); |
| progressFill.style.width = '0%'; |
| resolve(); |
| }, 1000); |
| } |
| }, 500); |
| }); |
| } |
| |
| // Show generated lyrics |
| function showGeneratedLyrics(requestData) { |
| // Mock generated lyrics |
| const mockLyrics = `[Verse 1] |
| ${requestData.theme || 'Walking through the city lights'} |
| ${requestData.theme || 'Memories of you keep me up at night'} |
| ${requestData.theme || 'Every corner holds a piece of you'} |
| ${requestData.theme || 'Every shadow makes me think it's true'} |
| |
| [Chorus] |
| ${requestData.theme || 'I'm lost without you, can't you see'} |
| ${requestData.theme || 'You're the only one who completes me'} |
| ${requestData.theme || 'Come back home, don't make me plead'} |
| ${requestData.theme || 'You're the air that I need to breathe'} |
| |
| [Verse 2] |
| ${requestData.theme || 'Empty rooms and silent phones'} |
| ${requestData.theme || 'Wondering if you're all alone'} |
| ${requestData.theme || 'Time moves slow when you're not here'} |
| ${requestData.theme || 'Wish I could make it all disappear'} |
| |
| [Chorus] |
| ${requestData.theme || 'I'm lost without you, can't you see'} |
| ${requestData.theme || 'You're the only one who completes me'} |
| ${requestData.theme || 'Come back home, don't make me plead'} |
| ${requestData.theme || 'You're the air that I need to breathe'}`; |
| |
| generatedLyrics.textContent = mockLyrics; |
| generatedLyricsContainer.classList.remove('hidden'); |
| } |
| |
| // Copy lyrics to clipboard |
| function copyLyrics() { |
| navigator.clipboard.writeText(generatedLyrics.textContent) |
| .then(() => { |
| const originalText = copyLyricsBtn.innerHTML; |
| copyLyricsBtn.innerHTML = '<i class="fas fa-check mr-2"></i> Copied!'; |
| setTimeout(() => { |
| copyLyricsBtn.innerHTML = originalText; |
| }, 2000); |
| }) |
| .catch(err => { |
| console.error('Failed to copy lyrics: ', err); |
| }); |
| } |
| |
| // Use lyrics for song |
| function useLyricsForSong() { |
| songLyrics.value = generatedLyrics.textContent; |
| if(lyricsTitle.value) { |
| songTitle.value = lyricsTitle.value; |
| } |
| |
| // Switch to song tab |
| document.querySelector('[data-tab="song"]').click(); |
| generatedLyricsContainer.classList.add('hidden'); |
| } |
| |
| // Add generated content to library |
| function addGeneratedContent(requestData, type) { |
| // In a real app, this would be the actual API response |
| const newContent = { |
| id: `new-${type}-${Date.now()}`, |
| title: requestData.title || `New ${type.charAt(0).toUpperCase() + type.slice(1)}`, |
| type: type, |
| genre: requestData.prompt ? requestData.prompt.split(',')[0] : 'Various', |
| mood: requestData.prompt ? requestData.prompt.split(',')[1] : 'Various', |
| vocal: type === 'song' ? (requestData.prompt ? requestData.prompt.split(',')[2] : 'Unknown') : 'None', |
| duration: requestData.duration ? `${Math.floor(requestData.duration / 60)}:${(requestData.duration % 60).toString().padStart(2, '0')}` : '2:30', |
| date: new Date().toISOString().split('T')[0], |
| cover: 'https://via.placeholder.com/150', |
| audio: type !== 'video' ? 'https://example.com/new-audio.mp3' : undefined, |
| video: type === 'video' ? 'https://example.com/new-video.mp4' : undefined |
| }; |
| |
| // Add to mock data |
| mockSongs.unshift(newContent); |
| |
| // Reload library |
| const activeFilter = document.querySelector('[data-filter].active').getAttribute('data-filter'); |
| loadLibraryContent(activeFilter); |
| |
| // Update video song select if a new song was added |
| if(type === 'song') { |
| populateVideoSongSelect(); |
| } |
| |
| // Show success message |
| alert(`${type.charAt(0).toUpperCase() + type.slice(1)} generated successfully!`); |
| } |
| |
| // In a real implementation, you would have actual API calls like this: |
| /* |
| async function callMurekaApi(endpoint, data) { |
| try { |
| const response = await fetch(`https://api.mureka.ai/v1/${endpoint}`, { |
| method: 'POST', |
| headers: { |
| 'Authorization': `Bearer ${MUREKA_API_KEY}`, |
| 'Content-Type': 'application/json' |
| }, |
| body: JSON.stringify(data) |
| }); |
| |
| if(!response.ok) { |
| throw new Error(`API request failed with status ${response.status}`); |
| } |
| |
| return await response.json(); |
| } catch (error) { |
| console.error('Error calling Mureka API:', error); |
| throw error; |
| } |
| } |
| */ |
| |
| // Initialize the app |
| initApp(); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=FGF897/mureka" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |