Skip to content

Commit 475e57a

Browse files
authored
Add files via upload
1 parent 75025a5 commit 475e57a

File tree

2 files changed

+187
-0
lines changed

2 files changed

+187
-0
lines changed

MP3-Metadata-Editor.py

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# music_metadata_editor.py
2+
# A simple dark mode popup app to edit MP3 metadata
3+
# Requirements: pip install mutagen customtkinter
4+
5+
import customtkinter as ctk
6+
from tkinter import filedialog, messagebox
7+
from mutagen.easyid3 import EasyID3
8+
from mutagen.mp3 import MP3
9+
import os
10+
11+
ctk.set_appearance_mode("dark")
12+
ctk.set_default_color_theme("dark-blue")
13+
14+
class MetadataEditor(ctk.CTk):
15+
def __init__(self):
16+
super().__init__()
17+
self.title("MP3 Metadata Editor")
18+
self.geometry("600x390") # Slightly reduced window height for a more compact appearance
19+
self.resizable(False, False)
20+
self.file_path = None
21+
22+
self.label = ctk.CTkLabel(self, text="Select an MP3 file to edit metadata:")
23+
self.label.pack(pady=6)
24+
25+
self.select_btn = ctk.CTkButton(self, text="Upload MP3", command=self.browse_file)
26+
self.select_btn.pack(pady=5)
27+
28+
# File name field under Upload MP3, above the title
29+
filename_frame = ctk.CTkFrame(self)
30+
filename_frame.pack(pady=(6, 2), fill="x", padx=20)
31+
filename_label = ctk.CTkLabel(filename_frame, text="File Name", width=100)
32+
filename_label.pack(side="left")
33+
self.filename_var = ctk.StringVar()
34+
self.filename_entry = ctk.CTkEntry(filename_frame, textvariable=self.filename_var, state="readonly", width=450)
35+
self.filename_entry.pack(side="left", padx=5, fill="x", expand=True)
36+
37+
self.fields = {}
38+
for field in ["title", "artist", "album", "genre", "date"]:
39+
frame = ctk.CTkFrame(self)
40+
frame.pack(pady=3, fill="x", padx=20)
41+
lbl = ctk.CTkLabel(frame, text=field.capitalize(), width=100)
42+
lbl.pack(side="left")
43+
entry = ctk.CTkEntry(frame, width=450)
44+
entry.pack(side="left", padx=5, fill="x", expand=True)
45+
self.fields[field] = entry
46+
47+
# Album cover buttons in a horizontal frame
48+
cover_frame = ctk.CTkFrame(self, fg_color="transparent") # Remove black background
49+
cover_frame.pack(pady=(8, 2), fill="x", padx=20)
50+
cover_frame.grid_columnconfigure(0, weight=1)
51+
cover_frame.grid_columnconfigure(1, weight=0)
52+
cover_frame.grid_columnconfigure(2, weight=1)
53+
# Add an empty label to the left for centering
54+
left_spacer = ctk.CTkLabel(cover_frame, text="", width=1)
55+
left_spacer.grid(row=0, column=0, sticky="ew")
56+
self.cover_btn = ctk.CTkButton(cover_frame, text="Change Song Cover", command=self.change_cover, state="disabled", width=180)
57+
self.cover_btn.grid(row=0, column=1, sticky="ew", padx=(0, 8))
58+
self.view_cover_btn = ctk.CTkButton(cover_frame, text="View", command=self.view_cover, state="disabled", width=60, height=28)
59+
self.view_cover_btn.grid(row=0, column=2, sticky="w")
60+
self.save_btn = ctk.CTkButton(self, text="Save Metadata", command=self.save_metadata, state="disabled")
61+
self.save_btn.pack(pady=15)
62+
63+
def browse_file(self):
64+
path = filedialog.askopenfilename(filetypes=[("MP3 Files", "*.mp3")])
65+
if path:
66+
self.file_path = path
67+
self.filename_var.set(os.path.basename(path))
68+
self.load_metadata()
69+
self.save_btn.configure(state="normal")
70+
self.cover_btn.configure(state="normal")
71+
self.view_cover_btn.configure(state="normal")
72+
73+
def load_metadata(self):
74+
try:
75+
audio = MP3(self.file_path, ID3=EasyID3)
76+
for field in self.fields:
77+
value = audio.tags.get(field, [""])[0] if audio.tags and field in audio.tags else ""
78+
self.fields[field].delete(0, "end")
79+
self.fields[field].insert(0, value)
80+
except Exception as e:
81+
messagebox.showerror("Error", f"Failed to load metadata: {e}")
82+
83+
def save_metadata(self):
84+
try:
85+
audio = MP3(self.file_path, ID3=EasyID3)
86+
for field, entry in self.fields.items():
87+
val = entry.get().strip()
88+
if val:
89+
audio.tags[field] = val
90+
elif field in audio.tags:
91+
del audio.tags[field]
92+
audio.save()
93+
messagebox.showinfo("Success", "Metadata updated successfully!")
94+
except Exception as e:
95+
messagebox.showerror("Error", f"Failed to save metadata: {e}")
96+
97+
def change_cover(self):
98+
from mutagen.id3 import ID3, APIC, error
99+
img_path = filedialog.askopenfilename(filetypes=[("Image Files", "*.jpg;*.jpeg;*.png")])
100+
if not img_path or not self.file_path:
101+
return
102+
try:
103+
audio = MP3(self.file_path, ID3=ID3)
104+
with open(img_path, 'rb') as img:
105+
img_data = img.read()
106+
# Remove old cover(s)
107+
audio.tags.delall('APIC')
108+
# Add new cover
109+
audio.tags.add(
110+
APIC(
111+
encoding=3,
112+
mime='image/jpeg' if img_path.lower().endswith(('jpg', 'jpeg')) else 'image/png',
113+
type=3, desc=u'Cover', data=img_data
114+
)
115+
)
116+
audio.save()
117+
messagebox.showinfo("Success", "Cover image updated!")
118+
except Exception as e:
119+
messagebox.showerror("Error", f"Failed to update cover: {e}")
120+
121+
def view_cover(self):
122+
from mutagen.id3 import ID3
123+
import tempfile
124+
import webbrowser
125+
if not self.file_path:
126+
return
127+
try:
128+
audio = MP3(self.file_path, ID3=ID3)
129+
apic = None
130+
for tag in audio.tags.values():
131+
if tag.FrameID == 'APIC':
132+
apic = tag
133+
break
134+
if apic:
135+
ext = '.jpg' if apic.mime == 'image/jpeg' else '.png'
136+
with tempfile.NamedTemporaryFile(delete=False, suffix=ext) as tmp:
137+
tmp.write(apic.data)
138+
tmp_path = tmp.name
139+
webbrowser.open(tmp_path)
140+
else:
141+
messagebox.showinfo("No Cover", "No cover image found in this MP3.")
142+
except Exception as e:
143+
messagebox.showerror("Error", f"Failed to view cover: {e}")
144+
145+
if __name__ == "__main__":
146+
app = MetadataEditor()
147+
app.mainloop()

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# MP3 Metadata Editor 🎵
2+
3+
A simple dark mode popup app to edit MP3 metadata and album cover art.
4+
5+
## ✨ Features
6+
- Edit MP3 metadata: Title, Artist, Album, Genre, Date
7+
- View and change the album cover image 🖼️
8+
- Modern dark mode UI 🌙
9+
10+
## 🚀 How to Use
11+
1. **Run the App**
12+
- Double-click `music_metadata_editor.exe` in the `dist` folder.
13+
2. **Upload an MP3**
14+
- Click `Upload MP3` and select your file.
15+
3. **Edit Metadata**
16+
- Change any of the fields (Title, Artist, Album, Genre, Date).
17+
- Click `Save Metadata` to apply changes.
18+
4. **Change/View Album Cover**
19+
- Click `Change Song Cover` to select a new image (JPG/PNG).
20+
- Click `View` to preview the current cover art.
21+
22+
## 🛠️ Build from Source
23+
1. Install requirements:
24+
```sh
25+
pip install -r requirements.txt
26+
```
27+
2. Build the executable:
28+
```sh
29+
pyinstaller --onefile --noconsole music_metadata_editor.py
30+
```
31+
The `.exe` will be in the `dist` folder.
32+
33+
## 📦 Requirements (for source build)
34+
- Python 3.8+
35+
- mutagen
36+
- customtkinter
37+
- pyinstaller (for building the exe)
38+
39+
## 📄 License
40+
MIT

0 commit comments

Comments
 (0)