SHARE
    TWEET
    Najeebsk

    MP3-LIVE.pyw

    May 2nd, 2025
    154
    0
    Never
    Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
    Python 22.25 KB | None | 0 0
    1. import os
    2. import sqlite3
    3. import tempfile
    4. from tkinter import *
    5. from tkinter import filedialog, messagebox, ttk
    6. import vlc
    7. from PIL import Image, ImageTk, ImageSequence
    8. import sys
    9. import configparser
    10. import hashlib
    11. import base64
    12. #================ADD-IMAGE-ICON=================
    13. import sys
    14. def resource_path(relative_path):
    15. """ Get the absolute path to the resource, works for PyInstaller. """
    16. if getattr(sys, '_MEIPASS', False):
    17. return os.path.join(sys._MEIPASS, relative_path)
    18. return os.path.join(os.path.abspath("."), relative_path)
    19. # Use this function to load files:
    20. #splash_image = resource_path("splash-1.png")
    21. icon_path = resource_path("M.ico")
    22. #-------------------------------------------
    23. def resource_path(relative_path):
    24. """ Get absolute path to resource, works for dev and for PyInstaller """
    25. try:
    26. # PyInstaller creates a temp folder and stores path in _MEIPASS
    27. base_path = sys._MEIPASS
    28. except Exception:
    29. base_path = os.path.abspath(".")
    30. return os.path.join(base_path, relative_path)
    31. #================ADD-IMAGE-ICON=================
    32. class Mp3PlayerApp:
    33. def __init__(self, root):
    34. self.root = root
    35. self.root.title("Najeeb Advanced MP3 Player")
    36. self.root.geometry("1200x700")
    37. self.root.config(bg="#f0f0f0")
    38. #self.root.configure(bg="#2c3e50")
    39. self.root.iconbitmap(icon_path)
    40. # Initialize VLC
    41. self.vlc_instance = vlc.Instance()
    42. self.media_player = self.vlc_instance.media_player_new()
    43. # Security
    44. self.secure_mode = False
    45. self.password_hash = self.load_password_hash()
    46. # DB Setup
    47. self.db_path = "M-DATA.db"
    48. self.connect_database()
    49. # Stream data
    50. self.streams = {}
    51. self.current_streams = {}
    52. # Temp files list
    53. self.temp_files = []
    54. # UI Setup
    55. self.setup_theme()
    56. self.create_menu()
    57. self.create_notebook()
    58. self.create_media_controls()
    59. self.create_status_bar()
    60. self.load_gif("MP3.gif")
    61. self.load_mp3s_from_database()
    62. def setup_theme(self):
    63. style = ttk.Style()
    64. style.theme_use('clam')
    65. style.configure("TButton", padding=6, relief="flat", background="#4CAF50")
    66. style.configure("TFrame", background="#f0f0f0")
    67. style.configure("Treeview", background="#ffffff", fieldbackground="#f0f0f0")
    68. style.configure("TNotebook.Tab", padding=[10, 5], background="#e0e0e0")
    69. self.root.option_add("*Font", "Helvetica 10")
    70. self.root.option_add("*Background", "#f0f0f0")
    71. self.root.option_add("*Button.Background", "#4CAF50")
    72. self.root.option_add("*Button.Foreground", "white")
    73. def create_menu(self):
    74. menubar = Menu(self.root)
    75. filemenu = Menu(menubar, tearoff=0)
    76. filemenu.add_command(label="Open MP3 Database", command=self.select_database)
    77. filemenu.add_command(label="Open Streams File", command=self.select_streams_file)
    78. filemenu.add_separator()
    79. filemenu.add_command(label="Exit", command=self.root.quit)
    80. menubar.add_cascade(label="File", menu=filemenu)
    81. securitymenu = Menu(menubar, tearoff=0)
    82. securitymenu.add_command(label="Set Password", command=self.set_password)
    83. securitymenu.add_command(label="Lock Application", command=self.lock_application)
    84. securitymenu.add_checkbutton(label="Secure Mode", variable=IntVar(value=1), command=self.toggle_secure_mode)
    85. menubar.add_cascade(label="Security", menu=securitymenu)
    86. self.root.config(menu=menubar)
    87. def create_notebook(self):
    88. self.notebook = ttk.Notebook(self.root)
    89. self.notebook.pack(fill=BOTH, expand=True, padx=10, pady=10)
    90. # Music Tab
    91. music_tab = ttk.Frame(self.notebook)
    92. self.notebook.add(music_tab, text='Music Library')
    93. self.create_music_ui(music_tab)
    94. # Radio Tab
    95. radio_tab = ttk.Frame(self.notebook)
    96. self.notebook.add(radio_tab, text='Live Radio')
    97. self.create_radio_ui(radio_tab)
    98. # Settings Tab
    99. settings_tab = ttk.Frame(self.notebook)
    100. self.notebook.add(settings_tab, text='Settings')
    101. self.create_settings_ui(settings_tab)
    102. def create_music_ui(self, parent):
    103. main_frame = ttk.Frame(parent)
    104. main_frame.pack(fill=BOTH, expand=True, padx=10, pady=10)
    105. button_frame = ttk.Frame(main_frame)
    106. button_frame.pack(fill=X, pady=5)
    107. Button(button_frame, text="Browse Folder", command=self.browse_folder).pack(side=LEFT, padx=5)
    108. Button(button_frame, text="Add MP3", command=self.add_mp3_file).pack(side=LEFT, padx=5)
    109. Button(button_frame, text="Delete MP3", command=self.delete_mp3_file).pack(side=LEFT, padx=5)
    110. Button(button_frame, text="Save MP3", command=self.save_mp3_to_database).pack(side=LEFT, padx=5)
    111. Button(button_frame, text="Delete Temp", command=self.delete_temp_files).pack(side=LEFT, padx=5)
    112. list_frame = ttk.Frame(main_frame)
    113. list_frame.pack(fill=BOTH, expand=True)
    114. self.listbox = Listbox(list_frame, width=50, height=10)
    115. self.listbox.pack(side=LEFT, fill=BOTH, expand=True)
    116. self.listbox.bind("<<ListboxSelect>>", self.play_selected_song)
    117. scrollbar = Scrollbar(list_frame)
    118. scrollbar.pack(side=RIGHT, fill=Y)
    119. self.listbox.config(yscrollcommand=scrollbar.set)
    120. scrollbar.config(command=self.listbox.yview)
    121. def create_radio_ui(self, parent):
    122. radio_frame = ttk.Frame(parent)
    123. radio_frame.pack(fill=BOTH, expand=True, padx=10, pady=10)
    124. Label(radio_frame, text="Select Category:", font=("Helvetica", 10, "bold")).pack(anchor=W, pady=5)
    125. self.category_var = StringVar()
    126. self.category_combo = ttk.Combobox(radio_frame, textvariable=self.category_var, state="readonly", width=30)
    127. self.category_combo.pack(pady=5)
    128. self.category_combo.bind("<<ComboboxSelected>>", self.update_stations)
    129. Label(radio_frame, text="Select Station:", font=("Helvetica", 10, "bold")).pack(anchor=W, pady=5)
    130. self.station_list = Listbox(radio_frame, width=50, height=10)
    131. self.station_list.pack(fill=BOTH, expand=True)
    132. self.station_list.bind("<Double-1>", self.play_selected_station)
    133. self.stream_info = Label(radio_frame, text="Double-click a station to play", fg="blue", cursor="hand2")
    134. self.stream_info.pack(pady=5)
    135. self.stream_info.bind("<Button-1>", lambda e: self.open_stream_url())
    136. def create_settings_ui(self, parent):
    137. settings_frame = ttk.Frame(parent)
    138. settings_frame.pack(fill=BOTH, expand=True, padx=10, pady=10)
    139. Label(settings_frame, text="Security Settings", font=("Helvetica", 12, "bold")).pack(anchor=W, pady=5)
    140. self.secure_mode_var = IntVar(value=1)
    141. Checkbutton(settings_frame, text="Enable Secure Mode", variable=self.secure_mode_var, command=self.toggle_secure_mode).pack(anchor=W)
    142. Button(settings_frame, text="Set Password", command=self.set_password).pack(anchor=W, pady=5)
    143. Button(settings_frame, text="Lock Application", command=self.lock_application).pack(anchor=W)
    144. Label(settings_frame, text="About", font=("Helvetica", 12, "bold")).pack(anchor=W, pady=5)
    145. Label(settings_frame, text="MP3 Player v3.0\nDeveloped by Najeeb Shah Khan").pack(anchor=W)
    146. def create_media_controls(self):
    147. control_frame = ttk.Frame(self.root)
    148. control_frame.pack(fill=X, padx=10, pady=10)
    149. Button(control_frame, text="Play", command=self.play_selected_song).pack(side=LEFT, padx=5)
    150. Button(control_frame, text="Stop", command=self.stop_song).pack(side=LEFT, padx=5)
    151. Button(control_frame, text="Previous", command=self.play_previous).pack(side=LEFT, padx=5)
    152. Button(control_frame, text="Next", command=self.play_next).pack(side=LEFT, padx=5)
    153. self.position_slider = Scale(control_frame, from_=0, to=100, orient=HORIZONTAL, length=300, command=self.seek_position)
    154. self.position_slider.pack(side=LEFT, padx=10)
    155. Label(control_frame, text="Volume").pack(side=LEFT)
    156. self.volume_slider = Scale(control_frame, from_=0, to=100, orient=HORIZONTAL, length=100, command=self.set_volume)
    157. self.volume_slider.set(50)
    158. self.volume_slider.pack(side=LEFT, padx=10)
    159. def create_status_bar(self):
    160. self.status_bar = Label(self.root, text="Ready", bd=1, relief=SUNKEN, anchor=W)
    161. self.status_bar.pack(side=BOTTOM, fill=X)
    162. def connect_database(self):
    163. try:
    164. self.db_connection = sqlite3.connect(self.db_path)
    165. self.cursor = self.db_connection.cursor()
    166. self.cursor.execute('''CREATE TABLE IF NOT EXISTS mp3_files
    167. (id INTEGER PRIMARY KEY, filename TEXT, filedata BLOB)''')
    168. self.db_connection.commit()
    169. except Exception as e:
    170. messagebox.showerror("Database Error", f"Failed to connect to database: {e}")
    171. def select_database(self):
    172. db_path = filedialog.askopenfilename(
    173. title="Select MP3 Database",
    174. filetypes=[("SQLite Database", "*.db"), ("All files", "*.*")]
    175. )
    176. if db_path:
    177. self.db_path = db_path
    178. self.connect_database()
    179. self.load_mp3s_from_database()
    180. self.update_status("Database loaded successfully")
    181. def select_streams_file(self):
    182. ini_path = filedialog.askopenfilename(
    183. title="Select Streams File",
    184. filetypes=[("INI Config", "*.ini"), ("All files", "*.*")]
    185. )
    186. if ini_path:
    187. self.load_streams_file(ini_path)
    188. self.update_status("Streams file loaded successfully")
    189. def load_streams_file(self, ini_path):
    190. config = configparser.ConfigParser()
    191. try:
    192. config.read(ini_path)
    193. self.streams = {sect: dict(config.items(sect)) for sect in config.sections()}
    194. if self.streams:
    195. self.category_combo['values'] = list(self.streams.keys())
    196. self.category_combo.current(0)
    197. self.update_stations()
    198. else:
    199. messagebox.showerror("Error", "No valid sections found in stream file.")
    200. except Exception as e:
    201. messagebox.showerror("Error", f"Failed to load stream file: {e}")
    202. def update_stations(self, event=None):
    203. selected_category = self.category_var.get()
    204. if selected_category in self.streams:
    205. self.station_list.delete(0, END)
    206. for station in self.streams[selected_category]:
    207. self.station_list.insert(END, station)
    208. self.current_streams = self.streams[selected_category]
    209. def play_selected_station(self, event=None):
    210. if self.secure_mode and not self.authenticate():
    211. return
    212. selected_index = self.station_list.curselection()
    213. if not selected_index:
    214. return
    215. station_name = self.station_list.get(selected_index)
    216. stream_url = self.current_streams.get(station_name)
    217. if not stream_url:
    218. messagebox.showerror("Error", "Stream URL not found.")
    219. return
    220. try:
    221. media = self.vlc_instance.media_new(stream_url)
    222. self.media_player.set_media(media)
    223. self.media_player.play()
    224. self.update_status(f"Playing: {station_name}")
    225. self.current_stream_url = stream_url
    226. except Exception as e:
    227. messagebox.showerror("Error", f"Failed to play stream: {e}")
    228. def open_stream_url(self):
    229. if hasattr(self, 'current_stream_url'):
    230. import webbrowser
    231. webbrowser.open(self.current_stream_url)
    232. def set_password(self):
    233. if self.secure_mode and not self.authenticate():
    234. return
    235. new_pass = self.get_password_dialog("Set New Password", "Enter new password:")
    236. if new_pass:
    237. self.password_hash = self.hash_password(new_pass)
    238. self.save_password_hash()
    239. messagebox.showinfo("Success", "Password set successfully")
    240. self.update_status("Password set")
    241. def lock_application(self):
    242. if self.authenticate():
    243. self.root.withdraw()
    244. self.root.after(100, self.show_login_dialog)
    245. def toggle_secure_mode(self):
    246. self.secure_mode = self.secure_mode_var.get() == 1
    247. status = "enabled" if self.secure_mode else "disabled"
    248. self.update_status(f"Secure mode {status}")
    249. def authenticate(self):
    250. if not self.secure_mode or not self.password_hash:
    251. return True
    252. password = self.get_password_dialog("Authentication Required", "Enter password:")
    253. if password and self.hash_password(password) == self.password_hash:
    254. return True
    255. return False
    256. def get_password_dialog(self, title, prompt):
    257. dialog = Toplevel(self.root)
    258. dialog.title(title)
    259. dialog.geometry("300x120")
    260. dialog.transient(self.root)
    261. dialog.grab_set()
    262. Label(dialog, text=prompt).pack(pady=5)
    263. password_var = StringVar()
    264. entry = Entry(dialog, textvariable=password_var, show="*")
    265. entry.pack(pady=5)
    266. result = [None]
    267. def on_ok():
    268. result[0] = password_var.get()
    269. dialog.destroy()
    270. Button(dialog, text="OK", command=on_ok).pack(side=LEFT, padx=20)
    271. Button(dialog, text="Cancel", command=dialog.destroy).pack(side=RIGHT, padx=20)
    272. self.root.wait_window(dialog)
    273. return result[0]
    274. def hash_password(self, password):
    275. salt = b'salt_123'
    276. return base64.b64encode(hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)).decode()
    277. def load_password_hash(self):
    278. try:
    279. with open('config.dat', 'r') as f:
    280. return f.read().strip()
    281. except:
    282. return None
    283. def save_password_hash(self):
    284. try:
    285. with open('config.dat', 'w') as f:
    286. f.write(self.password_hash or '')
    287. except Exception as e:
    288. messagebox.showerror("Error", f"Failed to save password: {e}")
    289. def show_login_dialog(self):
    290. login_window = Toplevel()
    291. login_window.title("Login")
    292. login_window.geometry("300x120")
    293. login_window.transient(self.root)
    294. Label(login_window, text="Enter password to unlock:").pack(pady=5)
    295. password_var = StringVar()
    296. entry = Entry(login_window, textvariable=password_var, show="*")
    297. entry.pack(pady=5)
    298. def on_login():
    299. if self.hash_password(password_var.get()) == self.password_hash:
    300. login_window.destroy()
    301. self.root.deiconify()
    302. else:
    303. messagebox.showerror("Error", "Invalid password")
    304. Button(login_window, text="Login", command=on_login).pack()
    305. login_window.protocol("WM_DELETE_WINDOW", self.root.quit)
    306. def update_status(self, message):
    307. self.status_bar.config(text=message)
    308. def load_gif(self, gif_path):
    309. if getattr(sys, 'frozen', False):
    310. base_path = sys._MEIPASS
    311. else:
    312. base_path = os.path.dirname(__file__)
    313. full_path = os.path.join(base_path, gif_path)
    314. self.gif_label = Label(self.root)
    315. self.gif_label.pack(pady=10)
    316. self.gif = Image.open(full_path)
    317. self.frames = [ImageTk.PhotoImage(frame) for frame in ImageSequence.Iterator(self.gif)]
    318. self.gif_index = 0
    319. self.gif_label.configure(image=self.frames[0])
    320. self.update_gif()
    321. def update_gif(self):
    322. self.gif_index = (self.gif_index + 1) % len(self.frames)
    323. self.gif_label.configure(image=self.frames[self.gif_index])
    324. self.root.after(100, self.update_gif)
    325. def load_mp3s_from_database(self):
    326. self.listbox.delete(0, END)
    327. try:
    328. self.cursor.execute("SELECT filename FROM mp3_files")
    329. for row in self.cursor.fetchall():
    330. self.listbox.insert(END, row[0])
    331. except Exception as e:
    332. messagebox.showerror("Error", f"Failed to load MP3 files: {e}")
    333. def play_selected_song(self, event=None):
    334. selected_index = self.listbox.curselection()
    335. if not selected_index:
    336. return
    337. song_name = self.listbox.get(selected_index)
    338. try:
    339. self.cursor.execute("SELECT filedata FROM mp3_files WHERE filename = ?", (song_name,))
    340. song_data = self.cursor.fetchone()[0]
    341. with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_file:
    342. temp_file.write(song_data)
    343. temp_file_path = temp_file.name
    344. self.temp_files.append(temp_file_path)
    345. self.media_player.set_media(self.vlc_instance.media_new(temp_file_path))
    346. self.media_player.play()
    347. self.update_position_slider()
    348. except Exception as e:
    349. messagebox.showerror("Error", f"Failed to play song: {e}")
    350. def stop_song(self):
    351. self.media_player.stop()
    352. self.position_slider.set(0)
    353. def play_next(self):
    354. current_index = self.listbox.curselection()[0]
    355. next_index = (current_index + 1) % self.listbox.size()
    356. self.listbox.select_clear(current_index)
    357. self.listbox.select_set(next_index)
    358. self.play_selected_song()
    359. def play_previous(self):
    360. current_index = self.listbox.curselection()[0]
    361. prev_index = (current_index - 1) % self.listbox.size()
    362. self.listbox.select_clear(current_index)
    363. self.listbox.select_set(prev_index)
    364. self.play_selected_song()
    365. def set_volume(self, volume):
    366. self.media_player.audio_set_volume(int(volume))
    367. def update_position_slider(self):
    368. if self.media_player.is_playing():
    369. current_pos = self.media_player.get_time() // 1000
    370. self.position_slider.set(current_pos)
    371. self.root.after(1000, self.update_position_slider)
    372. def seek_position(self, position):
    373. self.media_player.set_time(int(position) * 1000)
    374. def browse_folder(self):
    375. folder_path = filedialog.askdirectory()
    376. if not folder_path:
    377. return
    378. self.listbox.delete(0, END)
    379. try:
    380. self.cursor.execute("DELETE FROM mp3_files")
    381. self.db_connection.commit()
    382. for filename in os.listdir(folder_path):
    383. if filename.endswith(".mp3"):
    384. file_path = os.path.join(folder_path, filename)
    385. with open(file_path, 'rb') as file:
    386. file_data = file.read()
    387. self.cursor.execute("INSERT INTO mp3_files (filename, filedata) VALUES (?, ?)", (filename, file_data))
    388. self.db_connection.commit()
    389. self.load_mp3s_from_database()
    390. messagebox.showinfo("Success", "MP3 files loaded from folder and saved to database!")
    391. except Exception as e:
    392. messagebox.showerror("Error", f"Failed to load folder: {e}")
    393. def add_mp3_file(self):
    394. file_path = filedialog.askopenfilename(filetypes=[("MP3 files", "*.mp3")])
    395. if not file_path:
    396. return
    397. try:
    398. filename = os.path.basename(file_path)
    399. with open(file_path, 'rb') as file:
    400. file_data = file.read()
    401. self.cursor.execute("INSERT INTO mp3_files (filename, filedata) VALUES (?, ?)", (filename, file_data))
    402. self.db_connection.commit()
    403. self.listbox.insert(END, filename)
    404. messagebox.showinfo("Success", "MP3 file added to database!")
    405. except Exception as e:
    406. messagebox.showerror("Error", f"Failed to add MP3: {e}")
    407. def delete_mp3_file(self):
    408. selected_index = self.listbox.curselection()
    409. if not selected_index:
    410. return
    411. try:
    412. song_name = self.listbox.get(selected_index)
    413. self.cursor.execute("DELETE FROM mp3_files WHERE filename = ?", (song_name,))
    414. self.db_connection.commit()
    415. self.listbox.delete(selected_index)
    416. messagebox.showinfo("Deleted", "MP3 file deleted from database.")
    417. except Exception as e:
    418. messagebox.showerror("Error", f"Failed to delete MP3: {e}")
    419. def save_mp3_to_database(self):
    420. selected_index = self.listbox.curselection()
    421. if not selected_index:
    422. messagebox.showwarning("Warning", "Please select an MP3 file to save.")
    423. return
    424. try:
    425. song_name = self.listbox.get(selected_index)
    426. folder_path = filedialog.askdirectory()
    427. if not folder_path:
    428. return
    429. self.cursor.execute("SELECT filedata FROM mp3_files WHERE filename = ?", (song_name,))
    430. file_data = self.cursor.fetchone()
    431. if file_data:
    432. file_path = os.path.join(folder_path, song_name)
    433. with open(file_path, 'wb') as file:
    434. file.write(file_data[0])
    435. messagebox.showinfo("Success", f"MP3 file '{song_name}' saved to selected folder.")
    436. else:
    437. messagebox.showerror("Error", "File data not found in database.")
    438. except Exception as e:
    439. messagebox.showerror("Error", f"Failed to save MP3: {e}")
    440. def delete_temp_files(self):
    441. self.media_player.stop()
    442. deleted_files = []
    443. for temp_file in self.temp_files:
    444. try:
    445. if os.path.exists(temp_file):
    446. os.remove(temp_file)
    447. deleted_files.append(temp_file)
    448. except Exception as e:
    449. messagebox.showerror("Error", f"Failed to delete {temp_file}: {e}")
    450. self.temp_files.clear()
    451. if deleted_files:
    452. messagebox.showinfo("Success", f"Temporary files deleted: {', '.join(deleted_files)}")
    453. else:
    454. messagebox.showinfo("Success", "No temporary files to delete.")
    455. if __name__ == "__main__":
    456. root = Tk()
    457. app = Mp3PlayerApp(root)
    458. root.mainloop()
    Add Comment
    Please, Sign In to add comment
    Public Pastes
    We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
    Not a member of Pastebin yet?
    Sign Up, it unlocks many cool features!

    AltStyle によって変換されたページ (->オリジナル) /