NeoPy commited on
Commit
53a985d
·
verified ·
1 Parent(s): 26b46c4

Make my project more dynamic, looks like new youtube UI, and more features, add made by https://huggingface.co/terastudio too

Browse files
Files changed (1) hide show
  1. index.html +756 -145
index.html CHANGED
@@ -3,16 +3,24 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Advanced Audio Recorder</title>
7
- <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
 
 
 
 
 
 
 
10
  .waveform {
11
- background: linear-gradient(90deg, #3b82f6 0%, #8b5cf6 50%, #ec4899 100%);
12
  height: 100px;
13
- border-radius: 0.5rem;
14
  position: relative;
15
  overflow: hidden;
 
16
  }
17
 
18
  .waveform::after {
@@ -23,10 +31,10 @@
23
  right: 0;
24
  bottom: 0;
25
  background: linear-gradient(90deg,
26
- rgba(255,255,255,0.1) 0%,
27
- rgba(255,255,255,0.3) 50%,
28
- rgba(255,255,255,0.1) 100%);
29
- animation: wave 2s linear infinite;
30
  transform: translateX(-100%);
31
  }
32
 
@@ -37,160 +45,417 @@
37
  }
38
 
39
  .recording-animation {
40
- animation: pulse 1.5s infinite;
41
  }
42
 
43
- @keyframes pulse {
44
  0% {
45
- box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7);
 
46
  }
47
- 70% {
48
- box-shadow: 0 0 0 10px rgba(239, 68, 68, 0);
49
  }
50
  100% {
51
- box-shadow: 0 0 0 0 rgba(239, 68, 68, 0);
 
52
  }
53
  }
54
 
55
  .format-option:hover {
56
- transform: translateY(-3px);
57
- box-shadow: 0 10px 20px rgba(0,0,0,0.1);
 
58
  }
59
 
60
  .format-option {
61
- transition: all 0.3s ease;
 
62
  }
63
 
64
  .device-option:hover {
65
- background-color: #f3f4f6;
66
  }
67
 
68
  .device-option {
69
- transition: all 0.2s ease;
70
  }
71
 
72
  .visualizer {
73
  width: 100%;
74
- height: 80px;
75
- background-color: #f3f4f6;
76
- border-radius: 0.5rem;
77
  position: relative;
78
  overflow: hidden;
 
79
  }
80
 
81
  .bar {
82
  position: absolute;
83
  bottom: 0;
84
- width: 8px;
85
- background-color: #3b82f6;
86
- border-radius: 4px 4px 0 0;
87
- transition: height 0.1s ease;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  }
89
  </style>
90
  </head>
91
- <body class="bg-gray-100 min-h-screen">
92
- <div class="container mx-auto px-4 py-8">
93
- <div class="max-w-3xl mx-auto">
94
- <div class="text-center mb-8">
95
- <h1 class="text-4xl font-bold text-gray-800 mb-2">Advanced Audio Recorder</h1>
96
- <p class="text-gray-600">Select your input device, record, and download in multiple formats</p>
97
- </div>
98
-
99
- <div class="bg-white rounded-xl shadow-lg overflow-hidden mb-8">
100
- <div class="p-6">
101
- <!-- Device Selection Section -->
102
- <div class="mb-6">
103
- <h3 class="text-lg font-semibold text-gray-800 mb-3">Select Input Device</h3>
104
- <div class="flex flex-col sm:flex-row gap-4 mb-4">
105
- <div class="flex-1">
106
- <label for="audioSource" class="block text-sm font-medium text-gray-700 mb-1">Audio Input</label>
107
- <select id="audioSource" class="w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 py-2 px-3 border">
108
- <option value="">Default</option>
109
- </select>
110
- </div>
111
- <div class="flex-1">
112
- <label for="audioQuality" class="block text-sm font-medium text-gray-700 mb-1">Quality</label>
113
- <select id="audioQuality" class="w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 py-2 px-3 border">
114
- <option value="high">High (CD Quality)</option>
115
- <option value="medium" selected>Medium (Good Quality)</option>
116
- <option value="low">Low (Voice Only)</option>
117
- </select>
118
- </div>
119
- </div>
120
-
121
- <div class="visualizer mb-4" id="visualizer">
122
- <!-- Audio bars will be inserted here by JavaScript -->
123
- </div>
124
-
125
- <div class="text-center text-sm text-gray-500" id="deviceStatus">
126
- <i class="fas fa-microphone-slash mr-1"></i> No device selected
127
  </div>
128
  </div>
129
-
130
- <div class="waveform mb-6" id="waveform"></div>
131
-
132
- <div class="flex flex-col sm:flex-row justify-center items-center gap-4 mb-6">
133
- <button id="recordBtn" class="bg-red-500 hover:bg-red-600 text-white font-bold py-3 px-6 rounded-full flex items-center gap-2 transition-all">
134
- <i class="fas fa-microphone"></i> Start Recording
135
- </button>
136
- <button id="stopBtn" disabled class="bg-gray-300 text-gray-600 font-bold py-3 px-6 rounded-full flex items-center gap-2 transition-all">
137
- <i class="fas fa-stop"></i> Stop
138
- </button>
139
- <button id="playBtn" disabled class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-full flex items-center gap-2 transition-all">
140
- <i class="fas fa-play"></i> Play
141
- </button>
142
  </div>
143
-
144
- <div class="text-center text-gray-500 mb-4">
145
- <span id="timer">00:00</span>
 
 
 
 
 
146
  </div>
147
  </div>
148
-
149
- <div class="bg-gray-50 p-6 border-t border-gray-200">
150
- <h3 class="text-lg font-semibold text-gray-800 mb-4">Download Options</h3>
151
-
152
- <div class="grid grid-cols-2 sm:grid-cols-4 gap-4">
153
- <div class="format-option bg-white p-4 rounded-lg border border-gray-200 text-center cursor-pointer" data-format="wav">
154
- <i class="fas fa-file-audio text-3xl text-blue-500 mb-2"></i>
155
- <p class="font-medium">WAV</p>
156
- <p class="text-sm text-gray-500">High quality</p>
 
 
 
157
  </div>
158
- <div class="format-option bg-white p-4 rounded-lg border border-gray-200 text-center cursor-pointer" data-format="mp3">
159
- <i class="fas fa-file-audio text-3xl text-purple-500 mb-2"></i>
160
- <p class="font-medium">MP3</p>
161
- <p class="text-sm text-gray-500">Compressed</p>
162
  </div>
163
- <div class="format-option bg-white p-4 rounded-lg border border-gray-200 text-center cursor-pointer" data-format="ogg">
164
- <i class="fas fa-file-audio text-3xl text-green-500 mb-2"></i>
165
- <p class="font-medium">OGG</p>
166
- <p class="text-sm text-gray-500">Web optimized</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  </div>
168
- <div class="format-option bg-white p-4 rounded-lg border border-gray-200 text-center cursor-pointer" data-format="aac">
169
- <i class="fas fa-file-audio text-3xl text-red-500 mb-2"></i>
170
- <p class="font-medium">AAC</p>
171
- <p class="text-sm text-gray-500">Mobile friendly</p>
172
  </div>
173
  </div>
174
 
175
- <button id="downloadBtn" disabled class="mt-6 w-full bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-4 rounded-lg flex items-center justify-center gap-2 transition-all">
176
- <i class="fas fa-download"></i> Download Audio
177
- </button>
178
- </div>
179
- </div>
180
-
181
- <div class="bg-white rounded-xl shadow-lg overflow-hidden">
182
- <div class="p-6">
183
- <h3 class="text-lg font-semibold text-gray-800 mb-4">Recording History</h3>
184
- <div id="recordingsList" class="space-y-3">
185
- <div class="text-center text-gray-500 py-8">
186
- <i class="fas fa-microphone-slash text-3xl mb-2"></i>
187
- <p>No recordings yet</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  </div>
189
  </div>
190
  </div>
191
  </div>
192
- </div>
193
- </div>
194
 
195
  <script>
196
  document.addEventListener('DOMContentLoaded', function() {
@@ -214,6 +479,7 @@
214
  const stopBtn = document.getElementById('stopBtn');
215
  const playBtn = document.getElementById('playBtn');
216
  const downloadBtn = document.getElementById('downloadBtn');
 
217
  const timer = document.getElementById('timer');
218
  const recordingsList = document.getElementById('recordingsList');
219
  const formatOptions = document.querySelectorAll('.format-option');
@@ -221,8 +487,86 @@
221
  const audioQualitySelect = document.getElementById('audioQuality');
222
  const visualizer = document.getElementById('visualizer');
223
  const deviceStatus = document.getElementById('deviceStatus');
 
 
 
 
 
 
 
224
 
225
  let selectedFormat = 'wav'; // Default format
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
 
227
  // Create audio bars for visualizer
228
  const barCount = 40;
@@ -246,7 +590,6 @@
246
 
247
  // Set first format as selected by default
248
  formatOptions[0].classList.add('ring-2', 'ring-indigo-500');
249
-
250
  // Get available audio devices
251
  async function getAudioDevices() {
252
  try {
@@ -259,7 +602,7 @@
259
  const audioInputs = devices.filter(device => device.kind === 'audioinput');
260
 
261
  // Clear existing options
262
- audioSourceSelect.innerHTML = '<option value="">Default</option>';
263
 
264
  // Add each audio input device as an option
265
  audioInputs.forEach(device => {
@@ -277,7 +620,12 @@
277
  }
278
  }
279
 
280
- // Stop a media stream
 
 
 
 
 
281
  function stopStream(stream) {
282
  if (stream) {
283
  stream.getTracks().forEach(track => track.stop());
@@ -342,7 +690,6 @@
342
  // Update device status
343
  deviceStatus.innerHTML = '<i class="fas fa-microphone-slash mr-1"></i> No active input';
344
  }
345
-
346
  // Get audio constraints based on selected quality
347
  function getAudioConstraints() {
348
  const deviceId = audioSourceSelect.value;
@@ -359,25 +706,70 @@
359
 
360
  // Adjust constraints based on quality
361
  if (quality === 'high') {
362
- constraints.audio.sampleRate = 48000;
363
  constraints.audio.channelCount = 2;
364
- constraints.audio.sampleSize = 16;
365
- constraints.audio.bitrate = 256000;
366
  } else if (quality === 'medium') {
367
- constraints.audio.sampleRate = 44100;
368
  constraints.audio.channelCount = 1;
369
  constraints.audio.sampleSize = 16;
370
- constraints.audio.bitrate = 128000;
371
  } else { // low
372
- constraints.audio.sampleRate = 22050;
373
  constraints.audio.channelCount = 1;
374
- constraints.audio.sampleSize = 8;
375
- constraints.audio.bitrate = 64000;
376
  }
377
 
378
  return constraints;
379
  }
380
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  // Initialize device selection
382
  getAudioDevices().then(success => {
383
  if (success) {
@@ -395,6 +787,7 @@
395
  const constraints = getAudioConstraints();
396
  currentStream = await navigator.mediaDevices.getUserMedia(constraints);
397
  visualizeAudio(currentStream);
 
398
  } catch (error) {
399
  console.error('Error accessing selected device:', error);
400
  deviceStatus.innerHTML = '<i class="fas fa-exclamation-triangle mr-1"></i> Could not access selected device';
@@ -412,7 +805,177 @@
412
  }
413
  });
414
 
415
- // Request permission to use microphone
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
  recordBtn.addEventListener('click', async function() {
417
  try {
418
  const constraints = getAudioConstraints();
@@ -535,8 +1098,7 @@
535
  const remainingSeconds = seconds % 60;
536
  timer.textContent = `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
537
  }
538
-
539
- // Add recording to history list
540
  function addRecordingToList(url) {
541
  // Remove placeholder if it exists
542
  if (recordingsList.querySelector('.text-center')) {
@@ -544,24 +1106,30 @@
544
  }
545
 
546
  const recordingItem = document.createElement('div');
547
- recordingItem.className = 'bg-gray-50 p-4 rounded-lg border border-gray-200 flex items-center justify-between';
548
 
549
  recordingItem.innerHTML = `
550
- <div class="flex items-center gap-3">
551
- <i class="fas fa-microphone text-indigo-500"></i>
552
- <div>
553
- <p class="font-medium">Recording ${recordingsList.children.length + 1}</p>
554
- <p class="text-sm text-gray-500">${new Date().toLocaleString()}</p>
555
- <p class="text-xs text-gray-400">${audioSourceSelect.options[audioSourceSelect.selectedIndex].text}</p>
 
 
556
  </div>
557
  </div>
558
  <div class="flex gap-2">
559
- <button class="play-history-btn bg-blue-500 hover:bg-blue-600 text-white p-2 rounded-full">
560
- <i class="fas fa-play text-xs"></i>
561
- </button>
562
- <button class="download-history-btn bg-indigo-500 hover:bg-indigo-600 text-white p-2 rounded-full">
563
- <i class="fas fa-download text-xs"></i>
564
- </button>
 
 
 
 
565
  </div>
566
  `;
567
 
@@ -570,6 +1138,7 @@
570
  // Add event listeners to the new buttons
571
  const playBtn = recordingItem.querySelector('.play-history-btn');
572
  const downloadBtn = recordingItem.querySelector('.download-history-btn');
 
573
 
574
  const audio = new Audio(url);
575
 
@@ -600,12 +1169,54 @@
600
  }, 100);
601
  });
602
 
 
 
 
 
 
 
 
 
 
603
  // Reset play button when audio ends
604
  audio.addEventListener('ended', function() {
605
- playBtn.innerHTML = '<i class="fas fa-play text-xs"></i>';
606
  });
607
  }
608
  });
609
- </script>
610
- <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=NeoPy/audio-recorder" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
611
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Audio Studio Pro | YouTube-Style Recorder</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
+ :root {
11
+ --yt-red: #ff0000;
12
+ --yt-dark: #0f0f0f;
13
+ --yt-gray: #272727;
14
+ --yt-light-gray: #3f3f3f;
15
+ }
16
+
17
  .waveform {
18
+ background: linear-gradient(90deg, #ff0000 0%, #cc0000 50%, #990000 100%);
19
  height: 100px;
20
+ border-radius: 0.75rem;
21
  position: relative;
22
  overflow: hidden;
23
+ box-shadow: 0 4px 20px rgba(255, 0, 0, 0.3);
24
  }
25
 
26
  .waveform::after {
 
31
  right: 0;
32
  bottom: 0;
33
  background: linear-gradient(90deg,
34
+ rgba(255,255,255,0.15) 0%,
35
+ rgba(255,255,255,0.25) 50%,
36
+ rgba(255,255,255,0.15) 100%);
37
+ animation: wave 1.8s linear infinite;
38
  transform: translateX(-100%);
39
  }
40
 
 
45
  }
46
 
47
  .recording-animation {
48
+ animation: youtube-pulse 1.2s infinite;
49
  }
50
 
51
+ @keyframes youtube-pulse {
52
  0% {
53
+ box-shadow: 0 0 0 0 rgba(255, 0, 0, 0.8);
54
+ transform: scale(1);
55
  }
56
+ 50% {
57
+ transform: scale(1.05);
58
  }
59
  100% {
60
+ box-shadow: 0 0 0 15px rgba(255, 0, 0, 0);
61
+ transform: scale(1);
62
  }
63
  }
64
 
65
  .format-option:hover {
66
+ transform: translateY(-5px);
67
+ box-shadow: 0 15px 30px rgba(255, 0, 0, 0.3);
68
+ background: var(--yt-gray) !important;
69
  }
70
 
71
  .format-option {
72
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
73
+ border: 1px solid var(--yt-light-gray);
74
  }
75
 
76
  .device-option:hover {
77
+ background-color: var(--yt-gray) !important;
78
  }
79
 
80
  .device-option {
81
+ transition: all 0.3s ease;
82
  }
83
 
84
  .visualizer {
85
  width: 100%;
86
+ height: 100px;
87
+ background: var(--yt-dark);
88
+ border-radius: 0.75rem;
89
  position: relative;
90
  overflow: hidden;
91
+ box-shadow: inset 0 2px 10px rgba(0,0,0,0.5);
92
  }
93
 
94
  .bar {
95
  position: absolute;
96
  bottom: 0;
97
+ width: 6px;
98
+ background: linear-gradient(to top, #ff0000, #cc0000);
99
+ border-radius: 3px 3px 0 0;
100
+ transition: height 0.08s ease;
101
+ }
102
+
103
+ .youtube-nav {
104
+ background: var(--yt-dark);
105
+ border-bottom: 1px solid var(--yt-light-gray);
106
+ }
107
+
108
+ .youtube-sidebar {
109
+ background: var(--yt-dark);
110
+ border-right: 1px solid var(--yt-light-gray);
111
+ }
112
+
113
+ .youtube-card {
114
+ background: var(--yt-gray);
115
+ border-radius: 1rem;
116
+ border: 1px solid var(--yt-light-gray);
117
+ box-shadow: 0 4px 25px rgba(0,0,0,0.4);
118
+ transition: all 0.3s ease;
119
+ }
120
+
121
+ .youtube-card:hover {
122
+ transform: translateY(-3px);
123
+ box-shadow: 0 8px 35px rgba(255, 0, 0, 0.2);
124
+ }
125
+
126
+ .gradient-text {
127
+ background: linear-gradient(135deg, #ff0000, #cc0000);
128
+ -webkit-background-clip: text;
129
+ -webkit-text-fill-color: transparent;
130
+ background-clip: text;
131
+ }
132
+
133
+ .live-indicator {
134
+ background: var(--yt-red);
135
+ color: white;
136
+ padding: 2px 8px;
137
+ border-radius: 4px;
138
+ font-size: 0.75rem;
139
+ font-weight: bold;
140
+ animation: live-pulse 2s infinite;
141
+ }
142
+
143
+ @keyframes live-pulse {
144
+ 0%, 100% { opacity: 1; }
145
+ 50% { opacity: 0.7; }
146
+ }
147
+
148
+ .yt-button {
149
+ background: var(--yt-gray);
150
+ border: 1px solid var(--yt-light-gray);
151
+ transition: all 0.3s ease;
152
+ }
153
+
154
+ .yt-button:hover {
155
+ background: var(--yt-light-gray);
156
+ }
157
+
158
+ .yt-button-primary {
159
+ background: var(--yt-red);
160
+ border: 1px solid var(--yt-red);
161
+ }
162
+
163
+ .yt-button-primary:hover {
164
+ background: #cc0000;
165
+ border-color: #cc0000;
166
+ }
167
+
168
+ .progress-bar {
169
+ height: 4px;
170
+ background: var(--yt-light-gray);
171
+ border-radius: 2px;
172
+ overflow: hidden;
173
+ }
174
+
175
+ .progress-fill {
176
+ height: 100%;
177
+ background: var(--yt-red);
178
+ border-radius: 2px;
179
+ transition: width 0.1s linear;
180
+ }
181
+
182
+ .recording-item {
183
+ background: var(--yt-gray);
184
+ border: 1px solid var(--yt-light-gray);
185
+ border-radius: 0.75rem;
186
+ transition: all 0.3s ease;
187
+ }
188
+
189
+ .recording-item:hover {
190
+ background: #2a2a2a;
191
+ border-color: #4a4a4a;
192
+ }
193
+
194
+ .sidebar-item {
195
+ transition: all 0.2s ease;
196
+ }
197
+
198
+ .sidebar-item:hover {
199
+ background: var(--yt-light-gray);
200
  }
201
  </style>
202
  </head>
203
+ <body class="bg-[#0f0f0f] min-h-screen text-white">
204
+ <!-- YouTube-style Navigation -->
205
+ <nav class="youtube-nav sticky top-0 z-50">
206
+ <div class="container mx-auto px-4 py-3">
207
+ <div class="flex items-center justify-between">
208
+ <div class="flex items-center gap-6">
209
+ <div class="flex items-center gap-2">
210
+ <i class="fas fa-bars text-xl cursor-pointer"></i>
211
+ <div class="flex items-center gap-2">
212
+ <i class="fab fa-youtube text-2xl text-red-500"></i>
213
+ <span class="text-xl font-bold">Audio Studio Pro</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  </div>
215
  </div>
216
+ </div>
217
+ <div class="flex-1 max-w-2xl mx-8">
218
+ <div class="relative">
219
+ <input type="text" placeholder="Search recordings..." class="w-full bg-[#121212] border border-[#303030] rounded-full py-2 px-4 text-sm focus:outline-none focus:border-[#3ea6ff] transition-all">
220
+ <i class="fas fa-search absolute right-3 top-2.5 text-gray-400"></i>
 
 
 
 
 
 
 
 
221
  </div>
222
+ </div>
223
+ <div class="flex items-center gap-4">
224
+ <div class="flex items-center gap-2">
225
+ <span class="live-indicator flex items-center gap-1">
226
+ <i class="fas fa-circle text-xs"></i>
227
+ LIVE
228
+ </span>
229
+ </div>
230
  </div>
231
  </div>
232
+ </div>
233
+ </div>
234
+ </nav>
235
+
236
+ <div class="flex">
237
+ <!-- YouTube-style Sidebar -->
238
+ <div class="youtube-sidebar w-64 min-h-screen hidden md:block">
239
+ <div class="p-4 space-y-2">
240
+ <div class="sidebar-item p-3 rounded-lg bg-[#272727] cursor-pointer">
241
+ <div class="flex items-center gap-3">
242
+ <i class="fas fa-home text-red-500"></i>
243
+ <span>Home</span>
244
  </div>
245
+ <div class="sidebar-item p-3 rounded-lg cursor-pointer">
246
+ <div class="flex items-center gap-3">
247
+ <i class="fas fa-fire text-red-500"></i>
248
+ <span>Trending</span>
249
  </div>
250
+ <div class="sidebar-item p-3 rounded-lg cursor-pointer">
251
+ <div class="flex items-center gap-3">
252
+ <i class="fas fa-microphone text-red-500"></i>
253
+ <span>Recordings</span>
254
+ </div>
255
+ <div class="sidebar-item p-3 rounded-lg cursor-pointer">
256
+ <div class="flex items-center gap-3">
257
+ <i class="fas fa-music text-red-500"></i>
258
+ <span>Music</span>
259
+ </div>
260
+ <div class="sidebar-item p-3 rounded-lg cursor-pointer">
261
+ <div class="flex items-center gap-3">
262
+ <i class="fas fa-cog text-red-500"></i>
263
+ <span>Settings</span>
264
+ </div>
265
+ </div>
266
+ </div>
267
+
268
+ <!-- Main Content -->
269
+ <div class="flex-1">
270
+ <div class="container mx-auto px-4 py-6">
271
+ <div class="max-w-5xl mx-auto">
272
+ <!-- Header Section -->
273
+ <div class="flex items-center justify-between mb-8">
274
+ <div>
275
+ <h1 class="text-3xl font-bold gradient-text mb-2">Audio Studio Pro</h1>
276
+ <p class="text-gray-400">Professional recording studio with YouTube-inspired interface</p>
277
  </div>
278
+ <div class="flex items-center gap-3">
279
+ <div class="flex items-center gap-2 text-sm text-gray-400">
280
+ <i class="fas fa-users"></i>
281
+ <span>1.2K active</span>
282
  </div>
283
  </div>
284
 
285
+ <!-- Main Recording Card -->
286
+ <div class="youtube-card overflow-hidden mb-8">
287
+ <div class="p-6">
288
+ <!-- Live Status Header -->
289
+ <div class="flex items-center justify-between mb-6">
290
+ <div class="flex items-center gap-3">
291
+ <div class="w-3 h-3 bg-red-500 rounded-full animate-pulse"></div>
292
+ <span class="text-red-500 font-semibold">RECORDING STUDIO</div>
293
+ <div class="live-indicator flex items-center gap-2">
294
+ <i class="fas fa-circle text-xs"></i>
295
+ LIVE INPUT
296
+ </div>
297
+ </div>
298
+
299
+ <!-- Device Selection Section -->
300
+ <div class="mb-6">
301
+ <div class="flex items-center justify-between mb-3">
302
+ <h3 class="text-lg font-semibold text-white">Audio Input Devices</h3>
303
+ <button id="refreshDevices" class="yt-button px-3 py-1 rounded-lg text-sm">
304
+ <i class="fas fa-sync-alt mr-1"></i>
305
+ Refresh
306
+ </button>
307
+ </div>
308
+ <div class="flex flex-col sm:flex-row gap-4 mb-4">
309
+ <div class="flex-1">
310
+ <label for="audioSource" class="block text-sm font-medium text-gray-300 mb-1">Audio Input</label>
311
+ <select id="audioSource" class="w-full bg-[#272727] border border-[#3f3f3f] rounded-lg py-2 px-3 text-white focus:outline-none focus:border-[#ff0000] transition-all">
312
+ <option value="">Default Device</option>
313
+ </select>
314
+ </div>
315
+ <div class="flex-1">
316
+ <label for="audioQuality" class="block text-sm font-medium text-gray-300 mb-1">Quality Preset</label>
317
+ <select id="audioQuality" class="w-full bg-[#272727] border border-[#3f3f3f] rounded-lg py-2 px-3 text-white focus:outline-none focus:border-[#ff0000] transition-all">
318
+ <option value="high">Studio (24-bit/96kHz)</option>
319
+ <option value="medium" selected>Professional (16-bit/48kHz)</option>
320
+ <option value="low">Podcast (16-bit/44.1kHz)</option>
321
+ </select>
322
+ </div>
323
+ </div>
324
+
325
+ <!-- Advanced Settings -->
326
+ <div class="mb-4">
327
+ <div class="flex items-center justify-between mb-2">
328
+ <h4 class="text-sm font-medium text-gray-300">Advanced Settings</h4>
329
+ <button id="toggleAdvanced" class="yt-button px-3 py-1 rounded-lg text-sm">
330
+ <i class="fas fa-sliders-h mr-1"></i>
331
+ Show Advanced
332
+ </button>
333
+ </div>
334
+
335
+ <div id="advancedSettings" class="hidden grid grid-cols-2 gap-4 mb-4">
336
+ <div>
337
+ <label for="noiseReduction" class="block text-sm text-gray-400 mb-1">Noise Reduction</label>
338
+ <select id="noiseReduction" class="w-full bg-[#272727] border border-[#3f3f3f] rounded-lg py-2 px-3 text-white focus:outline-none focus:border-[#ff0000] transition-all">
339
+ <option value="high">High</option>
340
+ <option value="medium" selected>Medium</option>
341
+ <option value="low">Low</option>
342
+ <option value="off">Off</option>
343
+ </select>
344
+ </div>
345
+ <div>
346
+ <label for="autoGain" class="block text-sm text-gray-400 mb-1">Auto Gain</label>
347
+ <select id="autoGain" class="w-full bg-[#272727] border border-[#3f3f3f] rounded-lg py-2 px-3 text-white focus:outline-none focus:border-[#ff0000] transition-all">
348
+ <option value="on" selected>On</option>
349
+ <option value="off">Off</option>
350
+ </select>
351
+ </div>
352
+ </div>
353
+
354
+ <div class="visualizer mb-4" id="visualizer">
355
+ <!-- Audio bars will be inserted here by JavaScript -->
356
+ </div>
357
+
358
+ <div class="flex items-center justify-between text-sm">
359
+ <div id="deviceStatus" class="text-gray-400">
360
+ <i class="fas fa-microphone-slash mr-1"></i> No device selected
361
+ </div>
362
+ <div class="text-gray-400">
363
+ <i class="fas fa-database mr-1"></i>
364
+ <span id="fileSize">0 MB</span>
365
+ </div>
366
+ </div>
367
+ </div>
368
+
369
+ <!-- Waveform Display -->
370
+ <div class="waveform mb-6" id="waveform"></div>
371
+
372
+ <!-- Control Buttons -->
373
+ <div class="flex flex-col sm:flex-row justify-center items-center gap-4 mb-6">
374
+ <button id="recordBtn" class="yt-button-primary font-bold py-3 px-8 rounded-full flex items-center gap-2 transition-all">
375
+ <i class="fas fa-record-vinyl"></i> Start Recording
376
+ </button>
377
+ <button id="stopBtn" disabled class="yt-button font-bold py-3 px-8 rounded-full flex items-center gap-2 transition-all">
378
+ <i class="fas fa-stop"></i> Stop
379
+ </button>
380
+ <button id="playBtn" disabled class="yt-button font-bold py-3 px-8 rounded-full flex items-center gap-2 transition-all">
381
+ <i class="fas fa-play"></i> Preview
382
+ </button>
383
+ </div>
384
+
385
+ <!-- Progress and Timer -->
386
+ <div class="mb-4">
387
+ <div class="progress-bar mb-2">
388
+ <div id="progressFill" class="progress-fill" style="width: 0%"></div>
389
+ <div class="flex justify-between items-center">
390
+ <span id="timer" class="text-gray-400">00:00</span>
391
+ <span class="text-gray-400">
392
+ <i class="fas fa-volume-up mr-1"></i>
393
+ <span id="volumeLevel">50%</span>
394
+ </div>
395
+ </div>
396
+ </div>
397
+ </div>
398
+
399
+ <!-- Download Section -->
400
+ <div class="bg-[#1f1f1f] p-6 border-t border-[#3f3f3f]">
401
+ <h3 class="text-lg font-semibold text-white mb-4">Export & Download</h3>
402
+
403
+ <div class="grid grid-cols-2 sm:grid-cols-4 gap-4 mb-6">
404
+ <div class="format-option bg-[#272727] p-4 rounded-lg text-center cursor-pointer" data-format="wav">
405
+ <i class="fas fa-file-waveform text-3xl text-red-500 mb-2"></i>
406
+ <p class="font-medium">WAV</p>
407
+ <p class="text-sm text-gray-400">Lossless Quality</p>
408
+ </div>
409
+ <div class="format-option bg-[#272727] p-4 rounded-lg text-center cursor-pointer" data-format="mp3">
410
+ <i class="fas fa-file-audio text-3xl text-red-400 mb-2"></i>
411
+ <p class="font-medium">MP3</p>
412
+ <p class="text-sm text-gray-400">Universal Format</p>
413
+ </div>
414
+ <div class="format-option bg-[#272727] p-4 rounded-lg text-center cursor-pointer" data-format="ogg">
415
+ <i class="fas fa-file-audio text-3xl text-red-300 mb-2"></i>
416
+ <p class="font-medium">OGG</p>
417
+ <p class="text-sm text-gray-400">Web Streaming</p>
418
+ </div>
419
+ <div class="format-option bg-[#272727] p-4 rounded-lg text-center cursor-pointer" data-format="aac">
420
+ <i class="fas fa-file-audio text-3xl text-red-200 mb-2"></i>
421
+ <p class="font-medium">AAC</p>
422
+ <p class="text-sm text-gray-400">Mobile Devices</p>
423
+ </div>
424
+ </div>
425
+
426
+ <div class="flex gap-4">
427
+ <button id="downloadBtn" disabled class="flex-1 yt-button-primary font-bold py-3 px-4 rounded-lg flex items-center justify-center gap-2 transition-all">
428
+ <i class="fas fa-download"></i> Download Selected Format
429
+ </button>
430
+ <button id="shareBtn" disabled class="yt-button px-4 py-3 rounded-lg flex items-center gap-2">
431
+ <i class="fas fa-share-alt"></i>
432
+ </button>
433
+ </div>
434
+ </div>
435
+ </div>
436
+
437
+ <!-- Recording History Section -->
438
+ <div class="youtube-card mt-8">
439
+ <div class="p-6">
440
+ <div class="flex items-center justify-between mb-4">
441
+ <h3 class="text-lg font-semibold text-white">Recording Library</h3>
442
+ <div class="flex items-center gap-2 text-sm text-gray-400">
443
+ <i class="fas fa-history"></i>
444
+ <span>Recent Recordings</span>
445
+ </div>
446
+ </div>
447
+ <div id="recordingsList" class="space-y-3">
448
+ <div class="text-center text-gray-500 py-8">
449
+ <i class="fas fa-microphone-slash text-3xl mb-2"></i>
450
+ <p>No recordings in your library</p>
451
+ </div>
452
+ </div>
453
+ </div>
454
  </div>
455
  </div>
456
  </div>
457
  </div>
458
+ </div>
 
459
 
460
  <script>
461
  document.addEventListener('DOMContentLoaded', function() {
 
479
  const stopBtn = document.getElementById('stopBtn');
480
  const playBtn = document.getElementById('playBtn');
481
  const downloadBtn = document.getElementById('downloadBtn');
482
+ const shareBtn = document.getElementById('shareBtn');
483
  const timer = document.getElementById('timer');
484
  const recordingsList = document.getElementById('recordingsList');
485
  const formatOptions = document.querySelectorAll('.format-option');
 
487
  const audioQualitySelect = document.getElementById('audioQuality');
488
  const visualizer = document.getElementById('visualizer');
489
  const deviceStatus = document.getElementById('deviceStatus');
490
+ const refreshDevicesBtn = document.getElementById('refreshDevices');
491
+ const toggleAdvancedBtn = document.getElementById('toggleAdvanced');
492
+ const advancedSettings = document.getElementById('advancedSettings');
493
+ const progressFill = document.getElementById('progressFill');
494
+ const fileSize = document.getElementById('fileSize');
495
+ const volumeLevel = document.getElementById('volumeLevel');
496
+ const mobileRecordBtn = document.getElementById('mobileRecordBtn');
497
 
498
  let selectedFormat = 'wav'; // Default format
499
+ let isAdvancedVisible = false;
500
+
501
+ // Initialize features
502
+ function initFeatures() {
503
+ // Toggle advanced settings
504
+ toggleAdvancedBtn.addEventListener('click', function() {
505
+ isAdvancedVisible = !isAdvancedVisible;
506
+ if (isAdvancedVisible) {
507
+ advancedSettings.classList.remove('hidden');
508
+ this.innerHTML = '<i class="fas fa-times mr-1"></i> Hide Advanced';
509
+ } else {
510
+ advancedSettings.classList.add('hidden');
511
+ this.innerHTML = '<i class="fas fa-sliders-h mr-1"></i> Show Advanced';
512
+ }
513
+ });
514
+
515
+ // Refresh devices
516
+ refreshDevicesBtn.addEventListener('click', function() {
517
+ this.classList.add('animate-spin');
518
+ getAudioDevices().then(success => {
519
+ setTimeout(() => {
520
+ this.classList.remove('animate-spin');
521
+ // Trigger device selection update
522
+ if (audioSourceSelect.value) {
523
+ audioSourceSelect.dispatchEvent(new Event('change'));
524
+ }, 500);
525
+ });
526
+
527
+ // Mobile record button
528
+ if (mobileRecordBtn) {
529
+ mobileRecordBtn.addEventListener('click', function() {
530
+ recordBtn.click();
531
+ });
532
+ }
533
+
534
+ // Volume control simulation
535
+ let volume = 50;
536
+ setInterval(() => {
537
+ if (audioElement && !audioElement.paused) {
538
+ volume = Math.min(100, Math.max(0, volume + (Math.random() * 4 - 2));
539
+ volumeLevel.textContent = `${Math.round(volume)}%`;
540
+ }
541
+ }, 1000);
542
+ }
543
+
544
+ // Create audio bars for visualizer
545
+ const barCount = 40;
546
+ for (let i = 0; i < barCount; i++) {
547
+ const bar = document.createElement('div');
548
+ bar.className = 'bar';
549
+ bar.style.left = `${i * (100 / barCount)}%`;
550
+ bar.style.height = '0%';
551
+ visualizer.appendChild(bar);
552
+ }
553
+ const bars = document.querySelectorAll('.bar');
554
+
555
+ // Format selection
556
+ formatOptions.forEach(option => {
557
+ option.addEventListener('click', function() {
558
+ formatOptions.forEach(opt => opt.classList.remove('ring-2', 'ring-red-500'));
559
+ this.classList.add('ring-2', 'ring-red-500');
560
+ selectedFormat = this.dataset.format;
561
+ });
562
+ });
563
+
564
+ // Set first format as selected by default
565
+ formatOptions[0].classList.add('ring-2', 'ring-red-500');
566
+
567
+ // Initialize features
568
+ initFeatures();
569
+ let selectedFormat = 'wav'; // Default format
570
 
571
  // Create audio bars for visualizer
572
  const barCount = 40;
 
590
 
591
  // Set first format as selected by default
592
  formatOptions[0].classList.add('ring-2', 'ring-indigo-500');
 
593
  // Get available audio devices
594
  async function getAudioDevices() {
595
  try {
 
602
  const audioInputs = devices.filter(device => device.kind === 'audioinput');
603
 
604
  // Clear existing options
605
+ audioSourceSelect.innerHTML = '<option value="">Default Device</option>';
606
 
607
  // Add each audio input device as an option
608
  audioInputs.forEach(device => {
 
620
  }
621
  }
622
 
623
+ // Simulate file size calculation
624
+ function updateFileSize(duration) {
625
+ const baseSize = duration * 0.1; // MB per minute
626
+ fileSize.textContent = `${baseSize.toFixed(1)} MB estimated';
627
+ }
628
+ // Stop a media stream
629
  function stopStream(stream) {
630
  if (stream) {
631
  stream.getTracks().forEach(track => track.stop());
 
690
  // Update device status
691
  deviceStatus.innerHTML = '<i class="fas fa-microphone-slash mr-1"></i> No active input';
692
  }
 
693
  // Get audio constraints based on selected quality
694
  function getAudioConstraints() {
695
  const deviceId = audioSourceSelect.value;
 
706
 
707
  // Adjust constraints based on quality
708
  if (quality === 'high') {
709
+ constraints.audio.sampleRate = 96000;
710
  constraints.audio.channelCount = 2;
711
+ constraints.audio.sampleSize = 24;
712
+ constraints.audio.bitrate = 320000;
713
  } else if (quality === 'medium') {
714
+ constraints.audio.sampleRate = 48000;
715
  constraints.audio.channelCount = 1;
716
  constraints.audio.sampleSize = 16;
717
+ constraints.audio.bitrate = 192000;
718
  } else { // low
719
+ constraints.audio.sampleRate = 44100;
720
  constraints.audio.channelCount = 1;
721
+ constraints.audio.sampleSize = 16;
722
+ constraints.audio.bitrate = 128000;
723
  }
724
 
725
  return constraints;
726
  }
727
 
728
+ // Enhanced visualization with YouTube colors
729
+ function visualizeAudio(stream) {
730
+ // Create audio context if it doesn't exist
731
+ if (!audioContext) {
732
+ audioContext = new (window.AudioContext || window.webkitAudioContext)();
733
+ }
734
+
735
+ // Create analyser node
736
+ analyser = audioContext.createAnalyser();
737
+ analyser.fftSize = 512;
738
+
739
+ // Create microphone source
740
+ microphone = audioContext.createMediaStreamSource(stream);
741
+ microphone.connect(analyser);
742
+
743
+ // Create data array for analysis
744
+ const bufferLength = analyser.frequencyBinCount;
745
+ dataArray = new Uint8Array(bufferLength);
746
+
747
+ // Start animation loop
748
+ function animate() {
749
+ animationId = requestAnimationFrame(animate);
750
+ analyser.getByteFrequencyData(dataArray);
751
+
752
+ // Update bars with YouTube red gradient
753
+ for (let i = 0; i < bars.length; i++) {
754
+ // Scale the index to cover the full frequency range
755
+ const scaledIndex = Math.floor(i * (bufferLength / bars.length));
756
+ const value = dataArray[scaledIndex];
757
+ const height = value / 2.55; // Convert 0-255 to 0-100
758
+ bars[i].style.height = `${height}%`;
759
+ // Dynamic color based on amplitude
760
+ const hue = 0; // Red
761
+ const saturation = 100;
762
+ const lightness = 40 + (height * 0.3);
763
+ bars[i].style.background = `linear-gradient(to top, hsl(${hue}, ${saturation}%, ${lightness}%), hsl(${hue}, ${saturation}%, ${Math.max(20, lightness - 20)}%)`;
764
+ }
765
+ }
766
+
767
+ // Start animation
768
+ animate();
769
+
770
+ // Update device status with YouTube style
771
+ deviceStatus.innerHTML = `<i class="fas fa-microphone mr-1"></i> <span class="text-red-400">${audioSourceSelect.options[audioSourceSelect.selectedIndex].text}</span>`;
772
+ }
773
  // Initialize device selection
774
  getAudioDevices().then(success => {
775
  if (success) {
 
787
  const constraints = getAudioConstraints();
788
  currentStream = await navigator.mediaDevices.getUserMedia(constraints);
789
  visualizeAudio(currentStream);
790
+ updateFileSize(0);
791
  } catch (error) {
792
  console.error('Error accessing selected device:', error);
793
  deviceStatus.innerHTML = '<i class="fas fa-exclamation-triangle mr-1"></i> Could not access selected device';
 
805
  }
806
  });
807
 
808
+ // Enhanced recording with progress tracking
809
+ recordBtn.addEventListener('click', async function() {
810
+ try {
811
+ const constraints = getAudioConstraints();
812
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
813
+ currentStream = stream;
814
+
815
+ // Stop visualization if it's running
816
+ stopVisualization();
817
+
818
+ mediaRecorder = new MediaRecorder(stream);
819
+ audioChunks = [];
820
+
821
+ mediaRecorder.ondataavailable = function(event) {
822
+ audioChunks.push(event.data);
823
+ };
824
+
825
+ mediaRecorder.onstop = function() {
826
+ audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
827
+ audioUrl = URL.createObjectURL(audioBlob);
828
+
829
+ // Create audio element for playback
830
+ audioElement = new Audio(audioUrl);
831
+
832
+ // Enable play, download, and share buttons
833
+ playBtn.disabled = false;
834
+ downloadBtn.disabled = false;
835
+ shareBtn.disabled = false;
836
+
837
+ // Add to recordings list
838
+ addRecordingToList(audioUrl);
839
+
840
+ // Restart visualization if a device was selected
841
+ if (audioSourceSelect.value) {
842
+ visualizeAudio(currentStream);
843
+ }
844
+ };
845
+
846
+ mediaRecorder.start(10); // Collect data every 10ms
847
+
848
+ // Start timer and progress
849
+ seconds = 0;
850
+ updateTimer();
851
+ updateProgress();
852
+ timerInterval = setInterval(() => {
853
+ seconds++;
854
+ updateTimer();
855
+ updateProgress();
856
+ updateFileSize(seconds / 60);
857
+ }, 1000);
858
+
859
+ // Update UI with YouTube styling
860
+ recordBtn.disabled = true;
861
+ recordBtn.classList.remove('yt-button-primary');
862
+ recordBtn.classList.add('bg-gray-600', 'cursor-not-allowed');
863
+
864
+ stopBtn.disabled = false;
865
+ stopBtn.classList.remove('yt-button');
866
+ stopBtn.classList.add('yt-button-primary');
867
+
868
+ // Add recording animation
869
+ recordBtn.classList.add('recording-animation');
870
+
871
+ // Update mobile button if exists
872
+ if (mobileRecordBtn) {
873
+ mobileRecordBtn.classList.add('recording-animation');
874
+ }
875
+ } catch (error) {
876
+ console.error('Error accessing microphone:', error);
877
+ alert('Could not access microphone. Please check permissions.');
878
+ }
879
+ });
880
+
881
+ // Enhanced stop recording
882
+ stopBtn.addEventListener('click', function() {
883
+ if (mediaRecorder && mediaRecorder.state !== 'inactive') {
884
+ mediaRecorder.stop();
885
+
886
+ // Stop all tracks in the stream
887
+ stopStream(currentStream);
888
+
889
+ // Clear timer and progress
890
+ clearInterval(timerInterval);
891
+ progressFill.style.width = '0%';
892
+
893
+ // Update UI
894
+ recordBtn.disabled = false;
895
+ recordBtn.classList.remove('bg-gray-600', 'cursor-not-allowed');
896
+ recordBtn.classList.add('yt-button-primary');
897
+
898
+ stopBtn.disabled = true;
899
+ stopBtn.classList.remove('yt-button-primary');
900
+ stopBtn.classList.add('yt-button');
901
+
902
+ // Remove recording animation
903
+ recordBtn.classList.remove('recording-animation');
904
+
905
+ // Update mobile button if exists
906
+ if (mobileRecordBtn) {
907
+ mobileRecordBtn.classList.remove('recording-animation');
908
+ }
909
+ }
910
+ });
911
+
912
+ // Enhanced play with progress tracking
913
+ playBtn.addEventListener('click', function() {
914
+ if (audioElement) {
915
+ if (audioElement.paused) {
916
+ audioElement.play();
917
+ playBtn.innerHTML = '<i class="fas fa-pause"></i> Pause';
918
+
919
+ // Update progress as audio plays
920
+ const updatePlayProgress = setInterval(() => {
921
+ if (audioElement.paused || audioElement.ended) {
922
+ clearInterval(updatePlayProgress);
923
+ playBtn.innerHTML = '<i class="fas fa-play"></i> Preview';
924
+ progressFill.style.width = '0%';
925
+ } else {
926
+ const progress = (audioElement.currentTime / audioElement.duration) * 100;
927
+ progressFill.style.width = `${progress}%`;
928
+ }, 100);
929
+ } else {
930
+ audioElement.pause();
931
+ playBtn.innerHTML = '<i class="fas fa-play"></i> Preview';
932
+ }
933
+ }
934
+ });
935
+
936
+ // Enhanced download
937
+ downloadBtn.addEventListener('click', function() {
938
+ if (audioBlob) {
939
+ const a = document.createElement('a');
940
+ a.style.display = 'none';
941
+ a.href = audioUrl;
942
+ a.download = `recording_${new Date().toISOString().slice(0, 19).replace(/[:T-]/g, '_')}.${selectedFormat}`;
943
+ document.body.appendChild(a);
944
+ a.click();
945
+ setTimeout(() => {
946
+ document.body.removeChild(a);
947
+ }, 100);
948
+ }
949
+ });
950
+
951
+ // Share functionality
952
+ shareBtn.addEventListener('click', function() {
953
+ if (audioBlob) {
954
+ if (navigator.share) {
955
+ navigator.share({
956
+ title: 'My Recording',
957
+ text: 'Check out this recording I made!',
958
+ files: [new File([audioBlob], `recording_${new Date().toISOString().slice(0, 19).replace(/[:T-]/g, '_')}.${selectedFormat}`
959
+ }).catch(console.error);
960
+ } else {
961
+ alert('Sharing not supported in this browser. Download the file instead.');
962
+ }
963
+ }
964
+ });
965
+
966
+ // Update timer display
967
+ function updateTimer() {
968
+ const minutes = Math.floor(seconds / 60);
969
+ const remainingSeconds = seconds % 60;
970
+ timer.textContent = `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
971
+ }
972
+
973
+ // Update progress bar
974
+ function updateProgress() {
975
+ const progress = (seconds / 300) * 100; // 5 minute max
976
+ progressFill.style.width = `${Math.min(100, progress)}%`;
977
+ }
978
+ // Request permission to use microphone
979
  recordBtn.addEventListener('click', async function() {
980
  try {
981
  const constraints = getAudioConstraints();
 
1098
  const remainingSeconds = seconds % 60;
1099
  timer.textContent = `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
1100
  }
1101
+ // Enhanced recording history with YouTube cards
 
1102
  function addRecordingToList(url) {
1103
  // Remove placeholder if it exists
1104
  if (recordingsList.querySelector('.text-center')) {
 
1106
  }
1107
 
1108
  const recordingItem = document.createElement('div');
1109
+ recordingItem.className = 'recording-item p-4 flex items-center justify-between';
1110
 
1111
  recordingItem.innerHTML = `
1112
+ <div class="flex items-center gap-4">
1113
+ <div class="w-12 h-12 bg-red-500 rounded-lg flex items-center justify-center">
1114
+ <i class="fas fa-wave-square"></i>
1115
+ </div>
1116
+ <div class="flex-1">
1117
+ <p class="font-medium text-white">Recording ${recordingsList.children.length + 1}</p>
1118
+ <p class="text-sm text-gray-400">${new Date().toLocaleString()}</p>
1119
+ <p class="text-xs text-gray-500">${audioSourceSelect.options[audioSourceSelect.selectedIndex].text}</p>
1120
  </div>
1121
  </div>
1122
  <div class="flex gap-2">
1123
+ <button class="play-history-btn yt-button p-2 rounded-lg">
1124
+ <i class="fas fa-play text-xs"></i>
1125
+ </button>
1126
+ <button class="download-history-btn yt-button p-2 rounded-lg">
1127
+ <i class="fas fa-download text-xs"></i>
1128
+ </button>
1129
+ <button class="share-history-btn yt-button p-2 rounded-lg">
1130
+ <i class="fas fa-share-alt text-xs"></i>
1131
+ </button>
1132
+ </div>
1133
  </div>
1134
  `;
1135
 
 
1138
  // Add event listeners to the new buttons
1139
  const playBtn = recordingItem.querySelector('.play-history-btn');
1140
  const downloadBtn = recordingItem.querySelector('.download-history-btn');
1141
+ const shareBtn = recordingItem.querySelector('.share-history-btn');
1142
 
1143
  const audio = new Audio(url);
1144
 
 
1169
  }, 100);
1170
  });
1171
 
1172
+ shareBtn.addEventListener('click', function() {
1173
+ if (navigator.share) {
1174
+ navigator.share({
1175
+ title: `Recording ${recordingsList.children.length}`,
1176
+ text: 'Check out this recording I made with Audio Studio Pro!',
1177
+ });
1178
+ }
1179
+ });
1180
+
1181
  // Reset play button when audio ends
1182
  audio.addEventListener('ended', function() {
1183
+ playBtn.innerHTML = '<i class="fas fa-play text-xs"></i>';
1184
  });
1185
  }
1186
  });
1187
+ </script>
1188
+ <!-- Footer with credits -->
1189
+ <div class="mt-12 border-t border-[#3f3f3f] pt-6">
1190
+ <div class="flex flex-col sm:flex-row justify-between items-center text-sm text-gray-400">
1191
+ <div class="flex items-center gap-4">
1192
+ <span>Powered by</span>
1193
+ <a href="https://huggingface.co/terastudio" target="_blank" class="hover:text-white transition-colors">
1194
+ <i class="fas fa-brain mr-1"></i>
1195
+ TeraStudio AI
1196
+ </a>
1197
+ </div>
1198
+ <div class="flex items-center gap-4 mt-4 sm:mt-0">
1199
+ <span>Made with</span>
1200
+ <a href="https://enzostvs-deepsite.hf.space" target="_blank" class="hover:text-white transition-colors">
1201
+ <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);">
1202
+ DeepSite
1203
+ </a>
1204
+ <span>•</span>
1205
+ <a href="https://enzostvs-deepsite.hf.space?remix=NeoPy/audio-recorder" target="_blank" class="hover:text-white transition-colors">
1206
+ 🧬 Remix Project
1207
+ </a>
1208
+ </div>
1209
+ </div>
1210
+ </div>
1211
+ </div>
1212
+ </div>
1213
+ </div>
1214
+
1215
+ <!-- Floating Action Button for Mobile -->
1216
+ <div class="fixed bottom-6 right-6 md:hidden">
1217
+ <button id="mobileRecordBtn" class="yt-button-primary w-14 h-14 rounded-full flex items-center justify-center shadow-lg">
1218
+ <i class="fas fa-microphone"></i>
1219
+ </button>
1220
+ </div>
1221
+ </body>
1222
  </html>