ssiisnsksksnsjsksk commited on
Commit
7fbfbee
·
verified ·
1 Parent(s): 975356d

Upload index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +229 -0
templates/index.html ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>YT Audio</title>
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
10
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
11
+ </head>
12
+ <body class="bg-[#fafafa] dark:bg-gray-900 min-h-screen flex items-center justify-center p-4">
13
+ <div class="w-full max-w-xl mx-auto">
14
+ <!-- Ultra Modern Header -->
15
+ <div class="text-center mb-10 space-y-3">
16
+ <div class="inline-flex items-center justify-center p-2 rounded-full bg-red-50 dark:bg-red-900/20 mb-4">
17
+ <i class="fab fa-youtube text-red-500 text-3xl"></i>
18
+ </div>
19
+ <h1 class="text-3xl font-bold bg-gradient-to-r from-gray-900 to-gray-700 dark:from-white dark:to-gray-300 bg-clip-text text-transparent">
20
+ YouTube Listen to audio
21
+ </h1>
22
+ <p class="text-gray-500 dark:text-gray-400 text-sm">Simple • Fast • High Quality • No ads</p>
23
+ </div>
24
+
25
+ <!-- Main Card -->
26
+ <div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg shadow-black/5 p-6 mb-6">
27
+ <!-- Search Input -->
28
+ <div class="relative mb-6 group">
29
+ <input type="text" id="youtubeUrl"
30
+ placeholder="Paste YouTube URL here"
31
+ class="w-full pl-12 pr-4 py-4 bg-gray-50 dark:bg-gray-900/50 border-0 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500/50 transition-all duration-300 text-gray-700 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-500">
32
+ <div class="absolute inset-y-0 left-4 flex items-center pointer-events-none transition-transform group-focus-within:scale-110">
33
+ <i class="fas fa-link text-gray-400 group-focus-within:text-blue-500 transition-colors"></i>
34
+ </div>
35
+ </div>
36
+
37
+ <!-- Search Button -->
38
+ <button onclick="getVideoInfo()"
39
+ class="w-full bg-blue-500 hover:bg-blue-600 active:bg-blue-700 text-white py-4 px-6 rounded-xl transition-all duration-300 flex items-center justify-center space-x-2 font-medium focus:outline-none focus:ring-2 focus:ring-blue-500/50 focus:ring-offset-2 dark:ring-offset-gray-800">
40
+ <i class="fas fa-search text-sm"></i>
41
+ <span>Get Video Info</span>
42
+ </button>
43
+ </div>
44
+
45
+ <!-- Video Info Card -->
46
+ <div id="videoInfo" class="hidden animate-fade-in">
47
+ <div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg shadow-black/5 overflow-hidden mb-6">
48
+ <!-- Thumbnail Container with Gradient Overlay -->
49
+ <div id="thumbnailContainer" class="relative">
50
+ <div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent z-10"></div>
51
+ </div>
52
+
53
+ <!-- Video Details -->
54
+ <div class="p-6 space-y-4">
55
+ <h2 id="videoTitle" class="text-xl font-semibold text-gray-800 dark:text-white line-clamp-2"></h2>
56
+
57
+ <div class="space-y-2">
58
+ <div id="channelName" class="flex items-center text-sm text-gray-500 dark:text-gray-400">
59
+ <i class="fas fa-user-circle mr-2 text-blue-500"></i>
60
+ <span></span>
61
+ </div>
62
+ <div id="duration" class="flex items-center text-sm text-gray-500 dark:text-gray-400">
63
+ <i class="fas fa-clock mr-2 text-blue-500"></i>
64
+ <span></span>
65
+ </div>
66
+ </div>
67
+
68
+ <!-- Play Audio Button -->
69
+ <button onclick="playAudio()"
70
+ class="w-full bg-green-500 hover:bg-green-600 active:bg-green-700 text-white py-4 px-6 rounded-xl transition-all duration-300 flex items-center justify-center space-x-2 font-medium focus:outline-none focus:ring-2 focus:ring-green-500/50 focus:ring-offset-2 dark:ring-offset-gray-800 mt-4">
71
+ <i class="fas fa-play text-sm"></i>
72
+ <span>Start Listening</span>
73
+ </button>
74
+ </div>
75
+ </div>
76
+ </div>
77
+ </div>
78
+
79
+ <script>
80
+ const Toast = Swal.mixin({
81
+ toast: true,
82
+ position: 'top-end',
83
+ showConfirmButton: false,
84
+ timer: 3000,
85
+ timerProgressBar: true,
86
+ didOpen: (toast) => {
87
+ toast.addEventListener('mouseenter', Swal.stopTimer)
88
+ toast.addEventListener('mouseleave', Swal.resumeTimer)
89
+ }
90
+ });
91
+
92
+ function showLoading(message) {
93
+ return Swal.fire({
94
+ html: `
95
+ <div class="space-y-3">
96
+ <div class="w-16 h-16 mx-auto border-4 border-gray-200 border-t-blue-500 rounded-full animate-spin"></div>
97
+ <div class="text-gray-600 text-sm">${message}</div>
98
+ </div>
99
+ `,
100
+ showConfirmButton: false,
101
+ allowOutsideClick: false,
102
+ background: '#ffffff',
103
+ customClass: {
104
+ popup: 'rounded-2xl'
105
+ }
106
+ });
107
+ }
108
+
109
+ function showSuccess(message) {
110
+ Toast.fire({
111
+ icon: 'success',
112
+ title: message,
113
+ background: '#F0FDF4',
114
+ iconColor: '#22C55E'
115
+ });
116
+ }
117
+
118
+ function showError(message) {
119
+ Toast.fire({
120
+ icon: 'error',
121
+ title: message,
122
+ background: '#FEF2F2',
123
+ iconColor: '#EF4444'
124
+ });
125
+ }
126
+
127
+ function formatDuration(seconds) {
128
+ const minutes = Math.floor(seconds / 60);
129
+ const remainingSeconds = seconds % 60;
130
+ return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
131
+ }
132
+
133
+ function getVideoInfo() {
134
+ const url = $('#youtubeUrl').val().trim();
135
+ if (!url) {
136
+ showError('Please enter a YouTube URL');
137
+ return;
138
+ }
139
+
140
+ showLoading('Fetching video information...');
141
+ $('#videoInfo').addClass('hidden');
142
+
143
+ $.ajax({
144
+ url: '/get-info',
145
+ type: 'POST',
146
+ contentType: 'application/json',
147
+ data: JSON.stringify({ url: url }),
148
+ success: function(response) {
149
+ $('#thumbnailContainer').html(`
150
+ <img src="${response.thumbnail}" alt="Video Thumbnail"
151
+ class="w-full object-cover transition-transform duration-300 hover:scale-105">
152
+ `);
153
+ $('#videoTitle').text(response.title);
154
+ $('#channelName span').text(response.channel);
155
+ $('#duration span').text(formatDuration(response.duration));
156
+ $('#videoInfo').removeClass('hidden');
157
+ Swal.close();
158
+ showSuccess('Video information retrieved');
159
+ },
160
+ error: function(xhr) {
161
+ Swal.close();
162
+ showError(xhr.responseJSON?.error || 'Failed to get video information');
163
+ }
164
+ });
165
+ }
166
+
167
+ function playAudio() {
168
+ const url = $('#youtubeUrl').val().trim();
169
+ if (!url) {
170
+ showError('Please enter a YouTube URL');
171
+ return;
172
+ }
173
+
174
+ showLoading('Preparing audio...');
175
+
176
+ $.ajax({
177
+ url: '/download',
178
+ type: 'POST',
179
+ contentType: 'application/json',
180
+ data: JSON.stringify({ url: url }),
181
+ xhrFields: {
182
+ responseType: 'blob'
183
+ },
184
+ success: function(response) {
185
+ const blob = new Blob([response], { type: 'audio/mp3' });
186
+ const audioUrl = URL.createObjectURL(blob);
187
+
188
+ const videoInfoContainer = document.querySelector('#videoInfo .p-6');
189
+ // Remove any existing audio players
190
+ const existingAudioPlayers = videoInfoContainer.querySelectorAll('audio');
191
+ existingAudioPlayers.forEach(player => player.remove());
192
+
193
+ const audioPlayer = document.createElement('audio');
194
+ audioPlayer.src = audioUrl;
195
+ audioPlayer.controls = true;
196
+ audioPlayer.style.width = '100%';
197
+ audioPlayer.style.marginTop = '1rem';
198
+ audioPlayer.autoplay = true;
199
+
200
+ videoInfoContainer.appendChild(audioPlayer);
201
+
202
+ Swal.close();
203
+ showSuccess('Audio is ready to play');
204
+ },
205
+ error: function(xhr) {
206
+ Swal.close();
207
+ showError('Failed to prepare audio');
208
+ }
209
+ });
210
+ }
211
+
212
+ // Smooth page load animation
213
+ document.addEventListener('DOMContentLoaded', () => {
214
+ requestAnimationFrame(() => {
215
+ document.body.style.opacity = '0';
216
+ requestAnimationFrame(() => {
217
+ document.body.style.transition = 'opacity 0.5s ease-in';
218
+ document.body.style.opacity = '1';
219
+ });
220
+ });
221
+ });
222
+
223
+ // Check system dark mode preference
224
+ if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
225
+ document.documentElement.classList.add('dark');
226
+ }
227
+ </script>
228
+ </body>
229
+ </html>