haraberget commited on
Commit
68003b2
·
verified ·
1 Parent(s): 3471bcf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -240
app.py CHANGED
@@ -1,240 +1,56 @@
1
- from flask import Flask, request, render_template_string, send_from_directory
2
- import requests, os, re, glob, uuid
3
- from mutagen.easyid3 import EasyID3
4
-
5
- app = Flask(__name__)
6
-
7
- DOWNLOAD_FOLDER = "downloads"
8
- os.makedirs(DOWNLOAD_FOLDER, exist_ok=True)
9
- MAX_FILES = 20
10
-
11
- TEMPLATE = """
12
- <!DOCTYPE html>
13
- <html>
14
- <head>
15
- <meta charset="utf-8">
16
- <title>Udio Library</title>
17
- <style>
18
- body { background:#111; color:white; padding:2rem; font-family:sans-serif; }
19
- audio { width:100%; margin-top:1rem; }
20
- canvas { border:1px solid #333; width:100%; height:200px; margin-top:1rem; }
21
- ul { list-style:none; padding:0; }
22
- li { margin:0.5rem 0; }
23
- button.play-btn { margin-right:0.5rem; }
24
- #drop-area { border:2px dashed #555; padding:1rem; margin:1rem 0; text-align:center; }
25
- footer { margin-top:3rem; padding-top:2rem; border-top:1px solid #444; }
26
- </style>
27
- </head>
28
- <body>
29
-
30
- <h1>Udio Music Library</h1>
31
-
32
- <ul id="playlist">
33
- {% for song in songs %}
34
- <li data-url="{{ song.url }}">
35
- <button class="play-btn" onclick="playSong('{{ song.url }}')">▶️</button>
36
- {{ song.title }}
37
- </li>
38
- {% endfor %}
39
- </ul>
40
-
41
- <audio id="audio" controls crossorigin="anonymous"></audio>
42
- <canvas id="vis" width="800" height="200"></canvas>
43
-
44
- <div id="drop-area">
45
- Drag & Drop MP3 files here to upload
46
- </div>
47
-
48
- <footer>
49
- <h2>Fetch new song from Udio embed or song URL</h2>
50
- <form method="POST">
51
- <input type="text" name="embed_url" placeholder="Enter song page, embed URL or iframe snippet" size="60">
52
- <button type="submit">Fetch</button>
53
- </form>
54
-
55
- <ul>
56
- {% for msg in messages %}
57
- <li>{{ msg }}</li>
58
- {% endfor %}
59
- </ul>
60
-
61
- <p style="margin-top:2rem; font-size:0.8rem;">Built with ❤️ by <a href="https://chat.openai.com" target="_blank" style="color:#ccc;">ChatGPT</a></p>
62
- </footer>
63
-
64
- <script>
65
- const audio = document.getElementById('audio');
66
- const canvas = document.getElementById('vis');
67
- const cctx = canvas.getContext('2d');
68
-
69
- const ctx = new (window.AudioContext || window.webkitAudioContext)();
70
- const src = ctx.createMediaElementSource(audio);
71
- const analyser = ctx.createAnalyser();
72
- analyser.fftSize = 256;
73
- src.connect(analyser);
74
- analyser.connect(ctx.destination);
75
-
76
- const bufferLength = analyser.frequencyBinCount;
77
- const dataArray = new Uint8Array(bufferLength);
78
-
79
- function draw() {
80
- requestAnimationFrame(draw);
81
- analyser.getByteFrequencyData(dataArray);
82
-
83
- cctx.fillStyle = "#000";
84
- cctx.fillRect(0, 0, canvas.width, canvas.height);
85
-
86
- const barWidth = (canvas.width / bufferLength) * 2.5;
87
- let x = 0;
88
- for (let i = 0; i < bufferLength; i++) {
89
- const barHeight = dataArray[i];
90
- cctx.fillStyle = `rgb(${barHeight+100},50,50)`;
91
- cctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
92
- x += barWidth + 1;
93
- }
94
- }
95
-
96
- draw();
97
- audio.addEventListener('play', async () => await ctx.resume());
98
-
99
- let playlist = Array.from(document.querySelectorAll("#playlist li")).map(li => li.dataset.url);
100
- let currentIndex = 0;
101
-
102
- function playSong(url) {
103
- audio.src = url;
104
- audio.play();
105
- currentIndex = playlist.indexOf(url);
106
- }
107
-
108
- audio.addEventListener("ended", () => {
109
- currentIndex++;
110
- if (currentIndex >= playlist.length) currentIndex = 0;
111
- playSong(playlist[currentIndex]);
112
- });
113
-
114
- // Drag & Drop Upload
115
- let dropArea = document.getElementById('drop-area');
116
-
117
- dropArea.addEventListener('dragover', (e) => { e.preventDefault(); dropArea.style.borderColor = '#fff'; });
118
- dropArea.addEventListener('dragleave', (e) => { dropArea.style.borderColor = '#555'; });
119
- dropArea.addEventListener('drop', async (e) => {
120
- e.preventDefault();
121
- dropArea.style.borderColor = '#555';
122
- const files = e.dataTransfer.files;
123
- for(let file of files){
124
- if(file.type === "audio/mpeg"){
125
- let formData = new FormData();
126
- formData.append('file', file);
127
- await fetch('/upload', { method:'POST', body: formData });
128
- location.reload();
129
- }
130
- }
131
- });
132
- </script>
133
-
134
- </body>
135
- </html>
136
- """
137
-
138
- def normalize_udio_input(input_text):
139
- """Accept song page URL, embed URL, or iframe snippet, return embed URL"""
140
- match = re.search(r'src=["\'](https://www\.udio\.com/embed/[^"\']+)["\']', input_text)
141
- if match:
142
- return match.group(1)
143
- if input_text.startswith("https://www.udio.com/embed/"):
144
- return input_text.split()[0]
145
- song_match = re.search(r'https://www\.udio\.com/songs/([A-Za-z0-9]+)', input_text)
146
- if song_match:
147
- song_id = song_match.group(1)
148
- return f"https://www.udio.com/embed/{song_id}"
149
- return None
150
-
151
- def get_mp3_from_embed(embed_url):
152
- messages = []
153
- mp3_url = ""
154
- messages.append(f"Fetching embed page: {embed_url}")
155
- try:
156
- r = requests.get(embed_url)
157
- html = r.text
158
- mp3_match = re.search(r'https://storage\.googleapis\.com/.*?\.mp3', html)
159
- if mp3_match:
160
- mp3_url = mp3_match.group(0)
161
- messages.append(f"Found MP3 URL: {mp3_url}")
162
- else:
163
- messages.append("MP3 URL not found in embed page.")
164
- except Exception as e:
165
- messages.append(f"Error fetching embed page: {e}")
166
- return messages, mp3_url
167
-
168
- def download_mp3(mp3_url):
169
- ext = ".mp3"
170
- unique_name = f"{uuid.uuid4()}{ext}"
171
- local_path = os.path.join(DOWNLOAD_FOLDER, unique_name)
172
- try:
173
- r = requests.get(mp3_url)
174
- with open(local_path, "wb") as f:
175
- f.write(r.content)
176
- except Exception:
177
- return None
178
- return f"/downloads/{unique_name}"
179
-
180
- def list_songs():
181
- songs = []
182
- for f in sorted(os.listdir(DOWNLOAD_FOLDER)):
183
- if f.lower().endswith(".mp3"):
184
- path = os.path.join(DOWNLOAD_FOLDER, f)
185
- title = f
186
- try:
187
- audio = EasyID3(path)
188
- if 'title' in audio:
189
- title = audio['title'][0]
190
- except:
191
- pass
192
- songs.append({"title": title, "url": f"/downloads/{f}"})
193
- return songs
194
-
195
- def cleanup_old_files():
196
- files = sorted(glob.glob(os.path.join(DOWNLOAD_FOLDER, "*.mp3")), key=os.path.getmtime)
197
- while len(files) > MAX_FILES:
198
- os.remove(files[0])
199
- files.pop(0)
200
-
201
- @app.route("/", methods=["GET", "POST"])
202
- def index():
203
- messages = []
204
- if request.method == "POST":
205
- user_input = request.form.get("embed_url")
206
- if user_input:
207
- embed_url = normalize_udio_input(user_input)
208
- if embed_url:
209
- msg, mp3_url = get_mp3_from_embed(embed_url)
210
- messages.extend(msg)
211
- if mp3_url:
212
- download_mp3(mp3_url)
213
- messages.append("Downloaded new MP3.")
214
- cleanup_old_files()
215
- else:
216
- messages.append("Could not extract embed URL from input.")
217
- songs = list_songs()
218
- return render_template_string(TEMPLATE, messages=messages, songs=songs)
219
-
220
- @app.route("/uploads/<filename>")
221
- def serve_file(filename):
222
- return send_from_directory(DOWNLOAD_FOLDER, filename)
223
-
224
- @app.route("/upload", methods=["POST"])
225
- def upload_file():
226
- file = request.files.get("file")
227
- if file and file.filename.endswith(".mp3"):
228
- ext = ".mp3"
229
- unique_name = f"{uuid.uuid4()}{ext}"
230
- file.save(os.path.join(DOWNLOAD_FOLDER, unique_name))
231
- cleanup_old_files()
232
- return "", 204
233
-
234
- @app.route("/downloads/<filename>")
235
- def serve_download(filename):
236
- return send_from_directory(DOWNLOAD_FOLDER, filename)
237
-
238
- if __name__ == "__main__":
239
- app.run(debug=True)
240
-
 
1
+ # app.py
2
+ import re, requests, uuid, os
3
+ import gradio as gr
4
+
5
+ def normalize_udio_input(input_text):
6
+ """Accept song page URL, embed URL, or iframe snippet, return embed URL"""
7
+ match = re.search(r'src=["\'](https://www\.udio\.com/embed/[^"\']+)["\']', input_text)
8
+ if match:
9
+ return match.group(1)
10
+ if input_text.startswith("https://www.udio.com/embed/"):
11
+ return input_text.split()[0]
12
+ song_match = re.search(r'https://www\.udio\.com/songs/([A-Za-z0-9]+)', input_text)
13
+ if song_match:
14
+ song_id = song_match.group(1)
15
+ return f"https://www.udio.com/embed/{song_id}"
16
+ return None
17
+
18
+ def get_mp3(embed_url):
19
+ if not embed_url:
20
+ return "Invalid input", None, None
21
+
22
+ try:
23
+ r = requests.get(embed_url)
24
+ html = r.text
25
+ mp3_match = re.search(r'https://storage\.googleapis\.com/.*?\.mp3', html)
26
+ if mp3_match:
27
+ mp3_url = mp3_match.group(0)
28
+ return (
29
+ f"✅ Found MP3: {mp3_url}",
30
+ embed_url,
31
+ mp3_url
32
+ )
33
+ else:
34
+ return "⚠️ MP3 link not found in embed page.", embed_url, None
35
+ except Exception as e:
36
+ return f"❌ Error fetching embed: {e}", embed_url, None
37
+
38
+ def process_input(user_input):
39
+ embed_url = normalize_udio_input(user_input)
40
+ msg, embed, mp3 = get_mp3(embed_url)
41
+ return msg, embed, mp3
42
+
43
+ demo = gr.Interface(
44
+ fn=process_input,
45
+ inputs=gr.Textbox(label="Udio Song / Embed / Snippet", placeholder="Paste Udio URL or embed iframe here"),
46
+ outputs=[
47
+ gr.Textbox(label="Status / Message"),
48
+ gr.HTML(label="Embed Preview"),
49
+ gr.HTML(label="MP3 Download Link")
50
+ ],
51
+ title="🎵 Udio Fetcher",
52
+ description="Paste any Udio song link or embed code and get the playable embed + direct MP3 download link."
53
+ )
54
+
55
+ if __name__ == "__main__":
56
+ demo.launch()