-
Notifications
You must be signed in to change notification settings - Fork 0
/
musicplayer.py
228 lines (195 loc) · 7.94 KB
/
musicplayer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
import os
import pygame
import questionary
from questionary import Style
import time
from mutagen.mp3 import MP3
import threading
progress_thread_running = False
def initialize_music_player():
pygame.mixer.init()
# Function to clear the screen
def clear_screen():
os.system('cls' if os.name == 'nt' else 'clear')
# Function to list all music files
def list_music_files(path):
return [f for f in os.listdir(path) if f.endswith('.mp3')]
def search_songs(tracks, query):
"""
Search for songs in tracks list that contain the query string.
"""
query = query.lower()
return [track for track in tracks if query in track.lower()]
# Crossfade function
def crossfade_tracks(old_track, new_track, duration=2):
"""
Crossfade from old_track to new_track over the specified duration (in seconds).
"""
max_volume = pygame.mixer.music.get_volume()
step = max_volume / (duration * 10) # Calculate volume change per step
# Fade out the old track
for _ in range(int(duration * 10)):
current_volume = pygame.mixer.music.get_volume()
pygame.mixer.music.set_volume(max(0, current_volume - step))
time.sleep(0.1)
# Stop the old track and start the new one
pygame.mixer.music.stop()
pygame.mixer.music.load(new_track)
pygame.mixer.music.play()
# Fade in the new track
for _ in range(int(duration * 10)):
current_volume = pygame.mixer.music.get_volume()
pygame.mixer.music.set_volume(min(max_volume, current_volume + step))
time.sleep(0.1)
def get_song_duration(file_path):
"""
Get the duration of a song.
"""
audio = MP3(file_path)
return audio.info.length
def display_progress(current_song):
global progress_thread_running
duration = get_song_duration(current_song)
try:
while pygame.mixer.music.get_busy() and progress_thread_running:
position = pygame.mixer.music.get_pos() / 1000.0 # Convert to seconds
print(f"\033[94m\rProgress: {format_time(position)} / {format_time(duration)}\033[0m", end='')
time.sleep(1)
except Exception as e:
print ("")
def format_time(seconds):
"""
Format time in seconds to a string in the format 'minutes:seconds'.
"""
return time.strftime('%M:%S', time.gmtime(seconds))
# Music control functions
def play_music(new_track):
global progress_thread_running
try:
current_track = pygame.mixer.music.get_pos()
if current_track != -1: # Check if a track is already playing
crossfade_tracks(current_track, new_track)
else:
pygame.mixer.music.load(new_track)
pygame.mixer.music.play()
progress_thread_running = True # Set the flag to True when starting playback
# Start a new thread to display the progress
progress_thread = threading.Thread(target=display_progress, args=(new_track,))
progress_thread.start()
except pygame.error as e:
print(f"Error playing {new_track}: {e}")
def pause_music():
pygame.mixer.music.pause()
def resume_music():
pygame.mixer.music.unpause()
def stop_music():
global progress_thread_running
pygame.mixer.music.stop()
progress_thread_running = False
def music_player_main(music_path):
global progress_thread_running
custom_style = Style([
('pointer', 'fg:red bold'), # Color for the pointer
('highlighted', 'fg:red bold'), # Color for highlighted item
('selected', 'fg:orange bg:#673ab7'), # Color for selected item
])
# Function to print the currently playing song with color
def print_currently_playing(song):
# ANSI escape code for color
print(f"\033[94m\nCurrently Playing: {song}\033[0m")
# Interactive Menu Options
def menu_options(current_song):
clear_screen()
print_currently_playing(current_song)
return questionary.select(
"Plz enter your choice:",
choices=['Choose Song', 'Play/Pause', 'Resume', 'Stop', 'Next Track', 'Previous Track', 'Exit'],
style=custom_style
).ask()
def search_and_choose_song(tracks):
"""
Search for songs based on user input and allow the user to choose a song from the search results.
"""
while True:
query = questionary.text("Enter song name to search:").ask()
search_results = search_songs(tracks, query)
if not search_results:
print("No songs found. Try again.")
continue
choices = search_results + ['Search again', 'Back to Main Menu']
selected = questionary.select(
"Select a song to play, search again, or go back:",
choices=choices,
style=custom_style,
pointer='->'
).ask()
if selected == 'Back to Main Menu':
return None, -1
elif selected == 'Search again':
continue
else:
return selected, tracks.index(selected)
# Function to choose a song or go back
def choose_song(tracks, current_track_index):
clear_screen()
action = questionary.select(
"Do you want to search for a song or choose from the list?",
choices=['Search for a song', 'Choose from the list'],
style=custom_style
).ask()
if action == 'Search for a song':
selected_song, index = search_and_choose_song(tracks)
if selected_song is None:
# User chose 'Go Back', return to previous menu without action
return None, current_track_index
else:
return selected_song, index
else:
options = ["[Back to Main Menu]"] + tracks
selected = questionary.select(
"Select a song to play or go back:",
choices=options,
style=custom_style,
pointer='->',
default=options[current_track_index + 1]
).ask()
return selected, options.index(selected) - 1
tracks = list_music_files(music_path)
if not tracks:
print("No music files found in the provided path.")
return
current_track_index = 0
play_music(os.path.join(music_path, tracks[current_track_index]))
while True:
choice = menu_options(tracks[current_track_index])
if choice == 'Choose Song':
selected_song, index = choose_song(tracks, current_track_index)
if selected_song and selected_song != "[Back to Main Menu]":
current_track_index = index
play_music(os.path.join(music_path, selected_song))
elif choice == 'Play/Pause':
if pygame.mixer.music.get_busy():
pause_music()
else:
play_music(os.path.join(music_path, tracks[current_track_index]))
elif choice == 'Resume':
resume_music()
elif choice == 'Stop':
stop_music()
elif choice == 'Next Track':
current_track_index = (current_track_index + 1) % len(tracks)
play_music(os.path.join(music_path, tracks[current_track_index]))
elif choice == 'Previous Track':
current_track_index = (current_track_index - 1) % len(tracks)
play_music(os.path.join(music_path, tracks[current_track_index]))
elif choice == 'Exit':
progress_thread_running = False
if pygame.mixer.music.get_busy():
pause_music()
pygame.mixer.quit()
break
clear_screen()
if __name__ == "__main__":
music_path = "D:\\Media\\Music"
initialize_music_player()
music_player_main(music_path)