Sebastiankay commited on
Commit
72fc5ff
·
1 Parent(s): c84f5fa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -89
app.py CHANGED
@@ -1,22 +1,69 @@
1
  # MARK: app.py
2
 
3
- import os
4
- import sys
5
- import json
6
- import base64
7
- import random
8
  from fastapi import FastAPI, Request, HTTPException
9
  from fastapi.responses import HTMLResponse, FileResponse, StreamingResponse
10
  from fastapi.staticfiles import StaticFiles
11
  from fastapi.templating import Jinja2Templates
12
  from fastapi.middleware.cors import CORSMiddleware
13
  from pathlib import Path
14
- from io import BytesIO
 
 
 
 
15
  from mutagen import File
 
 
16
  from PIL import Image
17
- from colorsys import rgb_to_hsv, hsv_to_rgb
18
-
19
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  app = FastAPI()
21
 
22
  app.add_middleware(
@@ -30,8 +77,7 @@ app.add_middleware(
30
  SERVER_HOST = "0.0.0.0"
31
  SERVER_PORT = 7860
32
  BASE_URL = "https://sebastiankay-my-ai-songs.hf.space/"
33
- GET_AUDIO_FILE_URL = BASE_URL + "getfile/"
34
- GET_COVERART_URL = BASE_URL + "static/coverarts/"
35
 
36
 
37
  # Serve static files from the "static" directory
@@ -43,67 +89,20 @@ templates = Jinja2Templates(directory="templates")
43
  # Configure the base directory for your music files
44
  app.mount("/files/music", StaticFiles(directory="files/music"), name="music")
45
  MUSIC_DIR = Path("files/music")
 
46
 
47
 
48
- # MARK: LUMINANCE
49
- def get_luminance(r, g, b):
50
- """returns the luminance of a color"""
51
- return 0.2126 * r + 0.7152 * g + 0.0722 * b
52
-
53
-
54
- # MARK: COMPLEMENTARY COLOR
55
- def complementary(r, g, b):
56
- """returns RGB components of complementary color"""
57
- hsv = rgb_to_hsv(r, g, b)
58
- rgb_color = hsv_to_rgb((hsv[0] + 0.5) % 1, hsv[1], hsv[2])
59
- return [round(rgb_color[0]), round(rgb_color[1]), round(rgb_color[2])]
60
-
61
 
62
- # MARK: DOMINANT COLOR
63
- def get_dominant_color_2(image_path):
64
- img = Image.open(image_path)
65
- img = img.convert("RGB")
66
- img = img.resize((100, 100), resample=0)
67
- pixels = list(img.getdata())
68
 
69
- # Erzeuge eine Liste mit den Häufigkeiten der Farben
70
- colors = []
71
- for pixel in pixels:
72
- r, g, b = pixel
73
- h, s, v = rgb_to_hsv(r / 255, g / 255, b / 255)
74
- if v > 0.5: # Filteriere hellere Farben aus
75
- continue
76
- if v > 0.99: # Filteriere Weiß aus
77
- continue
78
- colors.append((h, s, v))
79
-
80
- # Ermittle die dominante Farbe
81
- dominant_color = max(colors, key=lambda x: x[2])
82
- dominant_color_rgb = hsv_to_rgb(dominant_color[0], dominant_color[1], dominant_color[2])
83
- dominant_color_rgb = [int(c * 255) for c in dominant_color_rgb]
84
- # print(dominant_color_rgb)
85
-
86
- return dominant_color_rgb
87
-
88
-
89
- def get_dominant_color(image, palette_size=16):
90
-
91
- pil_img = Image.open(image)
92
-
93
- # Resize image to speed up processing
94
- img = pil_img.copy()
95
- img.thumbnail((100, 100))
96
-
97
- # Reduce colors (uses k-means internally)
98
- paletted = img.convert("P", palette=Image.ADAPTIVE, colors=palette_size)
99
-
100
- # Find the color that occurs most often
101
- palette = paletted.getpalette()
102
- color_counts = sorted(paletted.getcolors(), reverse=True)
103
- palette_index = color_counts[0][1]
104
- dominant_color = palette[palette_index * 3 : palette_index * 3 + 3]
105
-
106
- return dominant_color
107
 
108
 
109
  # Function to get the list of music files with metadata
@@ -116,10 +115,17 @@ def get_music_files_with_metadata():
116
  music_files = []
117
  for file in MUSIC_DIR.iterdir():
118
  if file.is_file():
119
- # Datei überspringen, wenn "_HIDETHIS" im Namen vorkommt
120
- if "_HIDETHIS" in file.name:
 
121
  continue
122
 
 
 
 
 
 
 
123
  try: # Wrap metadata extraction in try-except
124
  audio = File(file)
125
  if audio is None: # Handle cases where mutagen can't read the file
@@ -129,41 +135,38 @@ def get_music_files_with_metadata():
129
  track_number_str = audio.get("TRCK", ["0"])[0].split("/")[0]
130
  track_number = int(track_number_str) if track_number_str.isdigit() else 0
131
 
132
- # print(audio.getall("APIC", ["Unknown"])[0].data)
133
-
134
- cover_art_filename = file.name + ".png" if Path("static/coverarts/" + file.name + ".png").is_file() else f"no_coverart_{random.randint(1, 4)}.png"
135
- print("cover_art_path:", GET_COVERART_URL + cover_art_filename)
136
-
137
  metadata = {
138
  "encoded_title": base64.b64encode(file.name.encode("utf-8")).decode("utf-8"),
139
- "filename": file.name,
140
  "title": str(audio.get("TIT2", ["Unknown"])[0]),
141
  "artist": str(audio.get("TPE1", ["Unknown"])[0]),
142
  "genre": str(audio.get("TCON", ["Unknown"])[0]),
143
  "duration": int(audio.info.length) if hasattr(audio, "info") and hasattr(audio.info, "length") else 0,
144
  "track_number": track_number,
145
- "audiofile": GET_AUDIO_FILE_URL + file.name,
146
- "cover_art": file.name + ".png",
147
- "coverart": GET_COVERART_URL + cover_art_filename,
148
- "dominant_color": "128, 128, 128",
149
- "complementary_color": "128, 128, 128",
 
 
150
  }
151
 
152
  music_files.append(metadata)
153
 
154
  # --- Cover Art Processing ---
155
- cover_art_path = Path("static/coverarts") / cover_art_filename
156
-
157
  if cover_art_path.is_file():
158
  try:
159
- dominant_color = get_dominant_color(cover_art_path)
160
- complementary_color = complementary(dominant_color[0], dominant_color[1], dominant_color[2])
 
 
161
 
162
- metadata["dominant_color"] = ", ".join(map(str, dominant_color))
163
- metadata["complementary_color"] = ", ".join(map(str, complementary_color))
164
 
165
  except Exception as e:
166
- print(f"Error processing cover art {metadata['cover_art']}: {e}")
167
  else:
168
  print(f"Cover art file not found: {cover_art_path}")
169
  # --- End Cover Art Processing ---
@@ -215,6 +218,12 @@ async def get_file(filename: str):
215
  media_type = "audio/ogg"
216
  elif filename.lower().endswith(".flac"):
217
  media_type = "audio/flac"
 
 
 
 
 
 
218
 
219
  # def iterfile(): # (1)
220
  # with open(file_path, mode="rb") as file_like: # (2)
@@ -240,6 +249,12 @@ if __name__ == "__main__":
240
 
241
  # print(f"\n\nStarting server on: \nhttp://{SERVER_HOST}:{SERVER_PORT}")
242
  print()
243
- print(f"API DOCS: {BASE_URL}docs\n----------------------------------\n----------------------------------")
 
 
 
 
 
 
244
  print()
245
  uvicorn.run(app, host=SERVER_HOST, port=SERVER_PORT)
 
1
  # MARK: app.py
2
 
 
 
 
 
 
3
  from fastapi import FastAPI, Request, HTTPException
4
  from fastapi.responses import HTMLResponse, FileResponse, StreamingResponse
5
  from fastapi.staticfiles import StaticFiles
6
  from fastapi.templating import Jinja2Templates
7
  from fastapi.middleware.cors import CORSMiddleware
8
  from pathlib import Path
9
+ from dominant_color import get_luminance, complementary, get_dominant_color, _is_grayscale, _rgb_to_hsv, hsv_to_rgb, rgb_to_hsv
10
+ import subprocess
11
+ import urllib.parse
12
+ import os
13
+ import json
14
  from mutagen import File
15
+ from io import BytesIO
16
+ import base64
17
  from PIL import Image
18
+ from colorsys import rgb_to_hls, hls_to_rgb
19
+ import logging
20
+ import wave
21
+ import struct
22
+ import math
23
+ import random
24
+ import shutil
25
+
26
+ # command = "cls"
27
+ # if os.name in ("nt", "dos"): # If Machine is running on Win OS, use cls
28
+ # subprocess.call(command, shell=True)
29
+ # else: # If Machine is running on OSX/Linux
30
+ # subprocess.call(["printf", "\033c"])
31
+
32
+
33
+ no_style = "\033[0m"
34
+ bold = "\033[91m"
35
+ black = "\033[30m"
36
+ grey = "\033[90m"
37
+ white = "\033[97m"
38
+ white_bg = "\033[107m"
39
+ blue = "\033[94m"
40
+ blue_bg = "\033[104m"
41
+ green = "\033[92m"
42
+ green_bg = "\033[102m"
43
+ yellow = "\033[93m"
44
+ red = "\033[31m"
45
+ red_light = "\033[91m"
46
+ red_light_bg = "\033[101m"
47
+
48
+ global logger
49
+ logger = logging.getLogger()
50
+ handler = logging.StreamHandler()
51
+ logging.addLevelName(logging.DEBUG, grey + "DEBUG: " + no_style)
52
+ logging.addLevelName(logging.INFO, blue + "ℹ️")
53
+ logging.addLevelName(logging.WARNING, no_style + yellow + "WARNING:")
54
+ logging.addLevelName(logging.ERROR, no_style + red_light_bg + black + "ERROR: " + no_style)
55
+ logging.addLevelName(logging.CRITICAL, f"{no_style + red}CRITICAL:{no_style}")
56
+ handler.setLevel(logging.INFO) # DEBUG INFO WARNING ERROR CRITICAL
57
+ # formatter = logging.Formatter(fmt=" %(levelname)-8s %(message)s", style="%")
58
+ # formatter = logging.Formatter(fmt=" %(levelname)-8s %(message)s")
59
+ # # formatter = AnsiColorFormatter("{levelname:<8s} {message}", style="{")
60
+ formatter = logging.Formatter("{levelname:s} {message}", style="{")
61
+ handler.setFormatter(formatter)
62
+ logger.addHandler(handler)
63
+ logger.setLevel(logging.INFO) # DEBUG INFO WARNING ERROR CRITICAL
64
+
65
+
66
+ # MARK: FastAPI
67
  app = FastAPI()
68
 
69
  app.add_middleware(
 
77
  SERVER_HOST = "0.0.0.0"
78
  SERVER_PORT = 7860
79
  BASE_URL = "https://sebastiankay-my-ai-songs.hf.space/"
80
+ GET_FILE_URL = BASE_URL + "getfile/"
 
81
 
82
 
83
  # Serve static files from the "static" directory
 
89
  # Configure the base directory for your music files
90
  app.mount("/files/music", StaticFiles(directory="files/music"), name="music")
91
  MUSIC_DIR = Path("files/music")
92
+ MUSIC_DIR_2 = Path("files/music_2")
93
 
94
 
95
+ def create_peaks_json(file):
96
+ input_file = file
97
+ output_file = f"{file}.json"
98
+ command = f'audiowaveform -i "{input_file}" -o "{output_file}" -b 8'
99
+ # print("Executing command:", command)
100
+ subprocess.call(command, shell=True)
 
 
 
 
 
 
 
101
 
102
+ with open(output_file, "r") as f:
103
+ peaks = json.load(f)
 
 
 
 
104
 
105
+ return peaks["data"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
 
108
  # Function to get the list of music files with metadata
 
115
  music_files = []
116
  for file in MUSIC_DIR.iterdir():
117
  if file.is_file():
118
+
119
+ if "_HIDETHIS" in file.name or file.name.endswith(".json") or file.name.endswith(".png"):
120
+ print(f"{yellow}Ignoring File: {no_style} {file.name}")
121
  continue
122
 
123
+ filename_without_mp3 = file.name.rsplit(".", 1)[0]
124
+ filename_coverart = filename_without_mp3 + ".coverart.png"
125
+ filename_coverart_encoded = urllib.parse.quote(filename_coverart)
126
+ filename_peaks = filename_without_mp3 + ".peaks.json"
127
+ # peaks = create_peaks_json(file)
128
+
129
  try: # Wrap metadata extraction in try-except
130
  audio = File(file)
131
  if audio is None: # Handle cases where mutagen can't read the file
 
135
  track_number_str = audio.get("TRCK", ["0"])[0].split("/")[0]
136
  track_number = int(track_number_str) if track_number_str.isdigit() else 0
137
 
 
 
 
 
 
138
  metadata = {
139
  "encoded_title": base64.b64encode(file.name.encode("utf-8")).decode("utf-8"),
 
140
  "title": str(audio.get("TIT2", ["Unknown"])[0]),
141
  "artist": str(audio.get("TPE1", ["Unknown"])[0]),
142
  "genre": str(audio.get("TCON", ["Unknown"])[0]),
143
  "duration": int(audio.info.length) if hasattr(audio, "info") and hasattr(audio.info, "length") else 0,
144
  "track_number": track_number,
145
+ "audiofile": GET_FILE_URL + file.name,
146
+ "coverart": GET_FILE_URL + filename_coverart_encoded,
147
+ "dominant_color_1": "128, 128, 128",
148
+ "complementary_color_1": "128, 128, 128",
149
+ "dominant_color_2": "128, 128, 128",
150
+ "complementary_color_2": "128, 128, 128",
151
+ # "peaks": peaks,
152
  }
153
 
154
  music_files.append(metadata)
155
 
156
  # --- Cover Art Processing ---
157
+ cover_art_path = MUSIC_DIR / filename_coverart
 
158
  if cover_art_path.is_file():
159
  try:
160
+ colors = get_dominant_color(cover_art_path, min_brightness=0.4, max_brightness=0.8, n_clusters=4)
161
+
162
+ metadata["dominant_color_1"] = ", ".join(map(str, colors[0]))
163
+ metadata["complementary_color_1"] = ", ".join(map(str, colors[1]))
164
 
165
+ metadata["dominant_color_2"] = ", ".join(map(str, colors[2]))
166
+ metadata["complementary_color_2"] = ", ".join(map(str, colors[3]))
167
 
168
  except Exception as e:
169
+ print(f"{red_light}Error{no_style} processing cover art {metadata['coverart']}: {e}")
170
  else:
171
  print(f"Cover art file not found: {cover_art_path}")
172
  # --- End Cover Art Processing ---
 
218
  media_type = "audio/ogg"
219
  elif filename.lower().endswith(".flac"):
220
  media_type = "audio/flac"
221
+ elif filename.lower().endswith(".png"):
222
+ media_type = "image/png"
223
+ elif filename.lower().endswith(".jpg") or filename.lower().endswith(".jpeg"):
224
+ media_type = "image/jpeg"
225
+ elif filename.lower().endswith(".gif"):
226
+ media_type = "image/gif"
227
 
228
  # def iterfile(): # (1)
229
  # with open(file_path, mode="rb") as file_like: # (2)
 
249
 
250
  # print(f"\n\nStarting server on: \nhttp://{SERVER_HOST}:{SERVER_PORT}")
251
  print()
252
+ logger.info("=============================================================")
253
+ logger.info(" ")
254
+ logger.info(f"API DOCS: {BASE_URL}docs")
255
+ logger.info(f"ENDPOINT: {BASE_URL}api/music")
256
+ logger.info("")
257
+ logger.info("=============================================================")
258
+ print()
259
  print()
260
  uvicorn.run(app, host=SERVER_HOST, port=SERVER_PORT)