|
|
<!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> |